/******************************************************************************* * Copyright 2017 Graz University of Technology * EAAF-Core Components has been developed in a cooperation between EGIZ, * A-SIT+, 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.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> attributs = new HashMap>(); //private PersonalAttributeList storkAttributes = new PersonalAttributeList(); private final List minimalMDSAttributeNamesList = Arrays.asList( PVPConstants.PRINCIPAL_NAME_NAME, PVPConstants.GIVEN_NAME_NAME, PVPConstants.BIRTHDATE_NAME, PVPConstants.BPK_NAME); private final List 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 *

* INFO: 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 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); internalInitialize(); } else throw new AssertionAttributeExtractorExeption(); } /** * Parse the SAML2 Assertion element and extracts included information *

* * @param assertion SAML2 Assertion * @throws AssertionAttributeExtractorExeption */ public AssertionAttributeExtractor(Assertion assertion) throws AssertionAttributeExtractorExeption { this.assertion = assertion; internalInitialize(); } /** * Get all SAML2 attributes from first SAML2 AttributeStatement element * * @return List of SAML2 Attributes */ public List 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 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 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 getAttributeValues(String attributeName) { return attributs.get(attributeName); } /** * Return all include PVP attribute names * * @return */ public Set 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"); } /** * Get the Id attribute from SAML2 assertion * * @return */ public String getAssertionID() { return assertion.getID(); } 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(); } /** * Get the Assertion validFrom period * * This method returns value of SAML 'Conditions' element. * * @return Date, after this SAML2 assertion is valid, otherwise null */ public Date getAssertionNotBefore() { try { return getFullAssertion().getConditions().getNotBefore().toDate(); } catch (NullPointerException e) { return null; } } private AuthnStatement getAuthnStatement() throws AssertionAttributeExtractorExeption { List 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); } private void internalInitialize() { 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 storkAttrValues = new ArrayList(); 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 attrList = new ArrayList(); for (XMLObject el : attr.getAttributeValues()) attrList.add(el.getDOM().getTextContent()); attributs.put(attr.getName(), attrList); } } } } }