Skip to content
Snippets Groups Projects
Commit b670c3ed authored by Michael Simon's avatar Michael Simon
Browse files

ISSUE-196 make account resolver scriptable for resolving an account

for a nameid.
parent b11514fd
No related branches found
No related tags found
No related merge requests found
...@@ -3,73 +3,13 @@ package edu.kit.scc.webreg.service.saml; ...@@ -3,73 +3,13 @@ package edu.kit.scc.webreg.service.saml;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable; import java.io.Serializable;
import org.opensaml.messaging.decoder.MessageDecodingException;
import org.opensaml.saml.saml2.core.AttributeQuery;
import org.opensaml.saml.saml2.core.StatusCode;
import org.opensaml.soap.soap11.Envelope;
import org.slf4j.Logger;
import edu.kit.scc.webreg.annotations.RetryTransaction;
import edu.kit.scc.webreg.entity.SamlAAConfigurationEntity; import edu.kit.scc.webreg.entity.SamlAAConfigurationEntity;
import edu.kit.scc.webreg.saml.idp.AttributeAuthorityService;
import edu.kit.scc.webreg.service.saml.exc.SamlAuthenticationException;
import jakarta.ejb.Stateless;
import jakarta.ejb.TransactionManagement;
import jakarta.ejb.TransactionManagementType;
import jakarta.inject.Inject;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import net.shibboleth.shared.component.ComponentInitializationException;
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class SamlAttributeQueryService implements Serializable {
private static final long serialVersionUID = 1L;
@Inject
private Logger logger;
@Inject
private AttributeAuthorityService aaService;
@Inject
private Saml2DecoderService saml2DecoderService;
@Inject
private SamlHelper samlHelper;
@RetryTransaction
public void consumeAttributeQuery(HttpServletRequest request, HttpServletResponse response,
SamlAAConfigurationEntity aaConfig) throws IOException {
logger.debug("Consuming SAML AttributeQuery");
try {
AttributeQuery query = saml2DecoderService.decodeAttributeQuery(request);
logger.debug("SAML AttributeQuery decoded");
Envelope envelope = aaService.processAttributeQuery(aaConfig, query);
response.getWriter().print(samlHelper.marshal(envelope)); public interface SamlAttributeQueryService extends Serializable {
} catch (MessageDecodingException e) { void consumeAttributeQuery(HttpServletRequest request, HttpServletResponse response,
logger.info("Could not execute AttributeQuery: {}", e.getMessage()); SamlAAConfigurationEntity aaConfig) throws IOException;
sendErrorResponse(response, StatusCode.REQUEST_DENIED, e.getMessage());
} catch (SecurityException e) {
logger.info("Could not execute AttributeQuery: {}", e.getMessage());
sendErrorResponse(response, StatusCode.REQUEST_DENIED, e.getMessage());
} catch (SamlAuthenticationException e) {
logger.info("Could not execute AttributeQuery: {}", e.getMessage());
sendErrorResponse(response, StatusCode.REQUEST_DENIED, e.getMessage());
} catch (ComponentInitializationException e) {
logger.info("Could not execute AttributeQuery: {}", e.getMessage());
sendErrorResponse(response, StatusCode.REQUEST_DENIED, e.getMessage());
}
}
private void sendErrorResponse(HttpServletResponse response, String statusCodeString, String messageString)
throws IOException {
Envelope envelope = aaService.buildErrorResponse(statusCodeString, messageString);
response.getWriter().print(samlHelper.marshal(envelope));
}
} }
package edu.kit.scc.webreg.service.saml;
import java.io.IOException;
import org.opensaml.messaging.decoder.MessageDecodingException;
import org.opensaml.saml.saml2.core.AttributeQuery;
import org.opensaml.saml.saml2.core.StatusCode;
import org.opensaml.soap.soap11.Envelope;
import org.slf4j.Logger;
import edu.kit.scc.webreg.annotations.RetryTransaction;
import edu.kit.scc.webreg.entity.SamlAAConfigurationEntity;
import edu.kit.scc.webreg.saml.idp.AttributeAuthorityService;
import edu.kit.scc.webreg.service.saml.exc.SamlAuthenticationException;
import jakarta.ejb.Stateless;
import jakarta.ejb.TransactionManagement;
import jakarta.ejb.TransactionManagementType;
import jakarta.inject.Inject;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import net.shibboleth.shared.component.ComponentInitializationException;
@Stateless
@TransactionManagement(TransactionManagementType.BEAN)
public class SamlAttributeQueryServiceImpl implements SamlAttributeQueryService {
private static final long serialVersionUID = 1L;
@Inject
private Logger logger;
@Inject
private AttributeAuthorityService aaService;
@Inject
private Saml2DecoderService saml2DecoderService;
@Inject
private SamlHelper samlHelper;
@Override
@RetryTransaction
public void consumeAttributeQuery(HttpServletRequest request, HttpServletResponse response,
SamlAAConfigurationEntity aaConfig) throws IOException {
logger.debug("Consuming SAML AttributeQuery");
try {
AttributeQuery query = saml2DecoderService.decodeAttributeQuery(request);
logger.debug("SAML AttributeQuery decoded");
Envelope envelope = aaService.processAttributeQuery(aaConfig, query);
response.getWriter().print(samlHelper.marshal(envelope));
} catch (MessageDecodingException e) {
logger.info("Could not execute AttributeQuery: {}", e.getMessage());
sendErrorResponse(response, StatusCode.REQUEST_DENIED, e.getMessage());
} catch (SecurityException e) {
logger.info("Could not execute AttributeQuery: {}", e.getMessage());
sendErrorResponse(response, StatusCode.REQUEST_DENIED, e.getMessage());
} catch (SamlAuthenticationException e) {
logger.info("Could not execute AttributeQuery: {}", e.getMessage());
sendErrorResponse(response, StatusCode.REQUEST_DENIED, e.getMessage());
} catch (ComponentInitializationException e) {
logger.info("Could not execute AttributeQuery: {}", e.getMessage());
sendErrorResponse(response, StatusCode.REQUEST_DENIED, e.getMessage());
}
}
private void sendErrorResponse(HttpServletResponse response, String statusCodeString, String messageString)
throws IOException {
Envelope envelope = aaService.buildErrorResponse(statusCodeString, messageString);
response.getWriter().print(samlHelper.marshal(envelope));
}
}
...@@ -2,6 +2,11 @@ package edu.kit.scc.webreg.saml.idp; ...@@ -2,6 +2,11 @@ package edu.kit.scc.webreg.saml.idp;
import java.time.Instant; import java.time.Instant;
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import org.opensaml.core.xml.XMLObject; import org.opensaml.core.xml.XMLObject;
import org.opensaml.core.xml.XMLObjectBuilderFactory; import org.opensaml.core.xml.XMLObjectBuilderFactory;
import org.opensaml.core.xml.schema.XSString; import org.opensaml.core.xml.schema.XSString;
...@@ -22,10 +27,12 @@ import org.opensaml.soap.soap11.Envelope; ...@@ -22,10 +27,12 @@ import org.opensaml.soap.soap11.Envelope;
import org.slf4j.Logger; import org.slf4j.Logger;
import edu.kit.scc.webreg.dao.SamlSpMetadataDao; import edu.kit.scc.webreg.dao.SamlSpMetadataDao;
import edu.kit.scc.webreg.dao.UserDao; import edu.kit.scc.webreg.dao.ScriptDao;
import edu.kit.scc.webreg.entity.SamlAAConfigurationEntity; import edu.kit.scc.webreg.entity.SamlAAConfigurationEntity;
import edu.kit.scc.webreg.entity.SamlSpMetadataEntity; import edu.kit.scc.webreg.entity.SamlSpMetadataEntity;
import edu.kit.scc.webreg.entity.ScriptEntity;
import edu.kit.scc.webreg.entity.UserEntity; import edu.kit.scc.webreg.entity.UserEntity;
import edu.kit.scc.webreg.script.ScriptingEnv;
import edu.kit.scc.webreg.service.saml.Saml2ResponseValidationService; import edu.kit.scc.webreg.service.saml.Saml2ResponseValidationService;
import edu.kit.scc.webreg.service.saml.SamlHelper; import edu.kit.scc.webreg.service.saml.SamlHelper;
import edu.kit.scc.webreg.service.saml.SsoHelper; import edu.kit.scc.webreg.service.saml.SsoHelper;
...@@ -46,18 +53,22 @@ public class AttributeAuthorityService { ...@@ -46,18 +53,22 @@ public class AttributeAuthorityService {
private SamlSpMetadataDao spMetadataDao; private SamlSpMetadataDao spMetadataDao;
@Inject @Inject
private UserDao userService; private ScriptDao scriptDao;
@Inject
private ScriptingEnv scriptingEnv;
@Inject @Inject
private SamlHelper samlHelper; private SamlHelper samlHelper;
@Inject @Inject
private SsoHelper ssoHelper; private SsoHelper ssoHelper;
public Envelope processAttributeQuery(SamlAAConfigurationEntity aaConfig, AttributeQuery query) throws SamlAuthenticationException { public Envelope processAttributeQuery(SamlAAConfigurationEntity aaConfig, AttributeQuery query)
throws SamlAuthenticationException {
logger.debug("Processing AttributeQuery"); logger.debug("Processing AttributeQuery");
Issuer issuer = query.getIssuer(); Issuer issuer = query.getIssuer();
if (issuer == null || issuer.getValue() == null) { if (issuer == null || issuer.getValue() == null) {
throw new SamlAuthenticationException("Issuer not set"); throw new SamlAuthenticationException("Issuer not set");
...@@ -68,6 +79,12 @@ public class AttributeAuthorityService { ...@@ -68,6 +79,12 @@ public class AttributeAuthorityService {
if (spEntity == null) if (spEntity == null)
throw new SamlAuthenticationException("Issuer metadata not in database"); throw new SamlAuthenticationException("Issuer metadata not in database");
if (!spEntity.getGenericStore().containsKey("aq_allowed"))
throw new SamlAuthenticationException("Issuer not allowed for attribute query");
else if (!spEntity.getGenericStore().get("aq_allowed").equalsIgnoreCase("true")) {
throw new SamlAuthenticationException("Issuer not allowed for attribute query");
}
EntityDescriptor spEntityDescriptor = samlHelper.unmarshal(spEntity.getEntityDescriptor(), EntityDescriptor spEntityDescriptor = samlHelper.unmarshal(spEntity.getEntityDescriptor(),
EntityDescriptor.class); EntityDescriptor.class);
...@@ -79,29 +96,53 @@ public class AttributeAuthorityService { ...@@ -79,29 +96,53 @@ public class AttributeAuthorityService {
samlResponse.setIssueInstant(Instant.now()); samlResponse.setIssueInstant(Instant.now());
if (query.getSubject() != null && query.getSubject().getNameID() != null) { if (query.getSubject() != null && query.getSubject().getNameID() != null) {
String nameIdValue = query.getSubject().getNameID().getValue();
String nameIdFormat = query.getSubject().getNameID().getFormat(); if (!spEntity.getGenericStore().containsKey("aq_resolve_user_scipt"))
throw new SamlAuthenticationException(
UserEntity user = userService.fetch(Long.parseLong(nameIdValue)); "NameId Resolver not configured, cannot resolve account. This is a server side error, contact the server administrator");
if (user != null) { String resolveUserScript = spEntity.getGenericStore().get("aq_resolve_user_scipt");
Assertion assertion = samlHelper.create(Assertion.class, Assertion.DEFAULT_ELEMENT_NAME); ScriptEntity script = scriptDao.findByName(resolveUserScript);
assertion.setIssueInstant(Instant.now()); if (script == null)
assertion.setIssuer(ssoHelper.buildIssuser(aaConfig.getEntityId())); throw new SamlAuthenticationException("NameId Resolver not configured correctly. Script not found: " + resolveUserScript);
assertion.setSubject(ssoHelper.buildAQSubject(aaConfig, spEntity, nameIdValue, NameID.UNSPECIFIED,
query.getID())); try {
assertion.getAttributeStatements().add(buildAttributeStatement(user)); ScriptEngine engine = (new ScriptEngineManager()).getEngineByName(script.getScriptEngine());
samlResponse.getAssertions().add(assertion); engine.eval(script.getScript());
Invocable invocable = (Invocable) engine;
String nameIdValue = query.getSubject().getNameID().getValue();
String nameIdFormat = query.getSubject().getNameID().getFormat();
UserEntity user = (UserEntity) invocable.invokeFunction("resolveUser", scriptingEnv, nameIdFormat, nameIdValue, logger,
spEntity, aaConfig);
if (user != null) {
Assertion assertion = samlHelper.create(Assertion.class, Assertion.DEFAULT_ELEMENT_NAME);
assertion.setIssueInstant(Instant.now());
assertion.setIssuer(ssoHelper.buildIssuser(aaConfig.getEntityId()));
assertion.setSubject(
ssoHelper.buildAQSubject(aaConfig, spEntity, nameIdValue, NameID.UNSPECIFIED, query.getID()));
assertion.getAttributeStatements().add(buildAttributeStatement(user));
samlResponse.getAssertions().add(assertion);
}
} catch (NoSuchMethodException e) {
logger.warn("Method is missing in script: {}", e.getMessage());
throw new SamlAuthenticationException("NameId Resolver not configured correctly. Method resolveUser not found in " + resolveUserScript);
} catch (ScriptException e) {
logger.warn("Script contains errors: {}", e.getMessage());
throw new SamlAuthenticationException("NameId Resolver "+ resolveUserScript + " contains errors");
} }
} else {
throw new SamlAuthenticationException("Subject or Subject Name ID is missing in request");
} }
return buildSoapEnvelope(samlResponse); return buildSoapEnvelope(samlResponse);
} }
public Envelope buildErrorResponse(String statusCodeString, String messageString) { public Envelope buildErrorResponse(String statusCodeString, String messageString) {
Response samlResponse = buildSamlRespone(statusCodeString, messageString); Response samlResponse = buildSamlRespone(statusCodeString, messageString);
return buildSoapEnvelope(samlResponse); return buildSoapEnvelope(samlResponse);
} }
private Response buildSamlRespone(String statusCodeString, String messageString) { private Response buildSamlRespone(String statusCodeString, String messageString) {
Response samlResponse = samlHelper.create(Response.class, Response.DEFAULT_ELEMENT_NAME); Response samlResponse = samlHelper.create(Response.class, Response.DEFAULT_ELEMENT_NAME);
samlResponse.setStatus(buildSamlStatus(statusCodeString, messageString)); samlResponse.setStatus(buildSamlStatus(statusCodeString, messageString));
......
...@@ -20,8 +20,6 @@ import edu.kit.scc.webreg.dao.SamlIdpMetadataDao; ...@@ -20,8 +20,6 @@ import edu.kit.scc.webreg.dao.SamlIdpMetadataDao;
import edu.kit.scc.webreg.dao.SamlSpConfigurationDao; import edu.kit.scc.webreg.dao.SamlSpConfigurationDao;
import edu.kit.scc.webreg.dao.ScriptDao; import edu.kit.scc.webreg.dao.ScriptDao;
import edu.kit.scc.webreg.dao.as.ASUserAttrValueDao; import edu.kit.scc.webreg.dao.as.ASUserAttrValueDao;
import edu.kit.scc.webreg.entity.SamlAAMetadataEntity;
import edu.kit.scc.webreg.entity.SamlIdpMetadataEntity;
import edu.kit.scc.webreg.entity.SamlMetadataEntity; import edu.kit.scc.webreg.entity.SamlMetadataEntity;
import edu.kit.scc.webreg.entity.SamlSpConfigurationEntity; import edu.kit.scc.webreg.entity.SamlSpConfigurationEntity;
import edu.kit.scc.webreg.entity.ScriptEntity; import edu.kit.scc.webreg.entity.ScriptEntity;
......
...@@ -26,7 +26,6 @@ import java.util.Set; ...@@ -26,7 +26,6 @@ import java.util.Set;
import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContext;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.config.RequestConfig; import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClients; import org.apache.hc.client5.http.impl.classic.HttpClients;
......
...@@ -22,8 +22,6 @@ import java.util.List; ...@@ -22,8 +22,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import javax.script.Invocable; import javax.script.Invocable;
import javax.script.ScriptEngine; import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager; import javax.script.ScriptEngineManager;
...@@ -62,6 +60,8 @@ import edu.kit.scc.webreg.entity.SamlUserEntity_; ...@@ -62,6 +60,8 @@ import edu.kit.scc.webreg.entity.SamlUserEntity_;
import edu.kit.scc.webreg.entity.ScriptEntity; import edu.kit.scc.webreg.entity.ScriptEntity;
import edu.kit.scc.webreg.service.saml.exc.NoAssertionException; import edu.kit.scc.webreg.service.saml.exc.NoAssertionException;
import edu.kit.scc.webreg.service.saml.exc.SamlAuthenticationException; import edu.kit.scc.webreg.service.saml.exc.SamlAuthenticationException;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@ApplicationScoped @ApplicationScoped
public class Saml2AssertionService { public class Saml2AssertionService {
...@@ -100,7 +100,7 @@ public class Saml2AssertionService { ...@@ -100,7 +100,7 @@ public class Saml2AssertionService {
} }
saml2ValidationService.verifyStatus(samlResponse); saml2ValidationService.verifyStatus(samlResponse);
saml2ValidationService.verifyIssuer((SamlIdpMetadataEntity) idpEntity, samlResponse); saml2ValidationService.verifyIssuer(idpEntity, samlResponse);
saml2ValidationService.verifyExpiration(samlResponse, 1000L * 60L * 10L); saml2ValidationService.verifyExpiration(samlResponse, 1000L * 60L * 10L);
Boolean responseSignatureValid = false; Boolean responseSignatureValid = false;
......
...@@ -39,7 +39,6 @@ import org.opensaml.xmlsec.signature.support.SignatureException; ...@@ -39,7 +39,6 @@ import org.opensaml.xmlsec.signature.support.SignatureException;
import org.opensaml.xmlsec.signature.support.impl.ExplicitKeySignatureTrustEngine; import org.opensaml.xmlsec.signature.support.impl.ExplicitKeySignatureTrustEngine;
import org.slf4j.Logger; import org.slf4j.Logger;
import edu.kit.scc.webreg.entity.SamlIdpMetadataEntity;
import edu.kit.scc.webreg.entity.SamlMetadataEntity; import edu.kit.scc.webreg.entity.SamlMetadataEntity;
import edu.kit.scc.webreg.entity.SamlSpMetadataEntity; import edu.kit.scc.webreg.entity.SamlSpMetadataEntity;
import edu.kit.scc.webreg.service.saml.exc.SamlAuthenticationException; import edu.kit.scc.webreg.service.saml.exc.SamlAuthenticationException;
...@@ -86,12 +85,12 @@ public class Saml2ResponseValidationService { ...@@ -86,12 +85,12 @@ public class Saml2ResponseValidationService {
} }
public void verifyIssuer(SamlIdpMetadataEntity metadataEntity, public void verifyIssuer(SamlMetadataEntity metadataEntity,
Response samlResponse) throws SamlAuthenticationException { Response samlResponse) throws SamlAuthenticationException {
verifyIssuer(metadataEntity, samlResponse.getIssuer()); verifyIssuer(metadataEntity, samlResponse.getIssuer());
} }
public void verifyIssuer(SamlIdpMetadataEntity metadataEntity, public void verifyIssuer(SamlMetadataEntity metadataEntity,
Issuer issuer) throws SamlAuthenticationException { Issuer issuer) throws SamlAuthenticationException {
if (issuer == null) if (issuer == null)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment