diff options
| author | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2018-06-26 11:03:48 +0200 | 
|---|---|---|
| committer | Thomas Lenz <thomas.lenz@egiz.gv.at> | 2018-06-26 11:03:48 +0200 | 
| commit | bee5dd259a4438d45ecd1bcc26dfba12875236d6 (patch) | |
| tree | fe1cf7a35cd15dee5fb3c05de0341aa63bf743e0 /eaaf_modules/eaaf_module_pvp2_sp/src | |
| download | EAAF-Components-bee5dd259a4438d45ecd1bcc26dfba12875236d6.tar.gz EAAF-Components-bee5dd259a4438d45ecd1bcc26dfba12875236d6.tar.bz2 EAAF-Components-bee5dd259a4438d45ecd1bcc26dfba12875236d6.zip | |
initial commit
Diffstat (limited to 'eaaf_modules/eaaf_module_pvp2_sp/src')
8 files changed, 745 insertions, 0 deletions
| diff --git a/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/META-INF/MANIFEST.MF b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/META-INF/MANIFEST.MF new file mode 100644 index 00000000..254272e1 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path:  + diff --git a/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/api/IPVPAuthnRequestBuilderConfiguruation.java b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/api/IPVPAuthnRequestBuilderConfiguruation.java new file mode 100644 index 00000000..b0439775 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/api/IPVPAuthnRequestBuilderConfiguruation.java @@ -0,0 +1,142 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.sp.api; + +import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.xml.security.credential.Credential; +import org.w3c.dom.Element; + +/** + * @author tlenz + * + */ +public interface IPVPAuthnRequestBuilderConfiguruation { + +	/** +	 * Defines a unique name for this PVP Service-provider, which is used for logging +	 *  +	 * @return +	 */ +	public String getSPNameForLogging(); +	 +	/** +	 * If true, the SAML2 isPassive flag is set in the AuthnRequest +	 *  +	 * @return +	 */ +	public Boolean isPassivRequest(); + +	/** +	 * Define the ID of the AssertionConsumerService,  +	 * which defines the required attributes in service-provider metadata. +	 *  +	 * @return +	 */ +	public Integer getAssertionConsumerServiceId(); + +	/** +	 * Define the SAML2 EntityID of the service provider. +	 *  +	 * @return +	 */ +	public String getSPEntityID(); + +	/** +	 * Define the SAML2 NameIDPolicy +	 *  +	 * @return Service-Provider EntityID, but never null +	 */ +	public String getNameIDPolicyFormat(); + +	/** +	 * Define the AuthnContextClassRefernece of this request +	 *  +	 * Example:  +	 * 			http://www.ref.gv.at/ns/names/agiz/pvp/secclass/0-3  +	 * 			http://www.stork.gov.eu/1.0/citizenQAALevel/4 +	 *           +	 *  +	 * @return +	 */ +	public String getAuthnContextClassRef(); + +	/** +	 * Define the AuthnContextComparison model, which should be used +	 *  +	 * @return +	 */ +	public AuthnContextComparisonTypeEnumeration getAuthnContextComparison(); +	 +	 +	/** +	 * Define the credential, which should be used to sign the AuthnRequest +	 *  +	 * @return +	 */ +	public Credential getAuthnRequestSigningCredential(); +	 +	 +	/** +	 * Define the SAML2 EntityDescriptor of the IDP, which should receive the AuthnRequest +	 *  +	 * @return Credential, but never null. +	 */ +	public EntityDescriptor getIDPEntityDescriptor(); + +	/** +	 * Set the SAML2 NameIDPolicy allow-creation flag +	 *  +	 * @return EntityDescriptor, but never null. +	 */ +	public boolean getNameIDPolicyAllowCreation(); + +	 +	/** +	 * Set the requested SubjectNameID +	 *  +	 * @return SubjectNameID, or null if no SubjectNameID should be used +	 */ +	public String getSubjectNameID(); + +	/** +	 * Define the qualifier of the <code>SubjectNameID</code> +	 * <br><br> +	 * Like: 'urn:publicid:gv.at:cdid+BF' +	 *  +	 * @return qualifier, or null if no qualifier should be set +	 */ +	public String getSubjectNameIDQualifier(); +	 +	/** +	 * Define the format of the subjectNameID, which is included in authn-request +	 *  +	 *  +	 * @return nameIDFormat, of SAML2 'transient' if nothing is defined +	 */ +	public String getSubjectNameIDFormat(); + +	/** +	 * Define a SP specific SAML2 requestID +	 *  +	 * @return requestID, or null if the requestID should be generated automatically +	 */ +	public String getRequestID(); + +	/** +	 * Defines the 'method' attribute in 'SubjectConformation' element  +	 *  +	 * @return method, or null if no method should set +	 */ +	public String getSubjectConformationMethode(); + +	/** +	 * Define the information, which should be added as 'subjectConformationDate'  +	 * in 'SubjectConformation' element  +	 *  +	 * @return subjectConformation information or null if no subjectConformation should be set +	 */ +	public Element getSubjectConformationDate(); + +	 +} diff --git a/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/exception/AssertionAttributeExtractorExeption.java b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/exception/AssertionAttributeExtractorExeption.java new file mode 100644 index 00000000..dccb0b22 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/exception/AssertionAttributeExtractorExeption.java @@ -0,0 +1,32 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.sp.exception; + +import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; + +/** + * @author tlenz + * + */ +public class AssertionAttributeExtractorExeption extends PVP2Exception { + +	/** +	 *  +	 */ +	private static final long serialVersionUID = -6459000942830951492L; + +	public AssertionAttributeExtractorExeption(String attributeName) { +		super("Parse PVP2.1 assertion FAILED: Attribute " + attributeName  +				+ " can not extract.", null); +	} +	 +	public AssertionAttributeExtractorExeption(String messageId, +			Object[] parameters) { +		super(messageId, parameters); +	} + +	public AssertionAttributeExtractorExeption() { +		super("Parse PVP2.1 assertion FAILED. Interfederation not possible", null);  +	} + +} diff --git a/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/exception/AssertionValidationExeption.java b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/exception/AssertionValidationExeption.java new file mode 100644 index 00000000..aec71501 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/exception/AssertionValidationExeption.java @@ -0,0 +1,29 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.sp.exception; + +import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; + +/** + * @author tlenz + * + */ +public class AssertionValidationExeption extends PVP2Exception { + +	private static final long serialVersionUID = -3987805399122286259L; + +	public AssertionValidationExeption(String messageId, Object[] parameters) { +		super(messageId, parameters); +	} + +	/** +	 * @param string +	 * @param object +	 * @param e +	 */ +	public AssertionValidationExeption(String string, Object[] parameters, +			Throwable e) { +		super(string, parameters, e); +	} + +} diff --git a/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/exception/AuthnRequestBuildException.java b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/exception/AuthnRequestBuildException.java new file mode 100644 index 00000000..bdb158b6 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/exception/AuthnRequestBuildException.java @@ -0,0 +1,29 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.sp.exception; + +import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; + +/** + * @author tlenz + * + */ +public class AuthnRequestBuildException extends PVP2Exception { + +	/** +	 *  +	 */ +	private static final long serialVersionUID = -1375451065455859354L; + +	/** +	 * @param messageId +	 * @param parameters +	 */ +	public AuthnRequestBuildException(String messageId, Object[] parameters) { +		super(messageId, parameters); +	} + +	public AuthnRequestBuildException(String messageId, Object[] parameters, Throwable e) { +		super(messageId, parameters, e); +	} +} diff --git a/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/exception/AuthnResponseValidationException.java b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/exception/AuthnResponseValidationException.java new file mode 100644 index 00000000..6f11f1c2 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/exception/AuthnResponseValidationException.java @@ -0,0 +1,30 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.sp.exception; + +import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; + +/** + * @author tlenz + * + */ +public class AuthnResponseValidationException extends PVP2Exception { + +	/** +	 *  +	 */ +	private static final long serialVersionUID = 8023812861029406575L; + +	/** +	 * @param messageId +	 * @param parameters +	 */ +	public AuthnResponseValidationException(String messageId, Object[] parameters) { +		super(messageId, parameters); +	} +	 +	public AuthnResponseValidationException(String messageId, Object[] parameters, Throwable e) { +		super(messageId, parameters, e); +	} + +} diff --git a/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/impl/PVPAuthnRequestBuilder.java b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/impl/PVPAuthnRequestBuilder.java new file mode 100644 index 00000000..9b02dc77 --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/impl/PVPAuthnRequestBuilder.java @@ -0,0 +1,205 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.sp.impl; + +import java.security.NoSuchAlgorithmException; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.StringUtils; +import org.joda.time.DateTime; +import org.opensaml.common.impl.SecureRandomIdentifierGenerator; +import org.opensaml.common.xml.SAMLConstants; +import org.opensaml.saml2.core.AuthnContextClassRef; +import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration; +import org.opensaml.saml2.core.AuthnRequest; +import org.opensaml.saml2.core.Issuer; +import org.opensaml.saml2.core.NameID; +import org.opensaml.saml2.core.NameIDPolicy; +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.EntityDescriptor; +import org.opensaml.saml2.metadata.SingleSignOnService; +import org.opensaml.ws.message.encoder.MessageEncodingException; +import org.opensaml.xml.security.SecurityException; +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.modules.pvp2.api.binding.IEncoder; +import at.gv.egiz.eaaf.modules.pvp2.exception.PVP2Exception; +import at.gv.egiz.eaaf.modules.pvp2.impl.binding.PostBinding; +import at.gv.egiz.eaaf.modules.pvp2.impl.binding.RedirectBinding; +import at.gv.egiz.eaaf.modules.pvp2.impl.utils.SAML2Utils; +import at.gv.egiz.eaaf.modules.pvp2.sp.api.IPVPAuthnRequestBuilderConfiguruation; +import at.gv.egiz.eaaf.modules.pvp2.sp.exception.AuthnRequestBuildException; + +/** + * @author tlenz + * + */ +@Service("PVPAuthnRequestBuilder") +public class PVPAuthnRequestBuilder { +	private static final Logger log = LoggerFactory.getLogger(PVPAuthnRequestBuilder.class); +	 +	 +	@Autowired(required=true) ApplicationContext springContext; +	 +	 +	/** +	 * Build a PVP2.x specific authentication request +	 *  +	 * @param pendingReq Currently processed pendingRequest  +	 * @param config AuthnRequest builder configuration, never null +	 * @param idpEntity SAML2 EntityDescriptor of the IDP, which receive this AuthnRequest, never null +	 * @param httpResp +	 * @throws NoSuchAlgorithmException  +	 * @throws SecurityException  +	 * @throws PVP2Exception  +	 * @throws MessageEncodingException  +	 */  +	public void buildAuthnRequest(IRequest pendingReq, IPVPAuthnRequestBuilderConfiguruation config,  +			HttpServletResponse httpResp) throws NoSuchAlgorithmException, MessageEncodingException, PVP2Exception, SecurityException { +		//get IDP Entity element from config +		EntityDescriptor idpEntity = config.getIDPEntityDescriptor(); +		 +		AuthnRequest authReq = SAML2Utils +				.createSAMLObject(AuthnRequest.class); +		 +		//select SingleSignOn Service endpoint from IDP metadata +		SingleSignOnService endpoint = null;   +		for (SingleSignOnService sss :  +				idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleSignOnServices()) { +			 +			// use POST binding as default if it exists  +			if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) {  +				endpoint = sss;  +				 +			} else if ( sss.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI)  +					&& endpoint == null ) +				endpoint = sss; +			 +		} +		 +		if (endpoint == null) { +			log.warn("Building AuthnRequest FAILED: > Requested IDP " + idpEntity.getEntityID()  +					+ " does not support POST or Redirect Binding."); +			throw new AuthnRequestBuildException("sp.pvp2.00", new Object[]{config.getSPNameForLogging(), idpEntity.getEntityID()}); +			 +		} else +			authReq.setDestination(endpoint.getLocation()); +		 +		 +		//set basic AuthnRequest information +		String reqID = config.getRequestID(); +		if (StringUtils.isNotEmpty(reqID)) +			authReq.setID(reqID); +		 +		else { +			SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator(); +			authReq.setID(gen.generateIdentifier()); +			 +		} +		 +		authReq.setIssueInstant(new DateTime()); +		 +		//set isPassive flag +		if (config.isPassivRequest() == null) +			authReq.setIsPassive(false); +		else +			authReq.setIsPassive(config.isPassivRequest()); + +		//set EntityID of the service provider +		Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); +		issuer.setFormat(NameIDType.ENTITY); +		issuer.setValue(config.getSPEntityID()); +		authReq.setIssuer(issuer); + +		//set AssertionConsumerService ID +		if (config.getAssertionConsumerServiceId() != null) +			authReq.setAssertionConsumerServiceIndex(config.getAssertionConsumerServiceId()); +		 +		//set NameIDPolicy +		if (config.getNameIDPolicyFormat() != null) { +			NameIDPolicy policy = SAML2Utils.createSAMLObject(NameIDPolicy.class); +			policy.setAllowCreate(config.getNameIDPolicyAllowCreation()); +			policy.setFormat(config.getNameIDPolicyFormat()); +			authReq.setNameIDPolicy(policy); +		} +		 +		//set requested QAA level +		if (config.getAuthnContextClassRef() != null) { +			RequestedAuthnContext reqAuthContext = SAML2Utils.createSAMLObject(RequestedAuthnContext.class);		 +			AuthnContextClassRef authnClassRef = SAML2Utils.createSAMLObject(AuthnContextClassRef.class); +		 +			authnClassRef.setAuthnContextClassRef(config.getAuthnContextClassRef()); +			 +			if (config.getAuthnContextComparison() == null) +				reqAuthContext.setComparison(AuthnContextComparisonTypeEnumeration.MINIMUM); +			else +				reqAuthContext.setComparison(config.getAuthnContextComparison()); +			 +			reqAuthContext.getAuthnContextClassRefs().add(authnClassRef);					 +			authReq.setRequestedAuthnContext(reqAuthContext); +		} +						 +		//set request Subject element +		if (StringUtils.isNotEmpty(config.getSubjectNameID())) { +			Subject reqSubject = SAML2Utils.createSAMLObject(Subject.class); +			NameID subjectNameID = SAML2Utils.createSAMLObject(NameID.class); +			 +			subjectNameID.setValue(config.getSubjectNameID()); +			if (StringUtils.isNotEmpty(config.getSubjectNameIDQualifier())) +				subjectNameID.setNameQualifier(config.getSubjectNameIDQualifier()); +			 +			if (StringUtils.isNotEmpty(config.getSubjectNameIDFormat())) +				subjectNameID.setFormat(config.getSubjectNameIDFormat()); +			else +				subjectNameID.setFormat(NameID.TRANSIENT); +			 +			reqSubject.setNameID(subjectNameID); +						 +			if (config.getSubjectConformationDate() != null) { +				SubjectConfirmation subjectConformation = SAML2Utils.createSAMLObject(SubjectConfirmation.class); +				SubjectConfirmationData subjectConformDate = SAML2Utils.createSAMLObject(SubjectConfirmationData.class);			 +				subjectConformation.setSubjectConfirmationData(subjectConformDate); +				reqSubject.getSubjectConfirmations().add(subjectConformation ); +							 +				if (config.getSubjectConformationMethode() != null) +					subjectConformation.setMethod(config.getSubjectConformationMethode()); +								 +				subjectConformDate.setDOM(config.getSubjectConformationDate()); +								 +			} +						 +			authReq.setSubject(reqSubject ); +						 +		} +		 +		//TODO: implement requested attributes +		//maybe: config.getRequestedAttributes(); +		 +		//select message encoder +		IEncoder binding = null; +		if (endpoint.getBinding().equals( +				SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { +			binding = springContext.getBean("PVPRedirectBinding", RedirectBinding.class); +														  +		} else if (endpoint.getBinding().equals( +				SAMLConstants.SAML2_POST_BINDING_URI)) { +			binding = springContext.getBean("PVPPOSTBinding", PostBinding.class); +			 +		} +		 +		//encode message +		binding.encodeRequest(null, httpResp, authReq,  +				endpoint.getLocation(), pendingReq.getPendingRequestId(), config.getAuthnRequestSigningCredential(), pendingReq); +	} + +} diff --git a/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/impl/utils/AssertionAttributeExtractor.java b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/impl/utils/AssertionAttributeExtractor.java new file mode 100644 index 00000000..1674e3fd --- /dev/null +++ b/eaaf_modules/eaaf_module_pvp2_sp/src/main/java/at/gv/egiz/eaaf/modules/pvp2/sp/impl/utils/AssertionAttributeExtractor.java @@ -0,0 +1,275 @@ +/******************************************************************************* + *******************************************************************************/ +package at.gv.egiz.eaaf.modules.pvp2.sp.impl.utils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.opensaml.saml2.core.Assertion; +import org.opensaml.saml2.core.Attribute; +import org.opensaml.saml2.core.AttributeStatement; +import org.opensaml.saml2.core.AuthnContextClassRef; +import org.opensaml.saml2.core.AuthnStatement; +import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.core.StatusResponseType; +import org.opensaml.saml2.core.Subject; +import org.opensaml.xml.XMLObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import at.gv.egiz.eaaf.modules.pvp2.PVPConstants; +import at.gv.egiz.eaaf.modules.pvp2.sp.exception.AssertionAttributeExtractorExeption; + +public class AssertionAttributeExtractor { +	 +	private static final Logger log = LoggerFactory.getLogger(AssertionAttributeExtractor.class); +	 +	private Assertion assertion = null; +	private Map<String, List<String>> attributs = new HashMap<String, List<String>>(); +	//private PersonalAttributeList storkAttributes = new PersonalAttributeList(); +		 +	private final List<String> minimalMDSAttributeNamesList = Arrays.asList( +			PVPConstants.PRINCIPAL_NAME_NAME,  +			PVPConstants.GIVEN_NAME_NAME, +			PVPConstants.BIRTHDATE_NAME, +			PVPConstants.BPK_NAME); + +	private final List<String> minimalIDLAttributeNamesList = Arrays.asList( +			PVPConstants.EID_IDENTITY_LINK_NAME,			 +			PVPConstants.EID_SOURCE_PIN_NAME, +			PVPConstants.EID_SOURCE_PIN_TYPE_NAME); +	 +	/** +	 * Parse the SAML2 Response element and extracts included information +	 * <br><br> +	 * <b>INFO:</b> Actually, only the first SAML2 Assertion of the SAML2 Response is used! +	 *  +	 * @param samlResponse SAML2 Response +	 * @throws AssertionAttributeExtractorExeption +	 */ +	public AssertionAttributeExtractor(StatusResponseType samlResponse) throws AssertionAttributeExtractorExeption { +		if (samlResponse != null && samlResponse instanceof Response) { +			List<Assertion> assertions = ((Response) samlResponse).getAssertions();			 +			if (assertions.size() == 0)  +				throw new AssertionAttributeExtractorExeption("Assertion"); +				 +			else if (assertions.size() > 1) +				log.warn("Found more then ONE PVP2.1 assertions. Only the First is used."); +			 +			assertion = assertions.get(0); + +			if (assertion.getAttributeStatements() != null && +					assertion.getAttributeStatements().size() > 0) { +				AttributeStatement attrStat = assertion.getAttributeStatements().get(0); +				for (Attribute attr : attrStat.getAttributes()) { +					if (attr.getName().startsWith(PVPConstants.STORK_ATTRIBUTE_PREFIX)) {							 +						List<String> storkAttrValues = new ArrayList<String>(); +						for (XMLObject el : attr.getAttributeValues()) +							storkAttrValues.add(el.getDOM().getTextContent()); +						 +//						PersonalAttribute storkAttr = new PersonalAttribute(attr.getName(),  +//								false, storkAttrValues , "Available"); +//						storkAttributes.put(attr.getName(), storkAttr ); +						 +					} else { +						List<String> attrList = new ArrayList<String>(); +						for (XMLObject el : attr.getAttributeValues()) +							attrList.add(el.getDOM().getTextContent()); + +						attributs.put(attr.getName(), attrList); +												 +					} +			} +				 +			} +						 +		} else  +			throw new AssertionAttributeExtractorExeption();		 +	} + +	/** +	 * Get all SAML2 attributes from first SAML2 AttributeStatement element +	 *  +	 * @return List of SAML2 Attributes +	 */ +	public List<Attribute> getAllResponseAttributesFromFirstAttributeStatement() { +		return assertion.getAttributeStatements().get(0).getAttributes(); +		 +	} +	 +	/** +	 * Get all SAML2 attributes of specific SAML2 AttributeStatement element +	 *  +	 * @param attrStatementID List ID of the AttributeStatement element +	 * @return List of SAML2 Attributes +	 */ +	public List<Attribute> getAllResponseAttributes(int attrStatementID) { +		return assertion.getAttributeStatements().get(attrStatementID).getAttributes(); +		 +	} +	 +	/** +	 * check attributes from assertion with minimal required attribute list +	 * @return +	 */ +	public boolean containsAllRequiredAttributes() { +		return containsAllRequiredAttributes(minimalMDSAttributeNamesList)  +				|| containsAllRequiredAttributes(minimalIDLAttributeNamesList); +		 +	} +	 +	/** +	 * check attributes from assertion with attributeNameList +	 * bPK or enc_bPK are always needed +	 *  +	 * @param List of attributes which are required +	 *  +	 * @return +	 */ +	public boolean containsAllRequiredAttributes(Collection<String> attributeNameList) {		 +		 +		//first check if a bPK or an encrypted bPK is available +		boolean flag = true; +		for (String attr : attributeNameList) { +			if (!attributs.containsKey(attr)) { +				flag = false;					 +				log.debug("Assertion contains no Attribute " + attr); +									 +			} +					 +		} +		 +		if (flag) +			return flag; +		 +		else {			 +			log.debug("Assertion contains no all minimum attributes from: " + attributeNameList.toString()); +			return false; +			 +		}		 +	} +	 +	public boolean containsAttribute(String attributeName) { +		return attributs.containsKey(attributeName); +		 +	} +	 +	public String getSingleAttributeValue(String attributeName) { +		if (attributs.containsKey(attributeName) && attributs.get(attributeName).size() > 0) +			return attributs.get(attributeName).get(0); +		else +			return null; +		 +	} +	 +	public List<String> getAttributeValues(String attributeName) { +		return attributs.get(attributeName); +		 +	} +	 +	/** +	 * Return all include PVP attribute names +	 *  +	 * @return +	 */ +	public Set<String> getAllIncludeAttributeNames() { +		return attributs.keySet(); +		 +	} +	 +//	public PersonalAttributeList getSTORKAttributes() { +//		return storkAttributes; +//	} +	 +	 +	public String getNameID() throws AssertionAttributeExtractorExeption {		 +		if (assertion.getSubject() != null) { +			Subject subject = assertion.getSubject(); +			 +			if (subject.getNameID() != null) { +				if (StringUtils.isNotEmpty(subject.getNameID().getValue()))					 +					return subject.getNameID().getValue();			 +				 +				else +					log.error("SAML2 NameID Element is empty."); +			} +		} +			 +		throw new AssertionAttributeExtractorExeption("nameID"); +	} +	 +	public String getSessionIndex() throws AssertionAttributeExtractorExeption {		 +		AuthnStatement authn = getAuthnStatement(); +		 +		if (StringUtils.isNotEmpty(authn.getSessionIndex())) +			return authn.getSessionIndex(); +		 +		else +			throw new AssertionAttributeExtractorExeption("SessionIndex");		 +	} + +	/** +	 * @return +	 * @throws AssertionAttributeExtractorExeption  +	 */ +	public String getQAALevel() throws AssertionAttributeExtractorExeption { +		AuthnStatement authn = getAuthnStatement(); +		if (authn.getAuthnContext() != null && authn.getAuthnContext().getAuthnContextClassRef() != null) { +			AuthnContextClassRef qaaClass = authn.getAuthnContext().getAuthnContextClassRef(); +			 +			if (StringUtils.isNotEmpty(qaaClass.getAuthnContextClassRef())) +				return qaaClass.getAuthnContextClassRef(); +			 +			else +				throw new AssertionAttributeExtractorExeption("AuthnContextClassRef (QAALevel)");			 +		} +		 +		throw new AssertionAttributeExtractorExeption("AuthnContextClassRef");		 +	} +	 +	public Assertion getFullAssertion() { +		return assertion; +	} +	 +	 +	/** +	 * Get the Assertion validTo period +	 *  +	 * Primarily, the 'SessionNotOnOrAfter' attribute in the SAML2 'AuthnStatment' element is used. +	 * If this is empty, this method returns value of  SAML 'Conditions' element.  +	 *  +	 * @return Date, until this SAML2 assertion is valid +	 */ +	public Date getAssertionNotOnOrAfter() { +		if (getFullAssertion().getAuthnStatements() != null  +				&& getFullAssertion().getAuthnStatements().size() > 0) { +			for (AuthnStatement el : getFullAssertion().getAuthnStatements()) { +				if (el.getSessionNotOnOrAfter() != null) +					return (el.getSessionNotOnOrAfter().toDate()); +			} +			 +		}  +		 +		return getFullAssertion().getConditions().getNotOnOrAfter().toDate(); +					 +	} +	 +	private AuthnStatement getAuthnStatement() throws AssertionAttributeExtractorExeption { +		List<AuthnStatement> authnList = assertion.getAuthnStatements(); +		if (authnList.size() == 0) +			throw new AssertionAttributeExtractorExeption("AuthnStatement"); +		 +		else if (authnList.size() > 1) +			log.warn("Found more then ONE AuthnStatements in PVP2.1 assertions. Only the First is used."); +		 +		return authnList.get(0); +	} + +} | 
