From 759ac5f42c6aff901dbeede4fbf1a1d2e08cad0f Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Wed, 4 Dec 2019 19:43:32 +0100 Subject: common EGIZ code-style refactoring --- .../pvp2/idp/impl/builder/AuthResponseBuilder.java | 234 ++++++----- .../idp/impl/builder/PVP2AssertionBuilder.java | 459 -------------------- .../idp/impl/builder/Pvp2AssertionBuilder.java | 465 +++++++++++++++++++++ 3 files changed, 586 insertions(+), 572 deletions(-) delete mode 100644 eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/PVP2AssertionBuilder.java create mode 100644 eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java (limited to 'eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder') 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 07423c19..bf51ac0f 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 @@ -1,41 +1,35 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + package at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder; import java.util.ArrayList; import java.util.List; - +import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; +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.Configuration; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.core.Assertion; import org.opensaml.saml2.core.EncryptedAssertion; import org.opensaml.saml2.core.Issuer; -import org.opensaml.saml2.core.NameID; +import org.opensaml.saml2.core.NameIDType; import org.opensaml.saml2.core.RequestAbstractType; import org.opensaml.saml2.core.Response; import org.opensaml.saml2.encryption.Encrypter; @@ -57,97 +51,111 @@ import org.opensaml.xml.security.x509.X509Credential; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import at.gv.egiz.eaaf.modules.pvp2.PVPConstants; -import at.gv.egiz.eaaf.modules.pvp2.idp.exception.InvalidAssertionEncryptionException; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils; - /** + * Authentication response builder. + * * @author tlenz * */ public class AuthResponseBuilder { - private static final Logger log = LoggerFactory.getLogger(AuthResponseBuilder.class); - - public static Response buildResponse(MetadataProvider metadataProvider, String issuerEntityID, RequestAbstractType req, DateTime date, Assertion assertion, boolean enableEncryption) throws InvalidAssertionEncryptionException { - Response authResponse = SAML2Utils.createSAMLObject(Response.class); - - Issuer nissuer = SAML2Utils.createSAMLObject(Issuer.class); - - nissuer.setValue(issuerEntityID); - nissuer.setFormat(NameID.ENTITY); - authResponse.setIssuer(nissuer); - authResponse.setInResponseTo(req.getID()); - - //set responseID - 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 - MetadataCredentialResolver mdCredResolver = - new MetadataCredentialResolver(metadataProvider); - - CriteriaSet criteriaSet = new CriteriaSet(); - criteriaSet.add( new EntityIDCriteria(req.getIssuer().getValue()) ); - criteriaSet.add( new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS) ); - criteriaSet.add( new UsageCriteria(UsageType.ENCRYPTION) ); - - X509Credential encryptionCredentials = null; - try { - encryptionCredentials = (X509Credential) mdCredResolver.resolveSingle(criteriaSet); - - } catch (SecurityException e2) { - log.warn("Can not extract the Assertion Encryption-Key from metadata", e2); - throw new InvalidAssertionEncryptionException(); - - } - - if (encryptionCredentials != null && enableEncryption) { - //encrypt SAML2 assertion - - try { - - EncryptionParameters dataEncParams = new EncryptionParameters(); - dataEncParams.setAlgorithm(PVPConstants.DEFAULT_SYM_ENCRYPTION_METHODE); - - List keyEncParamList = new ArrayList(); - KeyEncryptionParameters keyEncParam = new KeyEncryptionParameters(); - - keyEncParam.setEncryptionCredential(encryptionCredentials); - keyEncParam.setAlgorithm(PVPConstants.DEFAULT_ASYM_ENCRYPTION_METHODE); - KeyInfoGeneratorFactory kigf = Configuration.getGlobalSecurityConfiguration() - .getKeyInfoGeneratorManager().getDefaultManager() - .getFactory(encryptionCredentials); - keyEncParam.setKeyInfoGenerator(kigf.newInstance()); - keyEncParamList.add(keyEncParam); - - Encrypter samlEncrypter = new Encrypter(dataEncParams, keyEncParamList); - //samlEncrypter.setKeyPlacement(KeyPlacement.INLINE); - samlEncrypter.setKeyPlacement(KeyPlacement.PEER); - - EncryptedAssertion encryptAssertion = null; - - encryptAssertion = samlEncrypter.encrypt(assertion); - - authResponse.getEncryptedAssertions().add(encryptAssertion); - - } catch (EncryptionException e1) { - log.warn("Can not encrypt the PVP2 assertion", e1); - throw new InvalidAssertionEncryptionException(); - - } - - } else { - authResponse.getAssertions().add(assertion); - - } - - return authResponse; - } + private static final Logger log = LoggerFactory.getLogger(AuthResponseBuilder.class); + + /** + * 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 + * @return PVP2 S-Profile authentication response + * @throws InvalidAssertionEncryptionException In case of an error + */ + public static Response buildResponse(final MetadataProvider metadataProvider, + final String issuerEntityID, final RequestAbstractType req, final DateTime date, + final Assertion assertion, final boolean enableEncryption) + throws InvalidAssertionEncryptionException { + final Response authResponse = Saml2Utils.createSamlObject(Response.class); + + final Issuer nissuer = Saml2Utils.createSamlObject(Issuer.class); + + nissuer.setValue(issuerEntityID); + nissuer.setFormat(NameIDType.ENTITY); + authResponse.setIssuer(nissuer); + authResponse.setInResponseTo(req.getID()); + + // set responseID + 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 EntityIDCriteria(req.getIssuer().getValue())); + criteriaSet + .add(new MetadataCriteria(SPSSODescriptor.DEFAULT_ELEMENT_NAME, SAMLConstants.SAML20P_NS)); + criteriaSet.add(new UsageCriteria(UsageType.ENCRYPTION)); + + X509Credential encryptionCredentials = null; + try { + encryptionCredentials = (X509Credential) mdCredResolver.resolveSingle(criteriaSet); + + } catch (final SecurityException e2) { + log.warn("Can not extract the Assertion Encryption-Key from metadata", e2); + throw new InvalidAssertionEncryptionException(); + + } + + if (encryptionCredentials != null && enableEncryption) { + // encrypt SAML2 assertion + + try { + + 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(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.INLINE); + samlEncrypter.setKeyPlacement(KeyPlacement.PEER); + + EncryptedAssertion encryptAssertion = null; + + encryptAssertion = samlEncrypter.encrypt(assertion); + + authResponse.getEncryptedAssertions().add(encryptAssertion); + + } catch (final EncryptionException e1) { + log.warn("Can not encrypt the PVP2 assertion", e1); + throw new InvalidAssertionEncryptionException(); + + } + + } else { + authResponse.getAssertions().add(assertion); + + } + + return authResponse; + } } 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 deleted file mode 100644 index 2ccc2c9e..00000000 --- a/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/PVP2AssertionBuilder.java +++ /dev/null @@ -1,459 +0,0 @@ -/******************************************************************************* - * Copyright 2017 Graz University of Technology - * EAAF-Core Components has been developed in a cooperation between EGIZ, - * A-SIT Plus, A-SIT, and Graz University of Technology. - * - * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the "Licence"); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * https://joinup.ec.europa.eu/news/understanding-eupl-v12 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - * This product combines work with different licenses. See the "NOTICE" text - * file for details on the various modules and licenses. - * The "NOTICE" text file is part of the distribution. Any derivative works - * that you distribute must include a readable copy of the "NOTICE" text file. - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -/******************************************************************************* - *******************************************************************************/ -package at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder; - -import java.security.MessageDigest; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.apache.commons.lang3.StringUtils; -import org.joda.time.DateTime; -import org.opensaml.common.xml.SAMLConstants; -import org.opensaml.saml2.core.Assertion; -import org.opensaml.saml2.core.Attribute; -import org.opensaml.saml2.core.AttributeQuery; -import org.opensaml.saml2.core.AttributeStatement; -import org.opensaml.saml2.core.Audience; -import org.opensaml.saml2.core.AudienceRestriction; -import org.opensaml.saml2.core.AuthnContext; -import org.opensaml.saml2.core.AuthnContextClassRef; -import org.opensaml.saml2.core.AuthnRequest; -import org.opensaml.saml2.core.AuthnStatement; -import org.opensaml.saml2.core.Conditions; -import org.opensaml.saml2.core.Issuer; -import org.opensaml.saml2.core.NameID; -import org.opensaml.saml2.core.RequestedAuthnContext; -import org.opensaml.saml2.core.Subject; -import org.opensaml.saml2.core.SubjectConfirmation; -import org.opensaml.saml2.core.SubjectConfirmationData; -import org.opensaml.saml2.core.impl.AuthnRequestImpl; -import org.opensaml.saml2.metadata.AssertionConsumerService; -import org.opensaml.saml2.metadata.AttributeConsumingService; -import org.opensaml.saml2.metadata.EntityDescriptor; -import org.opensaml.saml2.metadata.NameIDFormat; -import org.opensaml.saml2.metadata.RequestedAttribute; -import org.opensaml.saml2.metadata.SPSSODescriptor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Service; -import org.springframework.util.Base64Utils; - -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; -import at.gv.egiz.eaaf.core.api.idp.ISPConfiguration; -import at.gv.egiz.eaaf.core.api.idp.slo.SLOInformationInterface; -import at.gv.egiz.eaaf.core.exceptions.UnavailableAttributeException; -import at.gv.egiz.eaaf.core.impl.data.Pair; -import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; -import at.gv.egiz.eaaf.core.impl.utils.Random; -import at.gv.egiz.eaaf.modules.pvp2.PVPConstants; -import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; -import at.gv.egiz.eaaf.modules.pvp2.exception.QAANotSupportedException; -import at.gv.egiz.eaaf.modules.pvp2.idp.api.builder.ISubjectNameIdGenerator; -import at.gv.egiz.eaaf.modules.pvp2.idp.exception.ResponderErrorException; -import at.gv.egiz.eaaf.modules.pvp2.idp.exception.UnprovideableAttributeException; -import at.gv.egiz.eaaf.modules.pvp2.idp.impl.PVPSProfilePendingRequest; -import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PVPAttributeBuilder; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.QAALevelVerifier; -import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils; - -@Service("PVP2AssertionBuilder") -public class PVP2AssertionBuilder implements PVPConstants { - - private static final Logger log = LoggerFactory.getLogger(PVP2AssertionBuilder.class); - @Autowired private ILoALevelMapper loaLevelMapper; - @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 * - * @return PVP 2.1 Assertion - * @throws PVP2Exception - */ - public Assertion buildAssertion(String issuerEntityID, AttributeQuery attrQuery, - List attrList, DateTime now, DateTime validTo, String qaaLevel, String sessionIndex) throws PVP2Exception { - - AuthnContextClassRef authnContextClassRef = SAML2Utils.createSAMLObject(AuthnContextClassRef.class); - authnContextClassRef.setAuthnContextClassRef(qaaLevel); - - NameID subjectNameID = SAML2Utils.createSAMLObject(NameID.class); - subjectNameID.setFormat(attrQuery.getSubject().getNameID().getFormat()); - subjectNameID.setValue(attrQuery.getSubject().getNameID().getValue()); - - SubjectConfirmationData subjectConfirmationData = null; - - return buildGenericAssertion(issuerEntityID, attrQuery.getIssuer().getValue(), now, - authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, - 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 - * @return - * @throws PVP2Exception - */ - public Assertion buildAssertion(String issuerEntityID, PVPSProfilePendingRequest pendingReq, AuthnRequest authnRequest, - IAuthData authData, EntityDescriptor peerEntity, DateTime date, - AssertionConsumerService assertionConsumerService, SLOInformationInterface sloInformation) - throws PVP2Exception { - - ISPConfiguration oaParam = pendingReq.getServiceProviderConfiguration(); - AuthnContextClassRef authnContextClassRef = SAML2Utils.createSAMLObject(AuthnContextClassRef.class); - - //check if authn. request contains LoA - RequestedAuthnContext reqAuthnContext = authnRequest.getRequestedAuthnContext(); - if (reqAuthnContext == null) { - authnContextClassRef.setAuthnContextClassRef(authData.getEIDASQAALevel()); - - } else { - //authn. request requests LoA levels. To LoA validation - List reqAuthnContextClassRefIt = reqAuthnContext.getAuthnContextClassRefs(); - - //get matching mode from authn. request - String loaMatchingMode = EAAFConstants.EIDAS_LOA_MATCHING_MINIMUM; - if (reqAuthnContext.getComparison() != null && - StringUtils.isNotEmpty(reqAuthnContext.getComparison().toString())) - loaMatchingMode = reqAuthnContext.getComparison().toString(); - - //get requested LoAs - if (reqAuthnContextClassRefIt.size() == 0) { - QAALevelVerifier.verifyQAALevel(authData.getEIDASQAALevel(), - oaParam.getRequiredLoA(), loaMatchingMode); - authnContextClassRef.setAuthnContextClassRef(authData.getEIDASQAALevel()); - - } else { - List eIDASLoaFromRequest = new ArrayList(); - for (AuthnContextClassRef authnClassRef : reqAuthnContextClassRefIt) { - String qaa_uri = authnClassRef.getAuthnContextClassRef(); - - if (!qaa_uri.trim().startsWith(EAAFConstants.EIDAS_LOA_PREFIX)) { - if (loaLevelMapper != null) { - log.debug("Find no eIDAS LoA in AuthnReq. Start mapping process ... " ); - eIDASLoaFromRequest.add(loaLevelMapper.mapToeIDASLoA(qaa_uri.trim())); - - } else - log.debug("AuthnRequest contains no eIDAS LoA. NO LoA mapper FOUND, ignore " - + "'" + qaa_uri.trim() + "'"); - } else - eIDASLoaFromRequest.add(qaa_uri.trim()); - - } - - //stop process if no supported LoA scheme is requested - if (eIDASLoaFromRequest.isEmpty()) { - log.info("Authn. request contains no supported LoA level. Stop authentication process ... "); - throw new QAANotSupportedException("No supported LoA in Authn. request"); - - } - - //verifiy LoAs from request to authentication LoA - QAALevelVerifier.verifyQAALevel(authData.getEIDASQAALevel(), eIDASLoaFromRequest , loaMatchingMode); - authnContextClassRef.setAuthnContextClassRef(authData.getEIDASQAALevel()); - - } - } - - - //load SPSS decriptor from service-provider metadata - SPSSODescriptor spSSODescriptor = peerEntity.getSPSSODescriptor(SAMLConstants.SAML20P_NS); - - //add Attributes to Assertion - List attrList = new ArrayList(); - if (spSSODescriptor.getAttributeConsumingServices() != null && - spSSODescriptor.getAttributeConsumingServices().size() > 0) { - - Integer aIdx = authnRequest.getAttributeConsumingServiceIndex(); - int idx = 0; - - AttributeConsumingService attributeConsumingService = null; - if (aIdx != null) { - idx = aIdx.intValue(); - attributeConsumingService = spSSODescriptor - .getAttributeConsumingServices().get(idx); - - } else { - List attrConsumingServiceList = spSSODescriptor.getAttributeConsumingServices(); - for (AttributeConsumingService el : attrConsumingServiceList) { - if (el.isDefault()) - attributeConsumingService = el; - } - } - - /* - * TODO: maybe use first AttributeConsumingService if no is selected - * in request or on service is marked as default - * - */ - if (attributeConsumingService == null ) { - List attrConsumingServiceList = spSSODescriptor.getAttributeConsumingServices(); - if (attrConsumingServiceList != null && !attrConsumingServiceList.isEmpty()) - attributeConsumingService = attrConsumingServiceList.get(0); - - } - - - if (attributeConsumingService != null) { - Iterator it = attributeConsumingService - .getRequestAttributes().iterator(); - while (it.hasNext()) { - RequestedAttribute reqAttribut = it.next(); - try { - Attribute attr = PVPAttributeBuilder.buildAttribute( - reqAttribut.getName(), oaParam, authData); - if (attr == null) { - if (reqAttribut.isRequired()) { - throw new UnprovideableAttributeException( - reqAttribut.getName()); - } - } else { - attrList.add(attr); - } - - } catch (UnavailableAttributeException e) { - log.info( - "Attribute generation for " - + reqAttribut.getFriendlyName() + " not possible."); - if (reqAttribut.isRequired()) { - throw new UnprovideableAttributeException( - reqAttribut.getName()); - } - - - } catch (PVP2Exception e) { - log.info( - "Attribute generation failed! for " - + reqAttribut.getFriendlyName()); - if (reqAttribut.isRequired()) { - throw new UnprovideableAttributeException( - reqAttribut.getName()); - } - - } catch (Exception e) { - log.warn( - "General Attribute generation failed! for " - + reqAttribut.getFriendlyName(), e); - if (reqAttribut.isRequired()) { - throw new UnprovideableAttributeException( - reqAttribut.getName()); - } - - } - } - } - } - - //generate subjectNameId - NameID subjectNameID = SAML2Utils.createSAMLObject(NameID.class); - Pair subjectNameIdPair = subjectNameIdGenerator.generateSubjectNameId(authData, oaParam); - subjectNameID.setValue(subjectNameIdPair.getFirst()); - subjectNameID.setNameQualifier(subjectNameIdPair.getSecond()); - - //get NameIDFormat from request - String nameIDFormat = NameID.TRANSIENT; - AuthnRequest authnReq = (AuthnRequestImpl) authnRequest; - if (authnReq.getNameIDPolicy() != null && - StringUtils.isNotEmpty(authnReq.getNameIDPolicy().getFormat())) { - nameIDFormat = authnReq.getNameIDPolicy().getFormat(); - - } else { - //get NameIDFormat from metadata - List metadataNameIDFormats = spSSODescriptor.getNameIDFormats(); - - if (metadataNameIDFormats != null) { - - for (NameIDFormat el : metadataNameIDFormats) { - if (NameID.PERSISTENT.equals(el.getFormat())) { - nameIDFormat = NameID.PERSISTENT; - break; - - } else if (NameID.TRANSIENT.equals(el.getFormat()) || - NameID.UNSPECIFIED.equals(el.getFormat())) - break; - - } - } - } - - if (NameID.TRANSIENT.equals(nameIDFormat) || NameID.UNSPECIFIED.equals(nameIDFormat)) { - String random = Random.nextHexRandom32(); - String nameID = subjectNameID.getValue(); - - try { - MessageDigest md = MessageDigest.getInstance("SHA-1"); - byte[] hash = md.digest((nameID + random).getBytes("ISO-8859-1")); - subjectNameID.setValue(Base64Utils.encodeToString(hash)); - subjectNameID.setNameQualifier(null); - subjectNameID.setFormat(NameID.TRANSIENT); - - } catch (Exception e) { - log.warn("PVP2 subjectNameID error", e); - throw new ResponderErrorException("internal.03", null, e); - - } - - } else - subjectNameID.setFormat(nameIDFormat); - - - String sessionIndex = null; - - //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())) { - subjectNameID.setValue(authData.getNameID()); - sessionIndex = authData.getSessionIndex(); - - } - - // - if (StringUtils.isEmpty(sessionIndex)) - sessionIndex = SAML2Utils.getSecureIdentifier(); - - SubjectConfirmationData subjectConfirmationData = SAML2Utils - .createSAMLObject(SubjectConfirmationData.class); - subjectConfirmationData.setInResponseTo(authnRequest.getID()); - subjectConfirmationData.setNotOnOrAfter(new DateTime(authData.getSsoSessionValidTo().getTime())); - - //set 'recipient' attribute in subjectConformationData - subjectConfirmationData.setRecipient(assertionConsumerService.getLocation()); - - //set IP address of the user machine as 'Address' attribute in subjectConformationData - String usersIPAddress = pendingReq.getRawData( - RequestImpl.DATAID_REQUESTER_IP_ADDRESS, String.class); - if (StringUtils.isNotEmpty(usersIPAddress)) - subjectConfirmationData.setAddress(usersIPAddress); - - //set SLO information - sloInformation.setUserNameIdentifier(subjectNameID.getValue()); - sloInformation.setNameIDFormat(subjectNameID.getFormat()); - sloInformation.setSessionIndex(sessionIndex); - - return buildGenericAssertion(issuerEntityID, peerEntity.getEntityID(), date, authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, subjectConfirmationData.getNotOnOrAfter()); - } - - /** - * - * @param issuer IDP EntityID - * @param entityID Service Provider EntityID - * @param date - * @param authnContextClassRef - * @param attrList - * @param subjectNameID - * @param subjectConfirmationData - * @param sessionIndex - * @param isValidTo - * @return - * @throws ConfigurationException - */ - - public Assertion buildGenericAssertion(String issuer, String entityID, DateTime date, - AuthnContextClassRef authnContextClassRef, List attrList, - NameID subjectNameID, SubjectConfirmationData subjectConfirmationData, - String sessionIndex, DateTime isValidTo) throws ResponderErrorException { - Assertion assertion = SAML2Utils.createSAMLObject(Assertion.class); - - AuthnContext authnContext = SAML2Utils - .createSAMLObject(AuthnContext.class); - authnContext.setAuthnContextClassRef(authnContextClassRef); - - AuthnStatement authnStatement = SAML2Utils - .createSAMLObject(AuthnStatement.class); - - authnStatement.setAuthnInstant(date); - authnStatement.setSessionIndex(sessionIndex); - authnStatement.setAuthnContext(authnContext); - - assertion.getAuthnStatements().add(authnStatement); - - AttributeStatement attributeStatement = SAML2Utils - .createSAMLObject(AttributeStatement.class); - attributeStatement.getAttributes().addAll(attrList); - if (attributeStatement.getAttributes().size() > 0) { - assertion.getAttributeStatements().add(attributeStatement); - } - - Subject subject = SAML2Utils.createSAMLObject(Subject.class); - subject.setNameID(subjectNameID); - - SubjectConfirmation subjectConfirmation = SAML2Utils - .createSAMLObject(SubjectConfirmation.class); - subjectConfirmation.setMethod(SubjectConfirmation.METHOD_BEARER); - subjectConfirmation.setSubjectConfirmationData(subjectConfirmationData); - - subject.getSubjectConfirmations().add(subjectConfirmation); - - Conditions conditions = SAML2Utils.createSAMLObject(Conditions.class); - AudienceRestriction audienceRestriction = SAML2Utils - .createSAMLObject(AudienceRestriction.class); - Audience audience = SAML2Utils.createSAMLObject(Audience.class); - - audience.setAudienceURI(entityID); - audienceRestriction.getAudiences().add(audience); - conditions.setNotBefore(date); - conditions.setNotOnOrAfter(isValidTo); - - conditions.getAudienceRestrictions().add(audienceRestriction); - - assertion.setConditions(conditions); - - Issuer issuerObj = SAML2Utils.createSAMLObject(Issuer.class); - - if (issuer.endsWith("/")) - issuer = issuer.substring(0, issuer.length()-1); - issuerObj.setValue(issuer); - issuerObj.setFormat(NameID.ENTITY); - - assertion.setIssuer(issuerObj); - assertion.setSubject(subject); - assertion.setID(SAML2Utils.getSecureIdentifier()); - assertion.setIssueInstant(date); - - return assertion; - } -} 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 new file mode 100644 index 00000000..79de4567 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_idp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/idp/impl/builder/Pvp2AssertionBuilder.java @@ -0,0 +1,465 @@ +/* + * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a + * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European + * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in + * compliance with the Licence. You may obtain a copy of the Licence at: + * https://joinup.ec.europa.eu/news/understanding-eupl-v12 + * + * Unless required by applicable law or agreed to in writing, software distributed under the Licence + * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + * or implied. See the Licence for the specific language governing permissions and limitations under + * the Licence. + * + * This product combines work with different licenses. See the "NOTICE" text file for details on the + * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative + * works that you distribute must include a readable copy of the "NOTICE" text file. +*/ + +package at.gv.egiz.eaaf.modules.pvp2.idp.impl.builder; + +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +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; +import at.gv.egiz.eaaf.core.api.idp.IspConfiguration; +import at.gv.egiz.eaaf.core.api.idp.slo.SloInformationInterface; +import at.gv.egiz.eaaf.core.exceptions.UnavailableAttributeException; +import at.gv.egiz.eaaf.core.impl.data.Pair; +import at.gv.egiz.eaaf.core.impl.idp.controller.protocols.RequestImpl; +import at.gv.egiz.eaaf.core.impl.utils.Random; +import at.gv.egiz.eaaf.modules.pvp2.PvpConstants; +import at.gv.egiz.eaaf.modules.pvp2.exception.Pvp2Exception; +import at.gv.egiz.eaaf.modules.pvp2.exception.QaaNotSupportedException; +import at.gv.egiz.eaaf.modules.pvp2.idp.api.builder.ISubjectNameIdGenerator; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.ResponderErrorException; +import at.gv.egiz.eaaf.modules.pvp2.idp.exception.UnprovideableAttributeException; +import at.gv.egiz.eaaf.modules.pvp2.idp.impl.PvpSProfilePendingRequest; +import at.gv.egiz.eaaf.modules.pvp2.impl.builder.PvpAttributeBuilder; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.QaaLevelVerifier; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.Saml2Utils; +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.core.Assertion; +import org.opensaml.saml2.core.Attribute; +import org.opensaml.saml2.core.AttributeQuery; +import org.opensaml.saml2.core.AttributeStatement; +import org.opensaml.saml2.core.Audience; +import org.opensaml.saml2.core.AudienceRestriction; +import org.opensaml.saml2.core.AuthnContext; +import org.opensaml.saml2.core.AuthnContextClassRef; +import org.opensaml.saml2.core.AuthnRequest; +import org.opensaml.saml2.core.AuthnStatement; +import org.opensaml.saml2.core.Conditions; +import org.opensaml.saml2.core.Issuer; +import org.opensaml.saml2.core.NameID; +import org.opensaml.saml2.core.NameIDType; +import org.opensaml.saml2.core.RequestedAuthnContext; +import org.opensaml.saml2.core.Subject; +import org.opensaml.saml2.core.SubjectConfirmation; +import org.opensaml.saml2.core.SubjectConfirmationData; +import org.opensaml.saml2.metadata.AssertionConsumerService; +import org.opensaml.saml2.metadata.AttributeConsumingService; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.NameIDFormat; +import org.opensaml.saml2.metadata.RequestedAttribute; +import org.opensaml.saml2.metadata.SPSSODescriptor; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.Base64Utils; + +@Service("PVP2AssertionBuilder") +public class Pvp2AssertionBuilder implements PvpConstants { + + private static final Logger log = LoggerFactory.getLogger(Pvp2AssertionBuilder.class); + @Autowired + private ILoALevelMapper loaLevelMapper; + @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 * + * @return PVP 2.1 Assertion + * @throws Pvp2Exception In case of an error + */ + public Assertion buildAssertion(final String issuerEntityID, final AttributeQuery attrQuery, + final List attrList, final DateTime now, final DateTime validTo, + final String qaaLevel, final String sessionIndex) throws Pvp2Exception { + + final AuthnContextClassRef authnContextClassRef = + Saml2Utils.createSamlObject(AuthnContextClassRef.class); + authnContextClassRef.setAuthnContextClassRef(qaaLevel); + + final NameID subjectNameID = Saml2Utils.createSamlObject(NameID.class); + subjectNameID.setFormat(attrQuery.getSubject().getNameID().getFormat()); + subjectNameID.setValue(attrQuery.getSubject().getNameID().getValue()); + + final SubjectConfirmationData subjectConfirmationData = null; + + return buildGenericAssertion(issuerEntityID, attrQuery.getIssuer().getValue(), now, + authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, + 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 + * @return PVP2 S-Profil Assertion + * @throws Pvp2Exception In case of an error + */ + public Assertion buildAssertion(final String issuerEntityID, + final PvpSProfilePendingRequest pendingReq, final AuthnRequest authnRequest, + final IAuthData authData, final EntityDescriptor peerEntity, final DateTime date, + final AssertionConsumerService assertionConsumerService, + final SloInformationInterface sloInformation) throws Pvp2Exception { + + final IspConfiguration oaParam = pendingReq.getServiceProviderConfiguration(); + final AuthnContextClassRef authnContextClassRef = + Saml2Utils.createSamlObject(AuthnContextClassRef.class); + + // check if authn. request contains LoA + final RequestedAuthnContext reqAuthnContext = authnRequest.getRequestedAuthnContext(); + if (reqAuthnContext == null) { + authnContextClassRef.setAuthnContextClassRef(authData.getEidasQaaLevel()); + + } else { + // authn. request requests LoA levels. To LoA validation + final List reqAuthnContextClassRefIt = + reqAuthnContext.getAuthnContextClassRefs(); + + // get matching mode from authn. request + String loaMatchingMode = EAAFConstants.EIDAS_LOA_MATCHING_MINIMUM; + if (reqAuthnContext.getComparison() != null + && StringUtils.isNotEmpty(reqAuthnContext.getComparison().toString())) { + loaMatchingMode = reqAuthnContext.getComparison().toString(); + } + + // get requested LoAs + if (reqAuthnContextClassRefIt.size() == 0) { + QaaLevelVerifier.verifyQaaLevel(authData.getEidasQaaLevel(), oaParam.getRequiredLoA(), + loaMatchingMode); + authnContextClassRef.setAuthnContextClassRef(authData.getEidasQaaLevel()); + + } else { + final List eidasLoaFromRequest = new ArrayList<>(); + for (final AuthnContextClassRef authnClassRef : reqAuthnContextClassRefIt) { + final String qaa_uri = authnClassRef.getAuthnContextClassRef(); + + if (!qaa_uri.trim().startsWith(EAAFConstants.EIDAS_LOA_PREFIX)) { + if (loaLevelMapper != null) { + log.debug("Find no eIDAS LoA in AuthnReq. Start mapping process ... "); + eidasLoaFromRequest.add(loaLevelMapper.mapToeIDASLoA(qaa_uri.trim())); + + } else { + log.debug("AuthnRequest contains no eIDAS LoA. NO LoA mapper FOUND, ignore " + "'" + + qaa_uri.trim() + "'"); + } + } else { + eidasLoaFromRequest.add(qaa_uri.trim()); + } + + } + + // stop process if no supported LoA scheme is requested + if (eidasLoaFromRequest.isEmpty()) { + log.info( + "Authn. request contains no supported LoA level. Stop authentication process ... "); + throw new QaaNotSupportedException("No supported LoA in Authn. request"); + + } + + // verifiy LoAs from request to authentication LoA + QaaLevelVerifier.verifyQaaLevel(authData.getEidasQaaLevel(), eidasLoaFromRequest, + loaMatchingMode); + authnContextClassRef.setAuthnContextClassRef(authData.getEidasQaaLevel()); + + } + } + + + // load SPSS decriptor from service-provider metadata + final SPSSODescriptor spSsoDescriptor = peerEntity.getSPSSODescriptor(SAMLConstants.SAML20P_NS); + + // add Attributes to Assertion + final List attrList = new ArrayList<>(); + if (spSsoDescriptor.getAttributeConsumingServices() != null + && spSsoDescriptor.getAttributeConsumingServices().size() > 0) { + + final Integer aIdx = authnRequest.getAttributeConsumingServiceIndex(); + int idx = 0; + + AttributeConsumingService attributeConsumingService = null; + if (aIdx != null) { + idx = aIdx.intValue(); + attributeConsumingService = spSsoDescriptor.getAttributeConsumingServices().get(idx); + + } else { + final List attrConsumingServiceList = + spSsoDescriptor.getAttributeConsumingServices(); + for (final AttributeConsumingService el : attrConsumingServiceList) { + if (el.isDefault()) { + attributeConsumingService = el; + } + } + } + + /* + * TODO: maybe use first AttributeConsumingService if no is selected in request or on service + * is marked as default + * + */ + if (attributeConsumingService == null) { + final List attrConsumingServiceList = + spSsoDescriptor.getAttributeConsumingServices(); + if (attrConsumingServiceList != null && !attrConsumingServiceList.isEmpty()) { + attributeConsumingService = attrConsumingServiceList.get(0); + } + + } + + + if (attributeConsumingService != null) { + final Iterator it = + attributeConsumingService.getRequestAttributes().iterator(); + while (it.hasNext()) { + final RequestedAttribute reqAttribut = it.next(); + try { + final Attribute attr = + PvpAttributeBuilder.buildAttribute(reqAttribut.getName(), oaParam, authData); + if (attr == null) { + if (reqAttribut.isRequired()) { + throw new UnprovideableAttributeException(reqAttribut.getName()); + } + } else { + attrList.add(attr); + } + + } catch (final UnavailableAttributeException e) { + log.info( + "Attribute generation for " + reqAttribut.getFriendlyName() + " not possible."); + if (reqAttribut.isRequired()) { + throw new UnprovideableAttributeException(reqAttribut.getName()); + } + + + } catch (final Pvp2Exception e) { + log.info("Attribute generation failed! for " + reqAttribut.getFriendlyName()); + if (reqAttribut.isRequired()) { + throw new UnprovideableAttributeException(reqAttribut.getName()); + } + + } catch (final Exception e) { + log.warn("General Attribute generation failed! for " + reqAttribut.getFriendlyName(), + e); + if (reqAttribut.isRequired()) { + throw new UnprovideableAttributeException(reqAttribut.getName()); + } + + } + } + } + } + + // generate subjectNameId + final NameID subjectNameID = Saml2Utils.createSamlObject(NameID.class); + final Pair subjectNameIdPair = + subjectNameIdGenerator.generateSubjectNameId(authData, oaParam); + subjectNameID.setValue(subjectNameIdPair.getFirst()); + subjectNameID.setNameQualifier(subjectNameIdPair.getSecond()); + + // get NameIDFormat from request + String nameIdFormat = NameIDType.TRANSIENT; + final AuthnRequest authnReq = authnRequest; + if (authnReq.getNameIDPolicy() != null + && StringUtils.isNotEmpty(authnReq.getNameIDPolicy().getFormat())) { + nameIdFormat = authnReq.getNameIDPolicy().getFormat(); + + } else { + // get NameIDFormat from metadata + final List metadataNameIdFormats = spSsoDescriptor.getNameIDFormats(); + + if (metadataNameIdFormats != null) { + + for (final NameIDFormat el : metadataNameIdFormats) { + if (NameIDType.PERSISTENT.equals(el.getFormat())) { + nameIdFormat = NameIDType.PERSISTENT; + break; + + } else if (NameIDType.TRANSIENT.equals(el.getFormat()) + || NameIDType.UNSPECIFIED.equals(el.getFormat())) { + break; + } + + } + } + } + + if (NameIDType.TRANSIENT.equals(nameIdFormat) || NameIDType.UNSPECIFIED.equals(nameIdFormat)) { + final String random = Random.nextHexRandom32(); + final String nameID = subjectNameID.getValue(); + + try { + final MessageDigest md = MessageDigest.getInstance("SHA-1"); + final byte[] hash = md.digest((nameID + random).getBytes("ISO-8859-1")); + subjectNameID.setValue(Base64Utils.encodeToString(hash)); + subjectNameID.setNameQualifier(null); + subjectNameID.setFormat(NameIDType.TRANSIENT); + + } catch (final Exception e) { + log.warn("PVP2 subjectNameID error", e); + throw new ResponderErrorException("internal.03", null, e); + + } + + } else { + subjectNameID.setFormat(nameIdFormat); + } + + + String sessionIndex = null; + + // 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())) { + subjectNameID.setValue(authData.getNameID()); + sessionIndex = authData.getSessionIndex(); + + } + + // + if (StringUtils.isEmpty(sessionIndex)) { + sessionIndex = Saml2Utils.getSecureIdentifier(); + } + + final SubjectConfirmationData subjectConfirmationData = + Saml2Utils.createSamlObject(SubjectConfirmationData.class); + subjectConfirmationData.setInResponseTo(authnRequest.getID()); + subjectConfirmationData + .setNotOnOrAfter(new DateTime(authData.getSsoSessionValidTo().getTime())); + + // set 'recipient' attribute in subjectConformationData + subjectConfirmationData.setRecipient(assertionConsumerService.getLocation()); + + // 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)) { + subjectConfirmationData.setAddress(usersIpAddress); + } + + // set SLO information + sloInformation.setUserNameIdentifier(subjectNameID.getValue()); + sloInformation.setNameIdFormat(subjectNameID.getFormat()); + sloInformation.setSessionIndex(sessionIndex); + + return buildGenericAssertion(issuerEntityID, peerEntity.getEntityID(), date, + authnContextClassRef, attrList, subjectNameID, subjectConfirmationData, sessionIndex, + subjectConfirmationData.getNotOnOrAfter()); + } + + /** + * 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 subjectConfirmationData SubjectConfirmationInformation + * @param sessionIndex SessionIndex + * @param isValidTo ValidTo Timestamp + * @return PVP S-Profile Assertion + * @throws ConfigurationException In case on an error + */ + + public Assertion buildGenericAssertion(String issuer, final String entityID, final DateTime date, + final AuthnContextClassRef authnContextClassRef, final List attrList, + final NameID subjectNameID, final SubjectConfirmationData subjectConfirmationData, + final String sessionIndex, final DateTime isValidTo) throws ResponderErrorException { + final Assertion assertion = Saml2Utils.createSamlObject(Assertion.class); + + final AuthnContext authnContext = Saml2Utils.createSamlObject(AuthnContext.class); + authnContext.setAuthnContextClassRef(authnContextClassRef); + + final AuthnStatement authnStatement = Saml2Utils.createSamlObject(AuthnStatement.class); + + authnStatement.setAuthnInstant(date); + authnStatement.setSessionIndex(sessionIndex); + authnStatement.setAuthnContext(authnContext); + + assertion.getAuthnStatements().add(authnStatement); + + final AttributeStatement attributeStatement = + Saml2Utils.createSamlObject(AttributeStatement.class); + attributeStatement.getAttributes().addAll(attrList); + if (attributeStatement.getAttributes().size() > 0) { + assertion.getAttributeStatements().add(attributeStatement); + } + + final Subject subject = Saml2Utils.createSamlObject(Subject.class); + subject.setNameID(subjectNameID); + + final SubjectConfirmation subjectConfirmation = + Saml2Utils.createSamlObject(SubjectConfirmation.class); + subjectConfirmation.setMethod(SubjectConfirmation.METHOD_BEARER); + subjectConfirmation.setSubjectConfirmationData(subjectConfirmationData); + + subject.getSubjectConfirmations().add(subjectConfirmation); + + final Conditions conditions = Saml2Utils.createSamlObject(Conditions.class); + final AudienceRestriction audienceRestriction = + Saml2Utils.createSamlObject(AudienceRestriction.class); + final Audience audience = Saml2Utils.createSamlObject(Audience.class); + + audience.setAudienceURI(entityID); + audienceRestriction.getAudiences().add(audience); + conditions.setNotBefore(date); + conditions.setNotOnOrAfter(isValidTo); + + conditions.getAudienceRestrictions().add(audienceRestriction); + + assertion.setConditions(conditions); + + final Issuer issuerObj = Saml2Utils.createSamlObject(Issuer.class); + + if (issuer.endsWith("/")) { + issuer = issuer.substring(0, issuer.length() - 1); + } + issuerObj.setValue(issuer); + issuerObj.setFormat(NameIDType.ENTITY); + + assertion.setIssuer(issuerObj); + assertion.setSubject(subject); + assertion.setID(Saml2Utils.getSecureIdentifier()); + assertion.setIssueInstant(date); + + return assertion; + } +} -- cgit v1.2.3