diff options
Diffstat (limited to 'id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java')
-rw-r--r-- | id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java | 423 |
1 files changed, 396 insertions, 27 deletions
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java index 1e0089a53..33c150927 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataBuilder.java @@ -22,24 +22,64 @@ */ package at.gv.egovernment.moa.id.auth.builder; +import iaik.x509.X509Certificate; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import javax.naming.ldap.LdapName; +import javax.naming.ldap.Rdn; + +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.Response; +import org.opensaml.ws.soap.client.BasicSOAPMessageContext; +import org.opensaml.ws.soap.client.http.HttpClientBuilder; +import org.opensaml.ws.soap.client.http.HttpSOAPClient; +import org.opensaml.ws.soap.common.SOAPException; +import org.opensaml.ws.soap.soap11.Body; +import org.opensaml.ws.soap.soap11.Envelope; +import org.opensaml.xml.parse.BasicParserPool; +import org.opensaml.xml.security.SecurityException; import org.w3c.dom.Element; import org.w3c.dom.Node; +import eu.stork.peps.auth.commons.PersonalAttribute; +import eu.stork.peps.auth.commons.PersonalAttributeList; + import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; import at.gv.egovernment.moa.id.auth.data.IdentityLink; import at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse; import at.gv.egovernment.moa.id.auth.exception.BuildException; +import at.gv.egovernment.moa.id.auth.exception.DynamicOABuildException; +import at.gv.egovernment.moa.id.auth.exception.ParseException; import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser; +import at.gv.egovernment.moa.id.commons.db.MOASessionDBUtils; +import at.gv.egovernment.moa.id.commons.db.dao.session.InterfederationSessionStore; +import at.gv.egovernment.moa.id.commons.db.dao.session.OASessionStore; +import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; import at.gv.egovernment.moa.id.config.ConfigurationException; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; -import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.config.auth.IOAAuthParameters; import at.gv.egovernment.moa.id.data.AuthenticationData; import at.gv.egovernment.moa.id.data.IAuthData; import at.gv.egovernment.moa.id.moduls.IRequest; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPTargetConfiguration; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.AttributQueryBuilder; import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AssertionAttributeExtractorExeption; -import at.gv.egovernment.moa.id.protocols.pvp2x.utils.AssertionAttributeExtractor; +import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AssertionValidationExeption; +import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AttributQueryException; +import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOARequest; +import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; +import at.gv.egovernment.moa.id.protocols.pvp2x.verification.SAMLVerificationEngine; +import at.gv.egovernment.moa.id.protocols.pvp2x.verification.TrustEngineFactory; import at.gv.egovernment.moa.id.protocols.saml1.SAML1AuthenticationData; import at.gv.egovernment.moa.id.protocols.saml1.SAML1RequestImpl; import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; @@ -47,6 +87,7 @@ import at.gv.egovernment.moa.id.util.IdentityLinkReSigner; import at.gv.egovernment.moa.id.util.ParamValidatorUtils; import at.gv.egovernment.moa.id.util.client.mis.simple.MISMandate; import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Base64Utils; import at.gv.egovernment.moa.util.Constants; import at.gv.egovernment.moa.util.MiscUtil; import at.gv.egovernment.moa.util.XPathUtils; @@ -58,7 +99,7 @@ import at.gv.egovernment.moa.util.XPathUtils; public class AuthenticationDataBuilder implements MOAIDAuthConstants { public static IAuthData buildAuthenticationData(IRequest protocolRequest, - AuthenticationSession session) throws ConfigurationException, BuildException, WrongParametersException { + AuthenticationSession session, List<Attribute> reqAttributes) throws ConfigurationException, BuildException, WrongParametersException, DynamicOABuildException { String oaID = protocolRequest.getOAURL(); @@ -71,11 +112,9 @@ public class AuthenticationDataBuilder implements MOAIDAuthConstants { if (!ParamValidatorUtils.isValidOA(oaID)) throw new WrongParametersException("StartAuthentication", PARAM_OA, "auth.12"); - - OAAuthParameter oaParam = AuthConfigurationProvider.getInstance() - .getOnlineApplicationParameter(oaID); - AuthenticationData authdata = null; + AuthenticationData authdata = null; + if (protocolRequest instanceof SAML1RequestImpl) { //request is SAML1 SAML1AuthenticationData saml1authdata = new SAML1AuthenticationData(); @@ -88,11 +127,65 @@ public class AuthenticationDataBuilder implements MOAIDAuthConstants { } + //reuse some parameters if it is a reauthentication + OASessionStore activeOA = AuthenticationSessionStoreage.searchActiveOASSOSession(session, oaID, protocolRequest.requestedModule()); + if (activeOA != null) { + authdata.setSessionIndex(activeOA.getAssertionSessionID()); + authdata.setNameID(activeOA.getUserNameID()); + authdata.setNameIDFormat(activeOA.getUserNameIDFormat()); - if (protocolRequest.getInterfederationResponse() != null) { - //get attributes from interfederated IDP - buildAuthDataFromInterfederationResponse(authdata, session, oaParam, protocolRequest); + //mark AttributeQuery as used + if ( protocolRequest instanceof PVPTargetConfiguration && + ((PVPTargetConfiguration) protocolRequest).getRequest() instanceof MOARequest && + ((PVPTargetConfiguration) protocolRequest).getRequest().getInboundMessage() instanceof AttributeQuery) { + try { + activeOA.setAttributeQueryUsed(true); + MOASessionDBUtils.saveOrUpdate(activeOA); + + } catch (MOADatabaseException e) { + Logger.error("MOASession interfederation information can not stored to database.", e); + + } + } + } + + InterfederationSessionStore interfIDP = AuthenticationSessionStoreage.searchInterfederatedIDPFORAttributeQueryWithSessionID(session); + + IOAAuthParameters oaParam = null; + if (reqAttributes == null) { + //get OnlineApplication from MOA-ID-Auth configuration + oaParam = AuthConfigurationProvider.getInstance() + .getOnlineApplicationParameter(oaID); + + } else { + //build OnlineApplication dynamic from requested attributes + oaParam = DynamicOAAuthParameterBuilder.buildFromAttributeQuery(reqAttributes, interfIDP); + + } + + if (interfIDP != null ) { + //IDP is a chained interfederated IDP and Authentication is requested + if (oaParam.isInderfederationIDP() && protocolRequest instanceof PVPTargetConfiguration && + !(((PVPTargetConfiguration)protocolRequest).getRequest() instanceof AttributeQuery)) { + //only set minimal response attributes + authdata.setQAALevel(interfIDP.getQAALevel()); + authdata.setBPK(interfIDP.getUserNameID()); + + } else { + //mark attribute request as used + try { + interfIDP.setAttributesRequested(true); + MOASessionDBUtils.saveOrUpdate(interfIDP); + + } catch (MOADatabaseException e) { + Logger.error("MOASession interfederation information can not stored to database.", e); + + } + + //get attributes from interfederated IDP + getAuthDataFromInterfederation(authdata, session, oaParam, protocolRequest, interfIDP, reqAttributes); + } } else { //build AuthenticationData from MOASession @@ -104,41 +197,282 @@ public class AuthenticationDataBuilder implements MOAIDAuthConstants { } /** + * @param req + * @param session + * @param reqAttributes + * @return + * @throws WrongParametersException + * @throws ConfigurationException + * @throws BuildException + * @throws DynamicOABuildException + */ + public static IAuthData buildAuthenticationData(IRequest req, + AuthenticationSession session) throws WrongParametersException, ConfigurationException, BuildException, DynamicOABuildException { + return buildAuthenticationData(req, session, null); + } + + /** * @param authdata * @param session * @param oaParam + * @param protocolRequest + * @param interfIDP + * @param reqQueryAttr + * @throws ConfigurationException */ - private static void buildAuthDataFromInterfederationResponse( + private static void getAuthDataFromInterfederation( AuthenticationData authdata, AuthenticationSession session, - OAAuthParameter oaParam, IRequest req) { - - try { - AssertionAttributeExtractor extract = - new AssertionAttributeExtractor(req.getInterfederationResponse().getResponse()); + IOAAuthParameters oaParam, IRequest req, + InterfederationSessionStore interfIDP, List<Attribute> reqQueryAttr) throws BuildException, ConfigurationException{ - if (oaParam.isInderfederationIDP()) { - //only set minimal response attributes - authdata.setQAALevel(extract.getQAALevel()); - authdata.setBPK(extract.getNameID()); - + try { + List<Attribute> attributs = null; + + //IDP is a chained interfederated IDP and request is of type AttributQuery + if (oaParam.isInderfederationIDP() && req instanceof PVPTargetConfiguration && + (((PVPTargetConfiguration)req).getRequest() instanceof AttributeQuery) && + reqQueryAttr != null) { + attributs = reqQueryAttr; + + //IDP is a service provider IDP and request interfederated IDP to collect attributes } else { - //IDP response to service provider - // --> collect attributes by using BackChannel communication - - //TODO: get protocol specific requested attributes + //TODO: check if response include attributes and map this attributes to requested attributes + + //get PVP 2.1 attributes from protocol specific requested attributes + attributs = req.getRequestedAttributes(); + } + //collect attributes by using BackChannel communication + String endpoint = oaParam.getIDPAttributQueryServiceURL(); + if (MiscUtil.isEmpty(endpoint)) { + Logger.error("No AttributeQueryURL for interfederationIDP " + oaParam.getPublicURLPrefix()); + throw new ConfigurationException("No AttributeQueryURL for interfederationIDP " + oaParam.getPublicURLPrefix(), null); } + + //build attributQuery request + AttributeQuery query = + AttributQueryBuilder.buildAttributQueryRequest(interfIDP.getUserNameID(), endpoint, attributs); + + //build SOAP request + BasicParserPool parserPool = new BasicParserPool(); + parserPool.setNamespaceAware(true); + + Envelope soapRequest = SAML2Utils.buildSOAP11Envelope(query); + + BasicSOAPMessageContext soapContext = new BasicSOAPMessageContext(); + soapContext.setOutboundMessage(soapRequest); + HttpClientBuilder clientBuilder = new HttpClientBuilder(); + HttpSOAPClient soapClient = new HttpSOAPClient(clientBuilder.buildClient(), parserPool); + + //send request to IDP + soapClient.send(endpoint, soapContext); + + //parse response + Envelope soapResponse = (Envelope) soapContext.getInboundMessage(); + Body soapBody = soapResponse.getBody(); + + if (soapBody.getUnknownXMLObjects().size() == 0) { + Logger.error("Receive emptry AttributeQuery response-body."); + throw new AttributQueryException("Receive emptry AttributeQuery response-body.", null); + + } + + if (soapBody.getUnknownXMLObjects().get(0) instanceof Response) { + Response intfResp = (Response) soapBody.getUnknownXMLObjects().get(0); + + //validate PVP 2.1 response + try { + SAMLVerificationEngine engine = new SAMLVerificationEngine(); + engine.verifyResponse(intfResp, TrustEngineFactory.getSignatureKnownKeysTrustEngine()); + + SAMLVerificationEngine.validateAssertion(intfResp, false); + + } catch (Exception e) { + Logger.warn("PVP 2.1 assertion validation FAILED.", e); + throw new AssertionValidationExeption("PVP 2.1 assertion validation FAILED.", null, e); + } + + //parse response information to authData + buildAuthDataFormInterfederationResponse(authdata, session, intfResp); + + } else { + Logger.error("Receive AttributeQuery response-body include no PVP 2.1 response"); + throw new AttributQueryException("Receive AttributeQuery response-body include no PVP 2.1 response.", null); + + } + + } catch (SOAPException e) { + throw new BuildException("builder.06", null, e); + + } catch (SecurityException e) { + throw new BuildException("builder.06", null, e); + + } catch (AttributQueryException e) { + throw new BuildException("builder.06", null, e); + + } catch (BuildException e) { + throw new BuildException("builder.06", null, e); + + } catch (AssertionValidationExeption e) { + throw new BuildException("builder.06", null, e); + } catch (AssertionAttributeExtractorExeption e) { - Logger.error("Build authData from interfederated PVP2.1 assertion FAILED.", e); + throw new BuildException("builder.06", null, e); } } + private static void buildAuthDataFormInterfederationResponse(AuthenticationData authData, AuthenticationSession session, + Response intfResp) throws BuildException, AssertionAttributeExtractorExeption { + + Logger.debug("Build AuthData from assertion starts ...."); + + Assertion assertion = intfResp.getAssertions().get(0); + + if (assertion.getAttributeStatements().size() == 0) { + Logger.warn("Can not build AuthData from Assertion. NO Attributes included."); + throw new AssertionAttributeExtractorExeption("Can not build AuthData from Assertion. NO Attributes included.", null); + + } + + AttributeStatement attrStat = assertion.getAttributeStatements().get(0); + for (Attribute attr : attrStat.getAttributes()) { + + if (attr.getName().equals(PVPConstants.PRINCIPAL_NAME_NAME)) + authData.setFamilyName(attr.getAttributeValues().get(0).getDOM().getTextContent()); + + if (attr.getName().equals(PVPConstants.GIVEN_NAME_NAME)) + authData.setGivenName(attr.getAttributeValues().get(0).getDOM().getTextContent()); + + if (attr.getName().equals(PVPConstants.BIRTHDATE_NAME)) + authData.setDateOfBirth(attr.getAttributeValues().get(0).getDOM().getTextContent()); + + if (attr.getName().equals(PVPConstants.BPK_NAME)) { + String pvpbPK = attr.getAttributeValues().get(0).getDOM().getTextContent(); + authData.setBPK(pvpbPK.split(":")[1]); + } + + if (attr.getName().equals(PVPConstants.EID_SECTOR_FOR_IDENTIFIER_NAME)) + authData.setBPKType(attr.getAttributeValues().get(0).getDOM().getTextContent()); + + if (attr.getName().equals(PVPConstants.EID_CITIZEN_QAA_LEVEL_NAME)) + authData.setQAALevel(PVPConstants.STORK_QAA_PREFIX + + attr.getAttributeValues().get(0).getDOM().getTextContent()); + + if (attr.getName().equals(PVPConstants.EID_ISSUING_NATION_NAME)) + authData.setCcc(attr.getAttributeValues().get(0).getDOM().getTextContent()); + + if (attr.getName().equals(PVPConstants.EID_CCS_URL_NAME)) + authData.setBkuURL(attr.getAttributeValues().get(0).getDOM().getTextContent()); + + if (attr.getName().equals(PVPConstants.EID_AUTH_BLOCK_NAME)) { + try { + byte[] authBlock = Base64Utils.decode(attr.getAttributeValues().get(0).getDOM().getTextContent(), false); + authData.setAuthBlock(new String(authBlock, "UTF-8")); + + } catch (IOException e) { + Logger.error("Received AuthBlock is not valid", e); + + } + } + + if (attr.getName().equals(PVPConstants.EID_SIGNER_CERTIFICATE_NAME)) { + try { + authData.setSignerCertificate(Base64Utils.decode( + attr.getAttributeValues().get(0).getDOM().getTextContent(), false)); + + } catch (IOException e) { + Logger.error("Received SignerCertificate is not valid", e); + + } + } + + if (attr.getName().equals(PVPConstants.EID_SOURCE_PIN_NAME)) + authData.setIdentificationValue(attr.getAttributeValues().get(0).getDOM().getTextContent()); + + if (attr.getName().equals(PVPConstants.EID_SOURCE_PIN_TYPE_NAME)) + authData.setIdentificationType(attr.getAttributeValues().get(0).getDOM().getTextContent()); + + if (attr.getName().equals(PVPConstants.EID_IDENTITY_LINK_NAME)) { + try { + InputStream idlStream = Base64Utils.decodeToStream(attr.getAttributeValues().get(0).getDOM().getTextContent(), false); + IdentityLink idl = new IdentityLinkAssertionParser(idlStream).parseIdentityLink(); + authData.setIdentityLink(idl); + + } catch (ParseException e) { + Logger.error("Received IdentityLink is not valid", e); + + } catch (Exception e) { + Logger.error("Received IdentityLink is not valid", e); + + } + } + + if (attr.getName().equals(PVPConstants.MANDATE_REFERENCE_VALUE_NAME)) + authData.setMandateReferenceValue(attr.getAttributeValues().get(0).getDOM().getTextContent()); + + + if (attr.getName().equals(PVPConstants.MANDATE_FULL_MANDATE_NAME)) { + try { + byte[] mandate = Base64Utils.decode( + attr.getAttributeValues().get(0).getDOM().getTextContent(), false); + + if (authData.getMISMandate() == null) + authData.setMISMandate(new MISMandate()); + authData.getMISMandate().setMandate(mandate); + + authData.setUseMandate(true); + + } catch (Exception e) { + Logger.error("Received Mandate is not valid", e); + throw new AssertionAttributeExtractorExeption(PVPConstants.MANDATE_FULL_MANDATE_NAME); + + } + } + + if (attr.getName().equals(PVPConstants.MANDATE_PROF_REP_OID_NAME)) { + if (authData.getMISMandate() == null) + authData.setMISMandate(new MISMandate()); + authData.getMISMandate().setProfRep( + attr.getAttributeValues().get(0).getDOM().getTextContent()); + + } + + if (attr.getName().equals(PVPConstants.EID_STORK_TOKEN_NAME)) { + authData.setStorkAuthnResponse(attr.getAttributeValues().get(0).getDOM().getTextContent()); + authData.setForeigner(true); + } + + if (attr.getName().startsWith(PVPConstants.STORK_ATTRIBUTE_PREFIX)) { + + if (authData.getStorkAttributes() == null) + authData.setStorkAttributes(new PersonalAttributeList()); + + List<String> storkAttrValues = new ArrayList<String>(); + storkAttrValues.add(attr.getAttributeValues().get(0).getDOM().getTextContent()); + PersonalAttribute storkAttr = new PersonalAttribute(attr.getName(), + false, storkAttrValues , "Available"); + authData.getStorkAttributes().put(attr.getName(), storkAttr ); + authData.setForeigner(true); + } + + } + + authData.setSsoSession(true); + + //only for SAML1 + if (PVPConstants.STORK_QAA_1_4.equals(authData.getQAALevel())) + authData.setQualifiedCertificate(true); + else + authData.setQualifiedCertificate(false); + authData.setPublicAuthority(false); + } + private static void buildAuthDataFormMOASession(AuthenticationData authData, AuthenticationSession session, - OAAuthParameter oaParam) throws BuildException { + IOAAuthParameters oaParam) throws BuildException { String target = oaParam.getTarget(); @@ -173,7 +507,42 @@ public class AuthenticationDataBuilder implements MOAIDAuthConstants { authData.setForeigner(session.isForeigner()); authData.setQAALevel(session.getQAALevel()); + + if (session.isForeigner()) { + if (authData.getStorkAuthnRequest() != null) { + authData.setCcc(authData.getStorkAuthnRequest() + .getCitizenCountryCode()); + } else { + + try { + //TODO: replace with TSL lookup when TSL is ready! + X509Certificate certificate = new X509Certificate(authData.getSignerCertificate()); + + if (certificate != null) { + + LdapName ln = new LdapName(certificate.getIssuerDN() + .getName()); + for (Rdn rdn : ln.getRdns()) { + if (rdn.getType().equalsIgnoreCase("C")) { + Logger.info("C is: " + rdn.getValue()); + authData.setCcc(rdn.getValue().toString()); + break; + } + } + } + + } catch (Exception e) { + Logger.error("Failed to extract country code from certificate", e); + + } + } + + } else { + authData.setCcc("AT"); + + } + try { authData.setSsoSession(AuthenticationSessionStoreage.isSSOSession(session.getSessionID())); |