diff options
Diffstat (limited to 'id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1AuthenticationServer.java')
-rw-r--r-- | id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1AuthenticationServer.java | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1AuthenticationServer.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1AuthenticationServer.java new file mode 100644 index 000000000..fec2d2b35 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1AuthenticationServer.java @@ -0,0 +1,522 @@ +package at.gv.egovernment.moa.id.protocols.saml1; + +import java.io.IOException; +import java.util.Date; +import java.util.List; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerException; + +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import at.gv.egovernment.moa.id.AuthenticationException; +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.ServiceException; +import at.gv.egovernment.moa.id.auth.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.builder.AuthenticationDataAssertionBuilder; +import at.gv.egovernment.moa.id.auth.builder.BPKBuilder; +import at.gv.egovernment.moa.id.auth.builder.PersonDataBuilder; +import at.gv.egovernment.moa.id.auth.builder.SAMLArtifactBuilder; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +import at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute; +import at.gv.egovernment.moa.id.auth.data.IdentityLink; +import at.gv.egovernment.moa.id.auth.parser.SAMLArtifactParser; +import at.gv.egovernment.moa.id.auth.validator.ValidateException; +import at.gv.egovernment.moa.id.auth.validator.parep.ParepUtils; +import at.gv.egovernment.moa.id.commons.db.dao.config.OASAML1; +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.OAAuthParameter; +import at.gv.egovernment.moa.id.data.AuthenticationData; +import at.gv.egovernment.moa.id.moduls.IRequest; +import at.gv.egovernment.moa.id.storage.AssertionStorage; +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.DOMUtils; +import at.gv.egovernment.moa.util.StringUtils; + +public class SAML1AuthenticationServer extends AuthenticationServer { + + private static SAML1AuthenticationServer instance; + + public static SAML1AuthenticationServer getInstace() { + if (instance == null) + instance = new SAML1AuthenticationServer(); + + return instance; + } + + //private static Map authenticationDataStore = new HashMap(); + private static AssertionStorage authenticationDataStore = AssertionStorage.getInstance(); + + + //TODO: make this time configurable + /** + * time out in milliseconds used by {@link cleanup} for authentication data + * store + */ + private static final long authDataTimeOut = 2 * 60 * 1000; // default 2 minutes + + + public Throwable getErrorResponse(String samlArtifact) throws AuthenticationException { + try { + new SAMLArtifactParser(samlArtifact).parseAssertionHandle(); + + } catch (ParseException ex) { + throw new AuthenticationException("1205", new Object[] { + samlArtifact, ex.toString() }); + } + Throwable error = null; + synchronized (authenticationDataStore) { + try { + error = authenticationDataStore + .get(samlArtifact, Throwable.class); + + authenticationDataStore.remove(samlArtifact); + + } catch (MOADatabaseException e) { + Logger.error("Assertion not found for SAML Artifact: " + samlArtifact); + throw new AuthenticationException("1206", new Object[] { samlArtifact }); + } + + } + + return error; + } + + /** + * Retrieves <code>AuthenticationData</code> indexed by the SAML artifact. + * The <code>AuthenticationData</code> is deleted from the store upon end of + * this call. + * + * @return <code>AuthenticationData</code> + */ + public AuthenticationData getSaml1AuthenticationData(String samlArtifact) + throws AuthenticationException { + try { + new SAMLArtifactParser(samlArtifact).parseAssertionHandle(); + + } catch (ParseException ex) { + throw new AuthenticationException("1205", new Object[] { + samlArtifact, ex.toString() }); + } + AuthenticationData authData = null; + synchronized (authenticationDataStore) { + // System.out.println("assertionHandle: " + assertionHandle); + + try { + authData = authenticationDataStore + .get(samlArtifact, AuthenticationData.class); + + } catch (MOADatabaseException e) { + Logger.error("Assertion not found for SAML Artifact: " + samlArtifact); + throw new AuthenticationException("1206", new Object[] { samlArtifact }); + } + } + + boolean keepAssertion = false; + + //removed from MOA-ID 2.0 config +// try { +// String boolStr = AuthConfigurationProvider.getInstance() +// .getGenericConfigurationParameter( +// "AuthenticationServer.KeepAssertion"); +// if (null != boolStr && boolStr.equalsIgnoreCase("true")) +// keepAssertion = true;// Only allowed for debug purposes!!! +// +// } catch (ConfigurationException ex) { +// throw new AuthenticationException("1205", new Object[] { +// samlArtifact, ex.toString() }); +// } + if (!keepAssertion) { + authenticationDataStore.remove(samlArtifact); + } + + long now = new Date().getTime(); + + if (now - authData.getTimestamp().getTime() > authDataTimeOut) + throw new AuthenticationException("1207", new Object[] { samlArtifact }); + + Logger.debug("Assertion delivered for SAML Artifact: " + samlArtifact); + + return authData; + } + + public String BuildErrorAssertion(Throwable error, IRequest protocolRequest) + throws BuildException, MOADatabaseException { + + String samlArtifact = new SAMLArtifactBuilder().build( + protocolRequest.getOAURL(), protocolRequest.getRequestID(), + null); + + authenticationDataStore.put(samlArtifact, error); + + return samlArtifact; + } + + public String BuildSAMLArtifact(AuthenticationSession session, + OAAuthParameter oaParam, + AuthenticationData authData) + throws ConfigurationException, BuildException, AuthenticationException { + + //Load SAML1 Parameter from OA config + OASAML1 saml1parameter = oaParam.getSAML1Parameter(); + + boolean useCondition = saml1parameter.isUseCondition(); + int conditionLength = saml1parameter.getConditionLength().intValue(); + + try { + + //set BASE64 encoded signer certificate + String signerCertificateBase64 = ""; + if (saml1parameter.isProvideCertificate()) { + byte[] signerCertificate = session.getEncodedSignerCertificate(); + if (signerCertificate != null) { + + signerCertificateBase64 = Base64Utils + .encode(signerCertificate); + } else { + Logger.info("\"provideCertificate\" is \"true\", but no signer certificate available"); + } + } + + //set prPersion + boolean provideStammzahl = saml1parameter.isProvideStammzahl(); + String prPerson = new PersonDataBuilder().build(authData.getIdentityLink(), + provideStammzahl); + + //set Authblock + String authBlock = saml1parameter.isProvideAUTHBlock() ? session + .getAuthBlock() : ""; + + //set IdentityLink for assortion + String ilAssertion = saml1parameter.isProvideIdentityLink() ? authData.getIdentityLink() + .getSerializedSamlAssertion() + : ""; + if (!saml1parameter.isProvideStammzahl()) { + ilAssertion = StringUtils.replaceAll(ilAssertion, authData.getIdentityLink() + .getIdentificationValue(), ""); + } + + String samlAssertion; + + if (session.getUseMandate()) { + List oaAttributes = session.getExtendedSAMLAttributesOA(); + + if (saml1parameter.isProvideFullMandatorData()) { + + try { + + ExtendedSAMLAttribute[] extendedSAMLAttributes = addExtendedSamlAttributes( + session.getMISMandate(), oaParam.getBusinessService(), + saml1parameter.isProvideStammzahl()); + + if (extendedSAMLAttributes != null) { + + String identifier = "MISService"; + String friendlyName ="MISService"; + + int length = extendedSAMLAttributes.length; + for (int i = 0; i < length; i++) { + ExtendedSAMLAttribute samlAttribute = extendedSAMLAttributes[i]; + + Object value = verifySAMLAttribute(samlAttribute, i, identifier, + friendlyName); + + if ((value instanceof String) || (value instanceof Element)) { + switch (samlAttribute.getAddToAUTHBlock()) { + case ExtendedSAMLAttribute.ADD_TO_AUTHBLOCK: + replaceExtendedSAMLAttribute(oaAttributes, samlAttribute); + break; + case ExtendedSAMLAttribute.NOT_ADD_TO_AUTHBLOCK: + replaceExtendedSAMLAttribute(oaAttributes, samlAttribute); + break; + default: + Logger + .info("Invalid return value from method \"getAddToAUTHBlock()\" (" + + samlAttribute.getAddToAUTHBlock() + + ") in SAML attribute number " + + (i + 1) + + " for infobox " + identifier); + throw new ValidateException("validator.47", new Object[] { + friendlyName, String.valueOf((i + 1)) }); + } + } else { + Logger + .info("The type of SAML-Attribute number " + + (i + 1) + + " returned from " + + identifier + + "-infobox validator is not valid. Must be either \"java.Lang.String\"" + + " or \"org.w3c.dom.Element\""); + throw new ValidateException("validator.46", new Object[] { + identifier, String.valueOf((i + 1)) }); + } + } + } + + } catch (SAXException e) { + throw new AuthenticationException("auth.16", + new Object[] { GET_MIS_SESSIONID }, e); + } catch (IOException e) { + throw new AuthenticationException("auth.16", + new Object[] { GET_MIS_SESSIONID }, e); + } catch (ParserConfigurationException e) { + throw new AuthenticationException("auth.16", + new Object[] { GET_MIS_SESSIONID }, e); + } catch (TransformerException e) { + throw new AuthenticationException("auth.16", + new Object[] { GET_MIS_SESSIONID }, e); + } + } + + String mandateDate = generateMandateDate(session, oaParam, authData); + + samlAssertion = new AuthenticationDataAssertionBuilder().buildMandate( + authData, + prPerson, + mandateDate, + authBlock, + ilAssertion, + session.getBkuURL(), + signerCertificateBase64, + oaParam.getBusinessService(), + oaAttributes, + useCondition, + conditionLength); + + } else { + samlAssertion = new AuthenticationDataAssertionBuilder().build( + authData, + prPerson, + authBlock, + ilAssertion, + session.getBkuURL(), + signerCertificateBase64, + oaParam.getBusinessService(), + session.getExtendedSAMLAttributesOA(), + useCondition, + conditionLength); + } + + authData.setSamlAssertion(samlAssertion); + + String samlArtifact = new SAMLArtifactBuilder().build( + session.getAuthURL(), session.getSessionID(), + saml1parameter.getSourceID()); + + storeAuthenticationData(samlArtifact, authData); + + Logger.info("Anmeldedaten zu MOASession " + session.getSessionID() + + " angelegt, SAML Artifakt " + samlArtifact); + return samlArtifact; + + } catch (Throwable ex) { + throw new BuildException("builder.00", new Object[] { + "AuthenticationData", ex.toString() }, ex); + } + + } + + private String generateMandateDate(AuthenticationSession session, + OAAuthParameter oaParam, AuthenticationData authData + ) throws AuthenticationException, BuildException, + ParseException, ConfigurationException, ServiceException, + ValidateException { + + if (session == null) + throw new AuthenticationException("auth.10", new Object[] { + REQ_VERIFY_AUTH_BLOCK, PARAM_SESSIONID }); + + //AuthenticationSession session = getSession(sessionID); + // AuthConfigurationProvider authConf = + // AuthConfigurationProvider.getInstance(); + + IdentityLink tempIdentityLink = null; + + Element mandate = session.getMandate(); + + if (session.getUseMandate()) { + tempIdentityLink = new IdentityLink(); + Element mandator = ParepUtils.extractMandator(mandate); + String dateOfBirth = ""; + Element prPerson = null; + String familyName = ""; + String givenName = ""; + String identificationType = ""; + String identificationValue = ""; + if (mandator != null) { + boolean physical = ParepUtils.isPhysicalPerson(mandator); + if (physical) { + familyName = ParepUtils.extractText(mandator, + "descendant-or-self::pr:Name/pr:FamilyName/text()"); + givenName = ParepUtils.extractText(mandator, + "descendant-or-self::pr:Name/pr:GivenName/text()"); + dateOfBirth = ParepUtils + .extractMandatorDateOfBirth(mandator); + } else { + familyName = ParepUtils.extractMandatorFullName(mandator); + } + identificationType = ParepUtils.getIdentification(mandator, + "Type"); + identificationValue = ParepUtils.extractMandatorWbpk(mandator); + + prPerson = ParepUtils.extractPrPersonOfMandate(mandate); + if (physical + && oaParam.getBusinessService() + && identificationType != null + && Constants.URN_PREFIX_BASEID + .equals(identificationType)) { + // now we calculate the wbPK and do so if we got it from the + // BKU + + + //load IdentityLinkDomainType from OAParam + String type = oaParam.getIdentityLinkDomainIdentifier(); + if (type.startsWith(Constants.URN_PREFIX_WBPK + "+")) + identificationType = type; + else + identificationType = Constants.URN_PREFIX_WBPK + "+" + + type; + + + identificationValue = new BPKBuilder().buildWBPK( + identificationValue, identificationType); + ParepUtils + .HideStammZahlen(prPerson, true, null, null, true); + } + + tempIdentityLink.setDateOfBirth(dateOfBirth); + tempIdentityLink.setFamilyName(familyName); + tempIdentityLink.setGivenName(givenName); + tempIdentityLink.setIdentificationType(identificationType); + tempIdentityLink.setIdentificationValue(identificationValue); + tempIdentityLink.setPrPerson(prPerson); + try { + tempIdentityLink.setSamlAssertion(authData.getIdentityLink() + .getSamlAssertion()); + } catch (Exception e) { + throw new ValidateException("validator.64", null); + } + + } + + } + + Element mandatePerson = tempIdentityLink.getPrPerson(); + + String mandateData = null; + try { + + boolean provideStammzahl = oaParam.getSAML1Parameter().isProvideStammzahl(); + + String oatargetType; + + if(oaParam.getBusinessService()) { + oatargetType = AuthenticationSession.REGISTERANDORDNR_PREFIX_+session.getDomainIdentifier(); + + } else { + oatargetType = AuthenticationSession.TARGET_PREFIX_ + oaParam.getTarget(); + } + + Element prIdentification = (Element) mandatePerson + .getElementsByTagNameNS(Constants.PD_NS_URI, + "Identification").item(0); + + if (!oatargetType.equals(tempIdentityLink.getIdentificationType())) { + + String isPrPerson = mandatePerson.getAttribute("xsi:type"); + + if (!StringUtils.isEmpty(isPrPerson)) { + if (isPrPerson.equalsIgnoreCase("pr:PhysicalPerson")) { + String baseid = getBaseId(mandatePerson); + Element identificationBpK = createIdentificationBPK(mandatePerson, + baseid, oaParam.getTarget()); + + if (!provideStammzahl) { + prIdentification.getFirstChild().setTextContent(""); + } + + mandatePerson.insertBefore(identificationBpK, + prIdentification); + } + } + + } else { + +// Element identificationBpK = mandatePerson.getOwnerDocument() +// .createElementNS(Constants.PD_NS_URI, "Identification"); +// Element valueBpK = mandatePerson.getOwnerDocument().createElementNS( +// Constants.PD_NS_URI, "Value"); +// +// valueBpK.appendChild(mandatePerson.getOwnerDocument().createTextNode( +// tempIdentityLink.getIdentificationValue())); +// Element typeBpK = mandatePerson.getOwnerDocument().createElementNS( +// Constants.PD_NS_URI, "Type"); +// typeBpK.appendChild(mandatePerson.getOwnerDocument().createTextNode( +// "urn:publicid:gv.at:cdid+bpk")); +// identificationBpK.appendChild(valueBpK); +// identificationBpK.appendChild(typeBpK); +// +// mandatePerson.insertBefore(identificationBpK, prIdentification); + } + + + mandateData = DOMUtils.serializeNode(mandatePerson); + + } catch (TransformerException e1) { + throw new AuthenticationException("auth.16", + new Object[] { GET_MIS_SESSIONID }); + } catch (IOException e1) { + throw new AuthenticationException("auth.16", + new Object[] { GET_MIS_SESSIONID }); + } + + return mandateData; + } + + + + + /** + * Stores authentication data indexed by the assertion handle contained in + * the given saml artifact. + * + * @param samlArtifact + * SAML artifact + * @param authData + * authentication data + * @throws AuthenticationException + * when SAML artifact is invalid + */ + private void storeAuthenticationData(String samlArtifact, + AuthenticationData authData) throws AuthenticationException { + + try { + SAMLArtifactParser parser = new SAMLArtifactParser(samlArtifact); + // check type code 0x0001 + byte[] typeCode = parser.parseTypeCode(); + if (typeCode[0] != 0 || typeCode[1] != 1) + throw new AuthenticationException("auth.06", + new Object[] { samlArtifact }); + parser.parseAssertionHandle(); + + synchronized (authenticationDataStore) { + Logger.debug("Assertion stored for SAML Artifact: " + + samlArtifact); + authenticationDataStore.put(samlArtifact, authData); + } + + } catch (AuthenticationException ex) { + throw ex; + + } catch (Throwable ex) { + throw new AuthenticationException("auth.06", + new Object[] { samlArtifact }); + } + } + +} |