From e7610325ee2f1d1f4e97e1e7a9b212e692836b5a Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Tue, 4 Feb 2020 17:37:34 +0100 Subject: first stable version that uses OpenSAML 3.x --- .../idp/Pvp2SProfileIdpSpringResourceProvider.java | 3 +- .../InvalidAssertionConsumerServiceException.java | 8 +- .../exception/SamlRequestNotSignedException.java | 3 - .../idp/exception/SamlRequestNotSupported.java | 4 - .../exception/UnprovideableAttributeException.java | 2 +- .../pvp2/idp/impl/AbstractPvp2XProtocol.java | 77 +++++----- .../pvp2/idp/impl/AuthenticationAction.java | 33 ++-- .../eaaf/modules/pvp2/idp/impl/MetadataAction.java | 5 +- .../pvp2/idp/impl/PvpSProfilePendingRequest.java | 1 + .../pvp2/idp/impl/builder/AuthResponseBuilder.java | 169 ++++++++++++++------- .../idp/impl/builder/Pvp2AssertionBuilder.java | 68 +++++---- 11 files changed, 210 insertions(+), 163 deletions(-) (limited to 'eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf') diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/Pvp2SProfileIdpSpringResourceProvider.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/Pvp2SProfileIdpSpringResourceProvider.java index 9414dc33..7e572d70 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/Pvp2SProfileIdpSpringResourceProvider.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/Pvp2SProfileIdpSpringResourceProvider.java @@ -20,6 +20,7 @@ package at.gv.egiz.eaaf.modules.pvp2.idp; import at.gv.egiz.components.spring.api.SpringResourceProvider; + import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; @@ -41,7 +42,7 @@ public class Pvp2SProfileIdpSpringResourceProvider implements SpringResourceProv final ClassPathResource sl20AuthConfig = new ClassPathResource("/eaaf_pvp_idp.beans.xml", Pvp2SProfileIdpSpringResourceProvider.class); - return new Resource[] {sl20AuthConfig}; + return new Resource[] { sl20AuthConfig }; } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java index 0003b829..a7e05664 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/InvalidAssertionConsumerServiceException.java @@ -28,21 +28,19 @@ public class InvalidAssertionConsumerServiceException extends Pvp2Exception { private static final long serialVersionUID = 7861790149343943091L; public InvalidAssertionConsumerServiceException(final int idx) { - super("pvp2.28", new Object[] {idx}); + super("pvp2.28", new Object[] { idx }); this.statusCodeValue = StatusCode.REQUESTER; } /** * Invalid assertion consumer-service URL. * - * @param wrongUrl invalid URL + * @param wrongUrl invalid URL */ public InvalidAssertionConsumerServiceException(final String wrongUrl) { - super("pvp2.23", new Object[] {wrongUrl}); + super("pvp2.23", new Object[] { wrongUrl }); this.statusCodeValue = StatusCode.REQUESTER; } - - } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSignedException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSignedException.java index c02e534c..add2103b 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSignedException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSignedException.java @@ -37,7 +37,4 @@ public class SamlRequestNotSignedException extends Pvp2Exception { this.statusCodeValue = StatusCode.REQUESTER; } - - - } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSupported.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSupported.java index b0dcdb2e..d672f457 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSupported.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/SamlRequestNotSupported.java @@ -23,7 +23,6 @@ import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; import org.opensaml.saml.saml2.core.StatusCode; - public class SamlRequestNotSupported extends Pvp2Exception { private static final long serialVersionUID = 1244883178458802767L; @@ -33,7 +32,4 @@ public class SamlRequestNotSupported extends Pvp2Exception { this.statusCodeValue = StatusCode.REQUEST_UNSUPPORTED; } - - - } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java index 0f84b8fb..3a56b414 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/exception/UnprovideableAttributeException.java @@ -28,7 +28,7 @@ public class UnprovideableAttributeException extends Pvp2Exception { private static final long serialVersionUID = 3972197758163647157L; public UnprovideableAttributeException(final String attributeName) { - super("pvp2.10", new Object[] {attributeName}); + super("pvp2.10", new Object[] { attributeName }); this.statusCodeValue = StatusCode.UNKNOWN_ATTR_PROFILE; } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java index f86fd883..1ef7da29 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AbstractPvp2XProtocol.java @@ -46,6 +46,7 @@ import at.gv.egiz.eaaf.modules.pvp2.exception.InvalidPvpRequestException; import at.gv.egiz.eaaf.modules.pvp2.exception.NameIdFormatNotSupportedException; import at.gv.egiz.eaaf.modules.pvp2.exception.NoMetadataInformationException; import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionConsumerServiceException; import at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding; import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding; @@ -72,7 +73,6 @@ import org.opensaml.saml.saml2.core.StatusMessage; import org.opensaml.saml.saml2.metadata.AssertionConsumerService; import org.opensaml.saml.saml2.metadata.EntityDescriptor; import org.opensaml.saml.saml2.metadata.SPSSODescriptor; -import org.opensaml.ws.security.SecurityPolicyException; import org.opensaml.xmlsec.signature.SignableXMLObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -81,6 +81,9 @@ import org.springframework.beans.factory.annotation.Autowired; public abstract class AbstractPvp2XProtocol extends AbstractController implements IModulInfo { private static final Logger log = LoggerFactory.getLogger(AbstractPvp2XProtocol.class); + private static final String HTTP_PARAM_SAMLREQ = "SAMLRequest"; + private static final String ERROR_INVALID_REQUEST = "Receive INVALID protocol request: {}"; + @Autowired(required = true) protected IPvp2BasicConfiguration pvpBasicConfiguration; @Autowired(required = true) @@ -92,8 +95,6 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement private AbstractCredentialProvider pvpIdpCredentials; - - /** * Sets a specific credential provider for PVP S-Profile IDP component. * @@ -151,7 +152,6 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement moaError = statusMessager.getResponseErrorCode(e); } - if (StringUtils.isNotEmpty(moaError)) { final StatusCode moaStatusCode = Saml2Utils.createSamlObject(StatusCode.class); moaStatusCode.setValue(moaError); @@ -245,16 +245,16 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement // get POST-Binding decoder implementation final InboundMessage msg = (InboundMessage) new PostBinding().decode(req, resp, - metadataProvider, false, + metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, new EaafUriCompare(pvpBasicConfiguration.getIdpSsoPostService(pendingReq.getAuthUrl()))); pendingReq.setRequest(msg); // preProcess Message preProcess(req, resp, pendingReq); - } catch (final SecurityPolicyException e) { - final String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); + } catch (final SamlSigningException e) { + final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); + log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); // write revision log entries if (pendingReq != null) { @@ -264,9 +264,9 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); - } catch (final SecurityException e) { - final String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); + } catch (final Pvp2Exception e) { + final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); + log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); // write revision log entries if (pendingReq != null) { @@ -274,7 +274,7 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement pendingReq.getUniqueTransactionIdentifier()); } - throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); + throw new InvalidProtocolRequestException("pvp2.22", new Object[] { e.getMessage() }); } catch (final EaafException e) { @@ -287,8 +287,8 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement throw e; } catch (final Throwable e) { - final String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); + final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); + log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); // write revision log entries if (pendingReq != null) { @@ -296,7 +296,7 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement pendingReq.getUniqueTransactionIdentifier()); } - throw new EaafException("pvp2.24", new Object[] {e.getMessage()}, e); + throw new EaafException("pvp2.24", new Object[] { e.getMessage() }, e); } } @@ -319,16 +319,16 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement // get POST-Binding decoder implementation final InboundMessage msg = (InboundMessage) new RedirectBinding().decode(req, resp, - metadataProvider, false, new EaafUriCompare( + metadataProvider, SPSSODescriptor.DEFAULT_ELEMENT_NAME, new EaafUriCompare( pvpBasicConfiguration.getIdpSsoRedirectService(pendingReq.getAuthUrl()))); pendingReq.setRequest(msg); // preProcess Message preProcess(req, resp, pendingReq); - } catch (final SecurityPolicyException e) { - final String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); + } catch (final SamlSigningException e) { + final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); + log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); // write revision log entries if (pendingReq != null) { @@ -338,9 +338,9 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement throw new InvalidProtocolRequestException("pvp2.21", new Object[] {}); - } catch (final SecurityException e) { - final String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); + } catch (final Pvp2Exception e) { + final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); + log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); // write revision log entries if (pendingReq != null) { @@ -348,11 +348,11 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement pendingReq.getUniqueTransactionIdentifier()); } - throw new InvalidProtocolRequestException("pvp2.22", new Object[] {e.getMessage()}); + throw new InvalidProtocolRequestException("pvp2.22", new Object[] { e.getMessage() }); } catch (final EaafException e) { - final String samlRequest = req.getParameter("SAMLRequest"); - log.info("Receive INVALID protocol request: " + samlRequest); + final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); + log.info(ERROR_INVALID_REQUEST, samlRequest, null, e); // write revision log entries if (pendingReq != null) { @@ -363,8 +363,8 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement throw e; } catch (final Throwable e) { - final String samlRequest = req.getParameter("SAMLRequest"); - log.warn("Receive INVALID protocol request: " + samlRequest, e); + final String samlRequest = req.getParameter(HTTP_PARAM_SAMLREQ); + log.warn(ERROR_INVALID_REQUEST, samlRequest, null, e); // write revision log entries if (pendingReq != null) { @@ -372,17 +372,15 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement pendingReq.getUniqueTransactionIdentifier()); } - throw new EaafException("pvp2.24", new Object[] {e.getMessage()}, e); + throw new EaafException("pvp2.24", new Object[] { e.getMessage() }, e); } } - - /** * Authentication request pre-processor. * - * @param request http request - * @param response http response + * @param request http request + * @param response http response * @param pendingReq current pending request * @return true if preprocess can handle this request type, otherwise false * @throws Throwable In case of an error @@ -419,20 +417,17 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement log.error("Receive unsupported PVP21 message of type: " + ((PvpSProfileRequest) msg).getSamlRequest().getClass().getName()); throw new InvalidPvpRequestException("pvp2.09", - new Object[] {((PvpSProfileRequest) msg).getSamlRequest().getClass().getName()}); + new Object[] { ((PvpSProfileRequest) msg).getSamlRequest().getClass().getName() }); } - - // switch to session authentication protAuthService.performAuthentication(request, response, pendingReq); } - /** * PreProcess Authn request. * - * @param request http request + * @param request http request * @param pendingReq current pending request * @throws Throwable in case of an error */ @@ -458,7 +453,7 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement if (authnRequest.getIssueInstant() == null) { log.warn("Unsupported request: No IssueInstant Attribute found."); throw new AuthnRequestValidatorException("pvp2.22", - new Object[] {"Unsupported request: No IssueInstant Attribute found"}, pendingReq); + new Object[] { "Unsupported request: No IssueInstant Attribute found" }, pendingReq); } @@ -466,7 +461,7 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement .isAfterNow()) { log.warn("Unsupported request: No IssueInstant DateTime is not valid anymore."); throw new AuthnRequestValidatorException("pvp2.22", - new Object[] {"Unsupported request: No IssueInstant DateTime is not valid anymore."}, + new Object[] { "Unsupported request: No IssueInstant DateTime is not valid anymore." }, pendingReq); } @@ -496,14 +491,13 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement } - } else { // use AssertionConsumerServiceIndex and select consumerService from metadata final Integer aIdx = authnRequest.getAssertionConsumerServiceIndex(); int assertionidx = 0; if (aIdx != null) { - assertionidx = aIdx.intValue(); + assertionidx = aIdx; } else { assertionidx = Saml2Utils.getDefaultAssertionConsumerServiceIndex(spSsoDescriptor); @@ -517,7 +511,6 @@ public abstract class AbstractPvp2XProtocol extends AbstractController implement } } - // validate AuthnRequest final AuthnRequest authReq = (AuthnRequest) samlReq; final String oaUrl = moaRequest.getEntityMetadata(metadataProvider).getEntityID(); diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java index 200d98c4..c0190959 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/AuthenticationAction.java @@ -23,19 +23,6 @@ import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.joda.time.DateTime; -import org.opensaml.saml.common.xml.SAMLConstants; -import org.opensaml.saml.saml2.core.Assertion; -import org.opensaml.saml.saml2.core.AuthnRequest; -import org.opensaml.saml.saml2.core.Response; -import org.opensaml.saml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml.saml2.metadata.EntityDescriptor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.stereotype.Service; - import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.idp.IAction; import at.gv.egiz.eaaf.core.api.idp.IAuthData; @@ -57,13 +44,23 @@ import at.gv.egiz.eaaf.modules.pvp2.impl.message.PvpSProfileRequest; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import org.joda.time.DateTime; +import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.saml2.core.Assertion; +import org.opensaml.saml.saml2.core.AuthnRequest; +import org.opensaml.saml.saml2.core.Response; +import org.opensaml.saml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml.saml2.metadata.EntityDescriptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.stereotype.Service; + @Service("PVPAuthenticationRequestAction") public class AuthenticationAction implements IAction { private static final Logger log = LoggerFactory.getLogger(AuthenticationAction.class); - private static final String CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION = - "protocols.pvp2.assertion.encryption.active"; - @Autowired(required = true) private IPvp2MetadataProvider metadataProvider; @Autowired(required = true) @@ -115,7 +112,7 @@ public class AuthenticationAction implements IAction { final Response authResponse = AuthResponseBuilder.buildResponse(metadataProvider, issuerEntityID, authnRequest, date, assertion, - authConfig.getBasicConfigurationBoolean(CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION, true)); + authConfig); IEncoder binding = null; @@ -141,7 +138,7 @@ public class AuthenticationAction implements IAction { sloInformation.setSpEntityID(req.getServiceProviderConfiguration().getUniqueIdentifier()); return sloInformation; - } catch (SecurityException e) { + } catch (final SecurityException e) { log.warn("Message Encoding exception", e); throw new ResponderErrorException("pvp2.01", null, e); diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java index a1e8b5ba..3f0ad0b6 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/MetadataAction.java @@ -22,6 +22,7 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.impl; import javax.annotation.PostConstruct; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; + import at.gv.egiz.eaaf.core.api.IRequest; import at.gv.egiz.eaaf.core.api.idp.IAction; import at.gv.egiz.eaaf.core.api.idp.IAuthData; @@ -33,6 +34,7 @@ import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvpMetadataConfigurationFactor import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2MetadataException; import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpMetadataBuilder; import at.gv.egiz.eaaf.modules.pvp2.impl.utils.AbstractCredentialProvider; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -74,8 +76,6 @@ public class MetadataAction implements IAction { final IPvpMetadataBuilderConfiguration metadataConfig = configFactory .generateMetadataBuilderConfiguration(req.getAuthUrlWithOutSlash(), pvpIdpCredentials); - - final String metadataXml = metadatabuilder.buildPvpMetadata(metadataConfig); log.trace("METADATA: " + metadataXml); @@ -117,5 +117,4 @@ public class MetadataAction implements IAction { } } - } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PvpSProfilePendingRequest.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PvpSProfilePendingRequest.java index 6c621841..26e04881 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PvpSProfilePendingRequest.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/PvpSProfilePendingRequest.java @@ -21,6 +21,7 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.impl; import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; import at.gv.egiz.eaaf.modules.pvp2.impl.message.InboundMessage; + import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java index 8cafebb9..55e3e8b4 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/AuthResponseBuilder.java @@ -19,37 +19,55 @@ package at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder; +import java.security.PublicKey; +import java.security.interfaces.ECPublicKey; +import java.security.interfaces.RSAPublicKey; import java.util.ArrayList; import java.util.List; +import at.gv.egiz.eaaf.core.api.idp.IConfiguration; +import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; +import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; +import at.gv.egiz.eaaf.modules.pvp2.exception.SamlSigningException; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionEncryptionException; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; + import org.joda.time.DateTime; import org.opensaml.core.criterion.EntityIdCriterion; import org.opensaml.saml.common.xml.SAMLConstants; +import org.opensaml.saml.criterion.EntityRoleCriterion; +import org.opensaml.saml.criterion.ProtocolCriterion; +import org.opensaml.saml.metadata.resolver.impl.PredicateRoleDescriptorResolver; import org.opensaml.saml.saml2.core.Assertion; import org.opensaml.saml.saml2.core.EncryptedAssertion; import org.opensaml.saml.saml2.core.Issuer; import org.opensaml.saml.saml2.core.NameIDType; import org.opensaml.saml.saml2.core.RequestAbstractType; import org.opensaml.saml.saml2.core.Response; +import org.opensaml.saml.saml2.encryption.Encrypter; import org.opensaml.saml.saml2.encryption.Encrypter.KeyPlacement; import org.opensaml.saml.saml2.metadata.SPSSODescriptor; import org.opensaml.saml.security.impl.MetadataCredentialResolver; -import org.opensaml.security.MetadataCriteria; import org.opensaml.security.credential.UsageType; import org.opensaml.security.criteria.UsageCriterion; import org.opensaml.security.x509.X509Credential; -import org.opensaml.xmlsec.EncryptionParameters; +import org.opensaml.xmlsec.SecurityConfigurationSupport; +import org.opensaml.xmlsec.encryption.support.DataEncryptionParameters; import org.opensaml.xmlsec.encryption.support.EncryptionException; import org.opensaml.xmlsec.encryption.support.KeyEncryptionParameters; +import org.opensaml.xmlsec.keyinfo.KeyInfoCredentialResolver; import org.opensaml.xmlsec.keyinfo.KeyInfoGeneratorFactory; +import org.opensaml.xmlsec.keyinfo.impl.BasicProviderKeyInfoCredentialResolver; +import org.opensaml.xmlsec.keyinfo.impl.KeyInfoProvider; +import org.opensaml.xmlsec.keyinfo.impl.provider.DSAKeyValueProvider; +import org.opensaml.xmlsec.keyinfo.impl.provider.InlineX509DataProvider; +import org.opensaml.xmlsec.keyinfo.impl.provider.RSAKeyValueProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; -import at.gv.egiz.eaaf.modules.pvp2.api.metadata.IPvp2MetadataProvider; -import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionEncryptionException; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import net.shibboleth.utilities.java.support.component.ComponentInitializationException; import net.shibboleth.utilities.java.support.resolver.CriteriaSet; +import net.shibboleth.utilities.java.support.resolver.ResolverException; /** * Authentication response builder. @@ -65,17 +83,17 @@ public class AuthResponseBuilder { * Build PVP2 S-Profile authentication response. * * @param metadataProvider Service-Provider metadata - * @param issuerEntityID IDP entityId - * @param req current pending request - * @param date Timestamp - * @param assertion PVP2 S-Profil Assertion - * @param enableEncryption encrypt Assertion flag + * @param issuerEntityID IDP entityId + * @param req current pending request + * @param date Timestamp + * @param assertion PVP2 S-Profil Assertion + * @param authConfig {@link IConfiguration} * @return PVP2 S-Profile authentication response * @throws InvalidAssertionEncryptionException In case of an error */ public static Response buildResponse(final IPvp2MetadataProvider metadataProvider, final String issuerEntityID, final RequestAbstractType req, final DateTime date, - final Assertion assertion, final boolean enableEncryption) + final Assertion assertion, IConfiguration authConfig) throws InvalidAssertionEncryptionException { final Response authResponse = Saml2Utils.createSamlObject(Response.class); @@ -90,72 +108,117 @@ public class AuthResponseBuilder { final String remoteSessionID = Saml2Utils.getSecureIdentifier(); authResponse.setID(remoteSessionID); - // SAML2 response required IssueInstant authResponse.setIssueInstant(date); authResponse.setStatus(Saml2Utils.getSuccessStatus()); // check, if metadata includes an encryption key - final MetadataCredentialResolver mdCredResolver = - new MetadataCredentialResolver(metadataProvider); - - final CriteriaSet criteriaSet = new CriteriaSet(); - criteriaSet.add(new EntityIdCriterion(req.getIssuer().getValue())); - criteriaSet - .add(new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); - criteriaSet.add(new UsageCriterion(UsageType.ENCRYPTION)); + final X509Credential encryptionCredentials = resolveEncryptionCredential(req, metadataProvider); - X509Credential encryptionCredentials = null; - try { - encryptionCredentials = (X509Credential) mdCredResolver.resolveSingle(criteriaSet); + if (encryptionCredentials != null + && authConfig.getBasicConfigurationBoolean( + PvpConstants.CONFIG_PROPERTY_PVP2_ENABLE_ENCRYPTION, true)) { + authResponse.getEncryptedAssertions().add( + doEncryption(assertion, encryptionCredentials, authConfig)); - } catch (final SecurityException e2) { - log.warn("Can not extract the Assertion Encryption-Key from metadata", e2); - throw new InvalidAssertionEncryptionException(); + } else { + authResponse.getAssertions().add(assertion); } - if (encryptionCredentials != null && enableEncryption) { - // encrypt SAML2 assertion + return authResponse; + } + + private static EncryptedAssertion doEncryption(Assertion assertion, + X509Credential encryptionCredentials, IConfiguration authConfig) + throws InvalidAssertionEncryptionException { + try { + final String keyEncAlg = selectKeyEncryptionAlgorithm(encryptionCredentials, authConfig); - try { + final DataEncryptionParameters dataEncParams = new DataEncryptionParameters(); + dataEncParams.setAlgorithm(authConfig.getBasicConfiguration( + PvpConstants.CONFIG_PROP_SEC_ENCRYPTION_DATA, PvpConstants.DEFAULT_SYM_ENCRYPTION_METHODE)); - final EncryptionParameters dataEncParams = new EncryptionParameters(); - dataEncParams.setAlgorithm(PvpConstants.DEFAULT_SYM_ENCRYPTION_METHODE); + final List keyEncParamList = new ArrayList<>(); + final KeyEncryptionParameters keyEncParam = new KeyEncryptionParameters(); + keyEncParam.setEncryptionCredential(encryptionCredentials); + keyEncParam.setAlgorithm(keyEncAlg); - final List keyEncParamList = new ArrayList<>(); - final KeyEncryptionParameters keyEncParam = new KeyEncryptionParameters(); + final KeyInfoGeneratorFactory kigf = + SecurityConfigurationSupport.getGlobalEncryptionConfiguration() + .getKeyTransportKeyInfoGeneratorManager().getDefaultManager().getFactory(encryptionCredentials); + keyEncParam.setKeyInfoGenerator(kigf.newInstance()); + keyEncParamList.add(keyEncParam); - keyEncParam.setEncryptionCredential(encryptionCredentials); - keyEncParam.setAlgorithm(PvpConstants.DEFAULT_ASYM_ENCRYPTION_METHODE); - final KeyInfoGeneratorFactory kigf = - org.opensaml.xml.Configuration.getGlobalSecurityConfiguration() - .getKeyInfoGeneratorManager().getDefaultManager().getFactory(encryptionCredentials); - keyEncParam.setKeyInfoGenerator(kigf.newInstance()); - keyEncParamList.add(keyEncParam); + final Encrypter samlEncrypter = new Encrypter(dataEncParams, keyEncParamList); + samlEncrypter.setKeyPlacement(KeyPlacement.PEER); - final Encrypter samlEncrypter = new Encrypter(dataEncParams, keyEncParamList); - // samlEncrypter.setKeyPlacement(KeyPlacement.INLINE); - samlEncrypter.setKeyPlacement(KeyPlacement.PEER); + return samlEncrypter.encrypt(assertion); - EncryptedAssertion encryptAssertion = null; + } catch (final EncryptionException | SamlSigningException e1) { + log.warn("Can not encrypt the PVP2 assertion", e1); + throw new InvalidAssertionEncryptionException(); - encryptAssertion = samlEncrypter.encrypt(assertion); + } - authResponse.getEncryptedAssertions().add(encryptAssertion); + } - } catch (final EncryptionException e1) { - log.warn("Can not encrypt the PVP2 assertion", e1); - throw new InvalidAssertionEncryptionException(); + private static String selectKeyEncryptionAlgorithm(X509Credential encryptionCredentials, + IConfiguration authConfig) throws SamlSigningException { + final PublicKey privatekey = encryptionCredentials.getPublicKey(); + if (privatekey instanceof RSAPublicKey) { + return authConfig.getBasicConfiguration( + PvpConstants.CONFIG_PROP_SEC_ENCRYPTION_KEY_RSA_ALG, + PvpConstants.DEFAULT_ASYM_ENCRYPTION_METHODE_RSA); - } + } else if (privatekey instanceof ECPublicKey) { + return authConfig.getBasicConfiguration( + PvpConstants.CONFIG_PROP_SEC_ENCRYPTION_KEY_EC_ALG, + PvpConstants.DEFAULT_ASYM_ENCRYPTION_METHODE_EC); } else { - authResponse.getAssertions().add(assertion); + log.warn("Could NOT evaluate the Private-Key type from " + encryptionCredentials.getEntityId() + + " credential."); + throw new SamlSigningException("internal.pvp.97", + new Object[] { encryptionCredentials.getEntityId(), privatekey.getClass().getName() }); } - return authResponse; + } + + private static X509Credential resolveEncryptionCredential(RequestAbstractType req, + IPvp2MetadataProvider metadataProvider) throws InvalidAssertionEncryptionException { + try { + final List keyInfoProvider = new ArrayList<>(); + keyInfoProvider.add(new DSAKeyValueProvider()); + keyInfoProvider.add(new RSAKeyValueProvider()); + keyInfoProvider.add(new InlineX509DataProvider()); + final KeyInfoCredentialResolver keyInfoCredentialResolver = new BasicProviderKeyInfoCredentialResolver( + keyInfoProvider); + + final PredicateRoleDescriptorResolver roleDescriptorResolver = new PredicateRoleDescriptorResolver( + metadataProvider); + roleDescriptorResolver.setRequireValidMetadata(true); + roleDescriptorResolver.initialize(); + + final MetadataCredentialResolver mdCredResolver = new MetadataCredentialResolver(); + mdCredResolver.setRoleDescriptorResolver(roleDescriptorResolver); + mdCredResolver.setKeyInfoCredentialResolver(keyInfoCredentialResolver); + mdCredResolver.initialize(); + + final CriteriaSet criteriaSet = new CriteriaSet(); + criteriaSet.add(new EntityIdCriterion(req.getIssuer().getValue())); + criteriaSet.add(new ProtocolCriterion(SAMLConstants.SAML20P_NS)); + criteriaSet.add(new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME)); + criteriaSet.add(new UsageCriterion(UsageType.ENCRYPTION)); + + return (X509Credential) mdCredResolver.resolveSingle(criteriaSet); + + } catch (final SecurityException | ComponentInitializationException | ResolverException e2) { + log.warn("Can not extract the Assertion Encryption-Key from metadata", e2); + throw new InvalidAssertionEncryptionException(); + + } } } diff --git a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java index 922e7efe..b7b18f0f 100644 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java @@ -24,6 +24,8 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import javax.naming.ConfigurationException; + import at.gv.egiz.eaaf.core.api.data.EaafConstants; import at.gv.egiz.eaaf.core.api.data.ILoALevelMapper; import at.gv.egiz.eaaf.core.api.idp.IAuthData; @@ -86,17 +88,16 @@ public class Pvp2AssertionBuilder implements PvpConstants { @Autowired private ISubjectNameIdGenerator subjectNameIdGenerator; - /** * Build a PVP assertion as response for a SAML2 AttributeQuery request. * * @param issuerEntityID EnitiyID, which should be used for this IDP response - * @param attrQuery AttributeQuery request from Service-Provider - * @param attrList List of PVP response attributes - * @param now Current time - * @param validTo ValidTo time of the assertion - * @param qaaLevel QAA level of the authentication - * @param sessionIndex SAML2 SessionIndex, which should be included * + * @param attrQuery AttributeQuery request from Service-Provider + * @param attrList List of PVP response attributes + * @param now Current time + * @param validTo ValidTo time of the assertion + * @param qaaLevel QAA level of the authentication + * @param sessionIndex SAML2 SessionIndex, which should be included * * @return PVP 2.1 Assertion * @throws Pvp2Exception In case of an error */ @@ -119,18 +120,21 @@ public class Pvp2AssertionBuilder implements PvpConstants { validTo); } - /** * Build a PVP 2.1 assertion as response of a SAML2 AuthnRequest. * - * @param issuerEntityID EnitiyID, which should be used for this IDP response - * @param pendingReq Current processed pendingRequest DAO - * @param authnRequest Current processed PVP AuthnRequest - * @param authData AuthenticationData of the user, which is already authenticated - * @param peerEntity SAML2 EntityDescriptor of the service-provider, which receives the response - * @param date TimeStamp - * @param assertionConsumerService SAML2 endpoint of the service-provider, which should be used - * @param sloInformation Single LogOut information DAO + * @param issuerEntityID EnitiyID, which should be used for this IDP + * response + * @param pendingReq Current processed pendingRequest DAO + * @param authnRequest Current processed PVP AuthnRequest + * @param authData AuthenticationData of the user, which is + * already authenticated + * @param peerEntity SAML2 EntityDescriptor of the + * service-provider, which receives the response + * @param date TimeStamp + * @param assertionConsumerService SAML2 endpoint of the service-provider, which + * should be used + * @param sloInformation Single LogOut information DAO * @return PVP2 S-Profil Assertion * @throws Pvp2Exception In case of an error */ @@ -203,7 +207,6 @@ public class Pvp2AssertionBuilder implements PvpConstants { } } - // load SPSS decriptor from service-provider metadata final SPSSODescriptor spSsoDescriptor = peerEntity.getSPSSODescriptor(SAMLConstants.SAML20P_NS); @@ -217,7 +220,7 @@ public class Pvp2AssertionBuilder implements PvpConstants { AttributeConsumingService attributeConsumingService = null; if (aIdx != null) { - idx = aIdx.intValue(); + idx = aIdx; attributeConsumingService = spSsoDescriptor.getAttributeConsumingServices().get(idx); } else { @@ -231,8 +234,8 @@ public class Pvp2AssertionBuilder implements PvpConstants { } /* - * TODO: maybe use first AttributeConsumingService if no is selected in request or on service - * is marked as default + * TODO: maybe use first AttributeConsumingService if no is selected in request + * or on service is marked as default * */ if (attributeConsumingService == null) { @@ -244,7 +247,6 @@ public class Pvp2AssertionBuilder implements PvpConstants { } - if (attributeConsumingService != null) { final Iterator it = attributeConsumingService.getRequestAttributes().iterator(); @@ -268,7 +270,6 @@ public class Pvp2AssertionBuilder implements PvpConstants { throw new UnprovideableAttributeException(reqAttribut.getName()); } - } catch (final Pvp2Exception e) { log.info("Attribute generation failed! for " + reqAttribut.getFriendlyName()); if (reqAttribut.isRequired()) { @@ -342,10 +343,10 @@ public class Pvp2AssertionBuilder implements PvpConstants { subjectNameID.setFormat(nameIdFormat); } - String sessionIndex = null; - // if request is a reauthentication and NameIDFormat match reuse old session information + // if request is a reauthentication and NameIDFormat match reuse old session + // information if (StringUtils.isNotEmpty(authData.getNameID()) && StringUtils.isNotEmpty(authData.getNameIdFormat()) && nameIdFormat.equals(authData.getNameIdFormat())) { @@ -368,7 +369,8 @@ public class Pvp2AssertionBuilder implements PvpConstants { // set 'recipient' attribute in subjectConformationData subjectConfirmationData.setRecipient(assertionConsumerService.getLocation()); - // set IP address of the user machine as 'Address' attribute in subjectConformationData + // set IP address of the user machine as 'Address' attribute in + // subjectConformationData final String usersIpAddress = pendingReq.getRawData(RequestImpl.DATAID_REQUESTER_IP_ADDRESS, String.class); if (StringUtils.isNotEmpty(usersIpAddress)) { @@ -388,15 +390,15 @@ public class Pvp2AssertionBuilder implements PvpConstants { /** * Build generic part of PVP S-Profile Assertion. * - * @param issuer IDP EntityID - * @param entityID Service Provider EntityID - * @param date Timestamp - * @param authnContextClassRef SAML2 AuthnContextClassReference - * @param attrList List of attributes - * @param subjectNameID SubjectNameId + * @param issuer IDP EntityID + * @param entityID Service Provider EntityID + * @param date Timestamp + * @param authnContextClassRef SAML2 AuthnContextClassReference + * @param attrList List of attributes + * @param subjectNameID SubjectNameId * @param subjectConfirmationData SubjectConfirmationInformation - * @param sessionIndex SessionIndex - * @param isValidTo ValidTo Timestamp + * @param sessionIndex SessionIndex + * @param isValidTo ValidTo Timestamp * @return PVP S-Profile Assertion * @throws ConfigurationException In case on an error */ -- cgit v1.2.3