From 3536b99c17250772f253ea5925da72a29e327c58 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 11 Sep 2015 18:23:33 +0200 Subject: move authentication protocol implementation to separate modules. authentication protocol modules are loaded by SPI now. --- .../AuthenticationDataAssertionBuilder.java | 458 ++++++++++++++++ .../moa/id/protocols/saml1/GetArtifactAction.java | 142 +++++ .../saml1/GetAuthenticationDataService.java | 213 ++++++++ .../protocols/saml1/SAML1AuthenticationData.java | 177 ++++++ .../protocols/saml1/SAML1AuthenticationServer.java | 592 +++++++++++++++++++++ .../moa/id/protocols/saml1/SAML1Protocol.java | 226 ++++++++ .../moa/id/protocols/saml1/SAML1RequestImpl.java | 96 ++++ .../at.gv.egovernment.moa.id.moduls.IModulInfo | 1 + 8 files changed, 1905 insertions(+) create mode 100644 id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataAssertionBuilder.java create mode 100644 id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/GetArtifactAction.java create mode 100644 id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/GetAuthenticationDataService.java create mode 100644 id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1AuthenticationData.java create mode 100644 id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1AuthenticationServer.java create mode 100644 id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1Protocol.java create mode 100644 id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1RequestImpl.java create mode 100644 id/server/modules/moa-id-modules-saml1/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.IModulInfo (limited to 'id/server/modules/moa-id-modules-saml1/src') diff --git a/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataAssertionBuilder.java b/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataAssertionBuilder.java new file mode 100644 index 000000000..fc04fa9a7 --- /dev/null +++ b/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/auth/builder/AuthenticationDataAssertionBuilder.java @@ -0,0 +1,458 @@ +/******************************************************************************* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 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: + * http://www.osor.eu/eupl/ + * + * 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.egovernment.moa.id.auth.builder; + +import java.text.MessageFormat; +import java.util.Calendar; +import java.util.List; + +import at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute; +import at.gv.egovernment.moa.id.auth.exception.BuildException; +import at.gv.egovernment.moa.id.auth.exception.ParseException; +import at.gv.egovernment.moa.id.data.AuthenticationData; +import at.gv.egovernment.moa.id.protocols.saml1.SAML1AuthenticationData; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DateTimeUtils; +import at.gv.egovernment.moa.util.StringUtils; + +/** + * Builder for the authentication data <saml:Assertion> + * to be provided by the MOA ID Auth component. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class AuthenticationDataAssertionBuilder extends AuthenticationAssertionBuilder implements Constants { + + /** 5 minutes (=300 seconds) default length of the assertion */ + private static int DEFAULT_CONDITIONS_LENGTH = 300; + + /** private static String NL contains the NewLine representation in Java*/ + private static final String NL = "\n"; + /** + * XML template for the <saml:Assertion> to be built + */ + private static final String AUTH_DATA = + "" + NL + + "" + NL + + " " + NL + + " " + NL + + " {4}" + NL + + " " + NL + + " " + MOA_NS_URI + "cm" + NL + + " {5}{6}" + NL + + " " + NL + + " " + NL + + " " + NL + + " {7}" + NL + + " " + NL + + " " + NL + + " {8}" + NL + + " " + NL + + " " + NL + + " {9}" + NL + + " " + NL + + "{10}" + + "{11}" + + "{12}" + + " " + NL + + ""; + + /** + * XML template for the <saml:Assertion> to be built (with Conditions) + */ + private static final String AUTH_DATA_WITH_CONDITIONS = + "" + NL + + "" + NL + + "" + NL + + " " + NL + + " " + NL + + " {6}" + NL + + " " + NL + + " " + MOA_NS_URI + "cm" + NL + + " {7}{8}" + NL + + " " + NL + + " " + NL + + " " + NL + + " {9}" + NL + + " " + NL + + " " + NL + + " {10}" + NL + + " " + NL + + " " + NL + + " {11}" + NL + + " " + NL + + "{12}" + + "{13}" + + "{14}" + + " " + NL + + ""; + + /** + * XML template for the <saml:Assertion> to be built + */ + private static final String AUTH_DATA_MANDATE = + "" + NL + + "" + NL + + " " + NL + + " " + NL + + " {4}" + NL + + " " + NL + + " " + MOA_NS_URI + "cm" + NL + + " {5}{6}" + NL + + " " + NL + + " " + NL + + " " + NL + + " {7}" + NL + + " " + NL + + " " + NL + + " {8}" + NL + + " " + NL + + " " + NL + + " {9}" + NL + + " " + NL + + " " + NL + + " {10}" + NL + + " " + NL + + "{11}" + + "{12}" + + "{13}" + + " " + NL + + ""; + + /** + * XML template for the <saml:Assertion> to be built + */ + private static final String AUTH_DATA_MANDATE_WITH_CONDITIONS = + "" + NL + + "" + NL + + "" + NL + + " " + NL + + " " + NL + + " {6}" + NL + + " " + NL + + " " + MOA_NS_URI + "cm" + NL + + " {7}{8}" + NL + + " " + NL + + " " + NL + + " " + NL + + " {9}" + NL + + " " + NL + + " " + NL + + " {10}" + NL + + " " + NL + + " " + NL + + " {11}" + NL + + " " + NL + + " " + NL + + " {12}" + NL + + " " + NL + + "{13}" + + "{14}" + + "{15}" + + " " + NL + + ""; + /** + * XML template for the <saml:Attribute> named "isPublicAuthority", + * to be inserted into the <saml:Assertion> + */ + private static final String PUBLIC_AUTHORITY_ATT = + " " + NL + + " {0}" + NL + + " " + NL; + + private static final String SIGNER_CERTIFICATE_ATT = + " " + NL + + " {0}" + NL + + " " + NL; + + /** + * Constructor for AuthenticationDataAssertionBuilder. + */ + public AuthenticationDataAssertionBuilder() { + super(); + } + + /** + * Builds the authentication data <saml:Assertion>. + * + * @param authData the AuthenticationData to build the + * <saml:Assertion> from + * @param xmlPersonData lt;pr:Person> element as a String + * @param xmlAuthBlock authentication block to be included in a + * lt;saml:SubjectConfirmationData> element; may include + * the "Stammzahl" or not; may be empty + * @param xmlIdentityLink the IdentityLink + * @param signerCertificateBase64 Base64 encoded certificate of the signer. Maybe + * an empty string if the signer certificate should not be provided. + * Will be ignored if the businessService parameter is + * set to false. + * @param businessService true if the online application is a + * business service, otherwise false + * @return the <saml:Assertion> + * @throws BuildException if an error occurs during the build process + */ + public String build( + SAML1AuthenticationData authData, + String xmlPersonData, + String xmlAuthBlock, + String xmlIdentityLink, + String bkuURL, + String signerCertificateBase64, + boolean businessService, + List extendedSAMLAttributes, + boolean useCondition, + int conditionLength) + throws BuildException + { + + String isQualifiedCertificate = authData.isQualifiedCertificate() ? "true" : "false"; + + String publicAuthorityAttribute = ""; + if (authData.isPublicAuthority()) { + String publicAuthorityIdentification = authData.getPublicAuthorityCode(); + if (publicAuthorityIdentification == null) + publicAuthorityIdentification = "True"; + publicAuthorityAttribute = MessageFormat.format( + PUBLIC_AUTHORITY_ATT, new Object[] { publicAuthorityIdentification }); + } + + + String signerCertificateAttribute = ""; + if (signerCertificateBase64 != "") { + signerCertificateAttribute = MessageFormat.format( + SIGNER_CERTIFICATE_ATT, new Object[] { signerCertificateBase64 }); + } + + String pkType; + String pkValue; + if (businessService) { + pkType = authData.getBPKType(); + pkValue = authData.getBPK(); + + } else { + // always has the bPK as type/value + pkType = URN_PREFIX_BPK; + pkValue = authData.getBPK(); + } + +// System.out.println("pkType; " + pkType); +// System.out.println("pkValue; " + pkValue); + + String assertion; + try { + + if (!useCondition) { + assertion = MessageFormat.format(AUTH_DATA, new Object[] { + authData.getAssertionID(), + authData.getIssuer(), + authData.getIssueInstantString(), + pkType, + pkValue, + StringUtils.removeXMLDeclaration(xmlAuthBlock), + StringUtils.removeXMLDeclaration(xmlIdentityLink), + StringUtils.removeXMLDeclaration(xmlPersonData), + isQualifiedCertificate, + bkuURL, + publicAuthorityAttribute, + signerCertificateAttribute, + buildExtendedSAMLAttributes(extendedSAMLAttributes)}); + } + else { + Calendar cal = Calendar.getInstance(); + String notBefore = DateTimeUtils.buildDateTimeUTC(cal); + if (conditionLength <= 0) + cal.add(Calendar.SECOND, DEFAULT_CONDITIONS_LENGTH); + else + cal.add(Calendar.SECOND, conditionLength); + + String notOnOrAfter = DateTimeUtils.buildDateTimeUTC(cal); + + assertion = MessageFormat.format(AUTH_DATA_WITH_CONDITIONS, new Object[] { + authData.getAssertionID(), + authData.getIssuer(), + authData.getIssueInstantString(), + notBefore, + notOnOrAfter, + pkType, + pkValue, + StringUtils.removeXMLDeclaration(xmlAuthBlock), + StringUtils.removeXMLDeclaration(xmlIdentityLink), + StringUtils.removeXMLDeclaration(xmlPersonData), + isQualifiedCertificate, + bkuURL, + publicAuthorityAttribute, + signerCertificateAttribute, + buildExtendedSAMLAttributes(extendedSAMLAttributes)}); + } + + + } catch (ParseException e) { + Logger.error("Error on building Authentication Data Assertion: " + e.getMessage()); + throw new BuildException("builder.00", new Object[] { "Authentication Data Assertion", e.toString()}); + } + return assertion; + } + + /** + * Builds the authentication data <saml:Assertion>. + * + * @param authData the AuthenticationData to build the + * <saml:Assertion> from + * @param xmlPersonData lt;pr:Person> element as a String + * @param xmlAuthBlock authentication block to be included in a + * lt;saml:SubjectConfirmationData> element; may include + * the "Stammzahl" or not; may be empty + * @param xmlIdentityLink the IdentityLink + * @param signerCertificateBase64 Base64 encoded certificate of the signer. Maybe + * an empty string if the signer certificate should not be provided. + * Will be ignored if the businessService parameter is + * set to false. + * @param businessService true if the online application is a + * business service, otherwise false + * @return the <saml:Assertion> + * @throws BuildException if an error occurs during the build process + */ + public String buildMandate( + SAML1AuthenticationData authData, + String xmlPersonData, + String xmlMandateData, + String xmlAuthBlock, + String xmlIdentityLink, + String bkuURL, + String signerCertificateBase64, + boolean businessService, + List extendedSAMLAttributes, + boolean useCondition, + int conditionLength) + throws BuildException + { + + String isQualifiedCertificate = authData.isQualifiedCertificate() ? "true" : "false"; + String publicAuthorityAttribute = ""; + if (authData.isPublicAuthority()) { + String publicAuthorityIdentification = authData.getPublicAuthorityCode(); + if (publicAuthorityIdentification == null) + publicAuthorityIdentification = "True"; + publicAuthorityAttribute = MessageFormat.format( + PUBLIC_AUTHORITY_ATT, new Object[] { publicAuthorityIdentification }); + } + + + String signerCertificateAttribute = ""; + if (signerCertificateBase64 != "") { + signerCertificateAttribute = MessageFormat.format( + SIGNER_CERTIFICATE_ATT, new Object[] { signerCertificateBase64 }); + } + + String pkType; + String pkValue; + if (businessService) { + pkType = authData.getBPKType(); + pkValue = authData.getBPK(); + + } else { + // always has the bPK as type/value + pkType = URN_PREFIX_BPK; + pkValue = authData.getBPK(); + } + +// System.out.println("pkType; " + pkType); +// System.out.println("pkValue; " + pkValue); + + String assertion; + try { + + + + if (!useCondition) { + assertion = MessageFormat.format(AUTH_DATA_MANDATE, new Object[] { + authData.getAssertionID(), + authData.getIssuer(), + authData.getIssueInstantString(), + pkType, + pkValue, + StringUtils.removeXMLDeclaration(xmlAuthBlock), + StringUtils.removeXMLDeclaration(xmlIdentityLink), + StringUtils.removeXMLDeclaration(xmlPersonData), + StringUtils.removeXMLDeclaration(xmlMandateData), + isQualifiedCertificate, + bkuURL, + publicAuthorityAttribute, + signerCertificateAttribute, + buildExtendedSAMLAttributes(extendedSAMLAttributes)}); + } + else { + Calendar cal = Calendar.getInstance(); + String notBefore = DateTimeUtils.buildDateTimeUTC(cal); + if (conditionLength <= 0) + cal.add(Calendar.SECOND, DEFAULT_CONDITIONS_LENGTH); + else + cal.add(Calendar.SECOND, conditionLength); + + String notOnOrAfter = DateTimeUtils.buildDateTimeUTC(cal); + + assertion = MessageFormat.format(AUTH_DATA_MANDATE_WITH_CONDITIONS, new Object[] { + authData.getAssertionID(), + authData.getIssuer(), + authData.getIssueInstantString(), + notBefore, + notOnOrAfter, + pkType, + pkValue, + StringUtils.removeXMLDeclaration(xmlAuthBlock), + StringUtils.removeXMLDeclaration(xmlIdentityLink), + StringUtils.removeXMLDeclaration(xmlPersonData), + StringUtils.removeXMLDeclaration(xmlMandateData), + isQualifiedCertificate, + bkuURL, + publicAuthorityAttribute, + signerCertificateAttribute, + buildExtendedSAMLAttributes(extendedSAMLAttributes)}); + } + + + + + + + } catch (ParseException e) { + Logger.error("Error on building Authentication Data Assertion: " + e.getMessage()); + throw new BuildException("builder.00", new Object[] { "Authentication Data Assertion", e.toString()}); + } + return assertion; + } + +} diff --git a/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/GetArtifactAction.java b/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/GetArtifactAction.java new file mode 100644 index 000000000..2019b0d20 --- /dev/null +++ b/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/GetArtifactAction.java @@ -0,0 +1,142 @@ +/******************************************************************************* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 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: + * http://www.osor.eu/eupl/ + * + * 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.egovernment.moa.id.protocols.saml1; + +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; +import at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute; +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; +import at.gv.egovernment.moa.id.auth.servlet.RedirectServlet; +import at.gv.egovernment.moa.id.auth.stork.STORKResponseProcessor; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.data.SLOInformationImpl; +import at.gv.egovernment.moa.id.data.SLOInformationInterface; +import at.gv.egovernment.moa.id.moduls.IAction; +import at.gv.egovernment.moa.id.moduls.IRequest; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.URLEncoder; + +public class GetArtifactAction implements IAction { + + public SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq, + HttpServletResponse httpResp, IAuthData obj) throws AuthenticationException { + + String oaURL = (String) req.getOAURL(); + + String sourceID = null; + if (req instanceof SAML1RequestImpl) { + SAML1RequestImpl saml1req = (SAML1RequestImpl) req; + sourceID = saml1req.getSourceID(); + + } + + SAML1AuthenticationData authData; + if (obj instanceof SAML1AuthenticationData) { + authData = (SAML1AuthenticationData) obj; + + } else { + Logger.error("AuthDate is NOT of type SAML1AuthenticationData."); + throw new AuthenticationException("AuthDate is NOT of type SAML1AuthenticationData.", new Object[]{}); + } + + try { + OAAuthParameter oaParam = AuthConfigurationProviderFactory.getInstance() + .getOnlineApplicationParameter(oaURL); + + SAML1AuthenticationServer saml1server = SAML1AuthenticationServer.getInstace(); + + // add other stork attributes to MOA assertion if available + if(null != authData.getStorkAttributes()) { + List moaExtendedSAMLAttibutes = STORKResponseProcessor.addAdditionalSTORKAttributes(authData.getStorkAttributes()); + authData.getExtendedSAMLAttributesOA().addAll(moaExtendedSAMLAttibutes); + Logger.info("MOA assertion assembled and SAML Artifact generated."); + } + + String samlArtifactBase64 = saml1server.BuildSAMLArtifact(oaParam, authData, sourceID); + + if (authData.isSsoSession()) { + String url = AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix() + "/RedirectServlet"; + url = addURLParameter(url, RedirectServlet.REDIRCT_PARAM_URL, URLEncoder.encode(oaURL, "UTF-8")); + if (!oaParam.getBusinessService()) + url = addURLParameter(url, MOAIDAuthConstants.PARAM_TARGET, URLEncoder.encode(req.getTarget(), "UTF-8")); + url = addURLParameter(url, MOAIDAuthConstants.PARAM_SAMLARTIFACT, URLEncoder.encode(samlArtifactBase64, "UTF-8")); + url = httpResp.encodeRedirectURL(url); + + httpResp.setContentType("text/html"); + httpResp.setStatus(302); + httpResp.addHeader("Location", url); + + } else { + String redirectURL = oaURL; + if (!oaParam.getBusinessService()) { + redirectURL = addURLParameter(redirectURL, MOAIDAuthConstants.PARAM_TARGET, + URLEncoder.encode(req.getTarget(), "UTF-8")); + + } + + redirectURL = addURLParameter(redirectURL, MOAIDAuthConstants.PARAM_SAMLARTIFACT, + URLEncoder.encode(samlArtifactBase64, "UTF-8")); + redirectURL = httpResp.encodeRedirectURL(redirectURL); + httpResp.setContentType("text/html"); + httpResp.setStatus(302); + httpResp.addHeader("Location", redirectURL); + Logger.debug("REDIRECT TO: " + redirectURL); + } + + SLOInformationInterface sloInformation = + new SLOInformationImpl(authData.getAssertionID(), null, null, req.requestedModule()); + + return sloInformation; + + } catch (Exception ex) { + Logger.error("SAML1 Assertion build error", ex); + throw new AuthenticationException("SAML1 Assertion build error.", new Object[]{}, ex); + } + + } + + protected static String addURLParameter(String url, String paramname, + String paramvalue) { + String param = paramname + "=" + paramvalue; + if (url.indexOf("?") < 0) + return url + "?" + param; + else + return url + "&" + param; + } + + public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, + HttpServletResponse httpResp) { + return true; + } + + public String getDefaultActionName() { + return SAML1Protocol.GETARTIFACT; + } + +} diff --git a/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/GetAuthenticationDataService.java b/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/GetAuthenticationDataService.java new file mode 100644 index 000000000..2b4aaf458 --- /dev/null +++ b/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/GetAuthenticationDataService.java @@ -0,0 +1,213 @@ +/******************************************************************************* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 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: + * http://www.osor.eu/eupl/ + * + * 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. + ******************************************************************************/ +/* + * Copyright 2003 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 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: + * http://www.osor.eu/eupl/ + * + * 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.egovernment.moa.id.protocols.saml1; + +import java.util.Calendar; + +import org.apache.axis.AxisFault; +import org.apache.commons.lang3.StringEscapeUtils; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import at.gv.egovernment.moa.id.auth.builder.SAMLResponseBuilder; +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.util.ErrorResponseUtils; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.id.util.Random; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.DateTimeUtils; +import at.gv.egovernment.moa.util.XPathUtils; + +/** + * Web service for picking up authentication data created in the MOA-ID Auth component. + * + * @author Paul Ivancsics + * @version $Id: GetAuthenticationDataService.java 1233 2012-01-26 21:59:33Z kstranacher $ + * @see at.gv.egovernment.moa.id.auth.AuthenticationServer#getAuthenticationData + */ +public class GetAuthenticationDataService implements Constants { + + /** + * Constructor for GetAuthenticationDataService. + */ + public GetAuthenticationDataService() { + super(); + } + + /** + * Takes a lt;samlp:Request> containing a + * SAML artifact and returns the corresponding + * authentication data lt;saml:Assertion> + * (obtained from the AuthenticationServer), + * enclosed in a lt;samlp:Response>. + *
Bad requests are mapped into various lt;samlp:StatusCode>s, + * possibly containing enclosed sub-lt;samlp:StatusCode>s. + * The status codes are defined in the SAML specification. + * + * @param requests request elements of type lt;samlp:Request>; + * only 1 request element is allowed + * @return response element of type lt;samlp:Response>, + * packed into an Element[] + * @throws AxisFault thrown when an error occurs in assembling the + * lt;samlp:Response> + */ + public Element[] Request(Element[] requests) + throws AxisFault { + + Element request = requests[0]; + Element[] responses = new Element[1]; + String requestID = ""; + String statusCode = ""; + String subStatusCode = null; + String statusMessageCode = null; + String statusMessage = null; + String samlAssertion = ""; + if (requests.length > 1) { + // more than 1 request given as parameter + statusCode = "samlp:Requester"; + subStatusCode = "samlp:TooManyResponses"; + statusMessageCode = "1201"; + } + else { + try { + DOMUtils.validateElement(request, ALL_SCHEMA_LOCATIONS, null); + NodeList samlArtifactList = XPathUtils.selectNodeList(request, "samlp:AssertionArtifact"); + if (samlArtifactList.getLength() == 0) { + // no SAML artifact given in request + statusCode = "samlp:Requester"; + statusMessageCode = "1202"; + } + else if (samlArtifactList.getLength() > 1) { + // too many SAML artifacts given in request + statusCode = "samlp:Requester"; + subStatusCode = "samlp:TooManyResponses"; + statusMessageCode = "1203"; + } + + else { + Element samlArtifactElem = (Element)samlArtifactList.item(0); + requestID = request.getAttribute("RequestID"); + String samlArtifact = DOMUtils.getText(samlArtifactElem); + SAML1AuthenticationServer saml1server = SAML1AuthenticationServer.getInstace(); + + try { + + samlAssertion = saml1server.getSaml1AuthenticationData(samlArtifact); + + // success + statusCode = "samlp:Success"; + statusMessageCode = "1200"; + } + + catch (ClassCastException ex) { + + try { + Throwable error = saml1server.getErrorResponse(samlArtifact); + statusCode = "samlp:Responder"; + + ErrorResponseUtils errorUtils = ErrorResponseUtils.getInstance(); + + if (error instanceof MOAIDException) { + statusMessageCode = ((MOAIDException)error).getMessageId(); + statusMessage = StringEscapeUtils.escapeXml(((MOAIDException)error).getMessage()); + + } else { + statusMessage = StringEscapeUtils.escapeXml(error.getMessage()); + } + subStatusCode = errorUtils.getResponseErrorCode(error); + + } catch (Exception e) { + //no authentication data for given SAML artifact + statusCode = "samlp:Requester"; + subStatusCode = "samlp:ResourceNotRecognized"; + statusMessage = ex.toString(); + } + + } + + catch (AuthenticationException ex) { + //no authentication data for given SAML artifact + statusCode = "samlp:Requester"; + subStatusCode = "samlp:ResourceNotRecognized"; + statusMessage = ex.toString(); + } + } + } + catch (Throwable t) { + // invalid request format + statusCode = "samlp:Requester"; + statusMessageCode = "1204"; + } + } + + try { + String responseID = Random.nextRandom(); + String issueInstant = DateTimeUtils.buildDateTimeUTC(Calendar.getInstance()); + + if (statusMessage == null) + statusMessage = MOAIDMessageProvider.getInstance().getMessage(statusMessageCode, null); + responses[0] = new SAMLResponseBuilder().build( + responseID, requestID, issueInstant, statusCode, subStatusCode, statusMessage, samlAssertion); + + } + catch (MOAIDException e) { + AxisFault fault = AxisFault.makeFault(e); + fault.setFaultDetail(new Element[] { e.toErrorResponse()}); + throw fault; + } + catch (Throwable t) { + MOAIDException e = new MOAIDException("1299", null, t); + AxisFault fault = AxisFault.makeFault(e); + fault.setFaultDetail(new Element[] { e.toErrorResponse()}); + throw fault; + } + return responses; + } + +} diff --git a/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1AuthenticationData.java b/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1AuthenticationData.java new file mode 100644 index 000000000..d48c0a9bb --- /dev/null +++ b/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1AuthenticationData.java @@ -0,0 +1,177 @@ +/******************************************************************************* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 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: + * http://www.osor.eu/eupl/ + * + * 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. + ******************************************************************************/ +/* + * Copyright 2003 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 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: + * http://www.osor.eu/eupl/ + * + * 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.egovernment.moa.id.protocols.saml1; + +import java.text.ParseException; +import java.util.List; + +import at.gv.egovernment.moa.id.auth.data.ExtendedSAMLAttribute; +import at.gv.egovernment.moa.id.data.AuthenticationData; +import at.gv.egovernment.moa.id.util.Random; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.DateTimeUtils; + +/** + * Encapsulates authentication data contained in a <saml:Assertion>. + * + * @author Paul Ivancsics + * @version $Id$ + */ + +public class SAML1AuthenticationData extends AuthenticationData { + /** + * + */ + private static final long serialVersionUID = -1042697056735596866L; +/** + * major version number of the SAML assertion + */ + private int majorVersion; + /** + * minor version number of the SAML assertion + */ + private int minorVersion; + /** + * identifier for this assertion + */ + private String assertionID; +/** + * @return the majorVersion + */ + + private String samlAssertion = null; + + private List extendedSAMLAttributesOA; + + + public SAML1AuthenticationData() { + this.setMajorVersion(1); + this.setMinorVersion(0); + this.setAssertionID(Random.nextRandom()); + } + + + //this method is only required for MOA-ID Proxy 2.0 Release. + //TODO: remove it, if MOA-ID Proxy is not supported anymore. + public String getWBPK() { + return getBPK(); + } + +public int getMajorVersion() { + return majorVersion; +} +/** + * @param majorVersion the majorVersion to set + */ +public void setMajorVersion(int majorVersion) { + this.majorVersion = majorVersion; +} +/** + * @return the minorVersion + */ +public int getMinorVersion() { + return minorVersion; +} +/** + * @param minorVersion the minorVersion to set + */ +public void setMinorVersion(int minorVersion) { + this.minorVersion = minorVersion; +} +/** + * @return the assertionID + */ +public String getAssertionID() { + return assertionID; +} +/** + * @param assertionID the assertionID to set + */ +public void setAssertionID(String assertionID) { + this.assertionID = assertionID; +} + +public void setIssueInstant(String date) { + try { + setIssueInstant(DateTimeUtils.parseDateTime(date)); + + } catch (ParseException e) { + Logger.error("Parse IssueInstant element FAILED.", e); + + } +} + +/** + * @return the samlAssertion + */ +public String getSamlAssertion() { + return samlAssertion; +} + +/** + * @param samlAssertion the samlAssertion to set + */ +public void setSamlAssertion(String samlAssertion) { + this.samlAssertion = samlAssertion; +} + +/** + * @return the extendedSAMLAttributesOA + */ +public List getExtendedSAMLAttributesOA() { + return extendedSAMLAttributesOA; +} + +/** + * @param extendedSAMLAttributesOA the extendedSAMLAttributesOA to set + */ +public void setExtendedSAMLAttributesOA( + List extendedSAMLAttributesOA) { + this.extendedSAMLAttributesOA = extendedSAMLAttributesOA; +} + +} diff --git a/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1AuthenticationServer.java b/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1AuthenticationServer.java new file mode 100644 index 000000000..e70e71d49 --- /dev/null +++ b/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1AuthenticationServer.java @@ -0,0 +1,592 @@ +/******************************************************************************* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 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: + * http://www.osor.eu/eupl/ + * + * 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.egovernment.moa.id.protocols.saml1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.List; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.Marshaller; +import javax.xml.namespace.QName; +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.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.exception.AuthenticationException; +import at.gv.egovernment.moa.id.auth.exception.BuildException; +import at.gv.egovernment.moa.id.auth.exception.ParseException; +import at.gv.egovernment.moa.id.auth.exception.ServiceException; +import at.gv.egovernment.moa.id.auth.exception.ValidateException; +import at.gv.egovernment.moa.id.auth.parser.SAMLArtifactParser; +import at.gv.egovernment.moa.id.auth.validator.parep.ParepUtils; +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.config.auth.data.SAML1ConfigurationParameters; +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.id.util.IdentityLinkReSigner; +import at.gv.egovernment.moa.id.util.Random; +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.MiscUtil; +import at.gv.egovernment.moa.util.StringUtils; +import at.gv.util.xsd.persondata.IdentificationType; +import at.gv.util.xsd.persondata.IdentificationType.Value; +import at.gv.util.xsd.persondata.PersonNameType; +import at.gv.util.xsd.persondata.PersonNameType.FamilyName; +import at.gv.util.xsd.persondata.PhysicalPersonType; + +public class SAML1AuthenticationServer extends AuthenticationServer { + + private static SAML1AuthenticationServer instance; + + public static SAML1AuthenticationServer getInstace() { + if (instance == null) + instance = new SAML1AuthenticationServer(); + + return instance; + } + + private static AssertionStorage authenticationDataStore = AssertionStorage.getInstance(); + + + /** + * 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 AuthenticationData indexed by the SAML artifact. + * The AuthenticationData is deleted from the store upon end of + * this call. + * + * @return AuthenticationData + */ + public String getSaml1AuthenticationData(String samlArtifact) + throws AuthenticationException { + try { + new SAMLArtifactParser(samlArtifact).parseAssertionHandle(); + + } catch (ParseException ex) { + throw new AuthenticationException("1205", new Object[] { + samlArtifact, ex.toString() }); + } + String authData = null; + synchronized (authenticationDataStore) { + // System.out.println("assertionHandle: " + assertionHandle); + + try { + authData = authenticationDataStore + .get(samlArtifact, String.class, authDataTimeOut); + + } catch (MOADatabaseException e) { + Logger.error("Assertion not found for SAML Artifact: " + samlArtifact); + throw new AuthenticationException("1206", new Object[] { samlArtifact }); + } + } + + authenticationDataStore.remove(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(OAAuthParameter oaParam, + SAML1AuthenticationData authData, String sourceID) + throws ConfigurationException, BuildException, AuthenticationException { + + //Load SAML1 Parameter from OA config + SAML1ConfigurationParameters saml1parameter = oaParam.getSAML1Parameter(); + + boolean useCondition = saml1parameter.isUseCondition(); + int conditionLength = saml1parameter.getConditionLength(); + + try { + + //set BASE64 encoded signer certificate + String signerCertificateBase64 = ""; + if (saml1parameter.isProvideCertificate()) { + byte[] signerCertificate = authData.getSignerCertificate(); + if (signerCertificate != null) { + + signerCertificateBase64 = Base64Utils + .encode(signerCertificate); + } else { + Logger.info("\"provideCertificate\" is \"true\", but no signer certificate available"); + } + } + + //set prPersion + boolean provideStammzahl = saml1parameter.isProvideStammzahl() + || oaParam.getBusinessService(); + + String prPerson = ""; + String ilAssertion = ""; + if (authData.getIdentityLink() != null) { + prPerson = new PersonDataBuilder().build(authData.getIdentityLink(), + provideStammzahl); + + //set IdentityLink for assortion + if (saml1parameter.isProvideIdentityLink()) { + ilAssertion = authData.getIdentityLink().getSerializedSamlAssertion(); + + if (!provideStammzahl) + ilAssertion = StringUtils.replaceAll(ilAssertion, authData.getIdentityLink() + .getIdentificationValue(), ""); + } + } else { + Logger.info("No IdentityLink available! Build attribute 'PersonDate' from givenname, familyname and dateofbirth. "); + PhysicalPersonType person = new PhysicalPersonType(); + PersonNameType name = new PersonNameType(); + person.setName(name); + FamilyName familyName = new FamilyName(); + name.getFamilyName().add(familyName ); + IdentificationType id = new IdentificationType(); + person.getIdentification().add(id ); + Value value = new Value(); + id.setValue(value ); + + id.setType(authData.getIdentificationType()); + //add baseID if it is requested and available + if ( MiscUtil.isNotEmpty(authData.getIdentificationValue()) && + saml1parameter.isProvideIdentityLink() ) + value.setValue(authData.getIdentificationValue()); + else + value.setValue(""); + + familyName.setValue(authData.getFamilyName()); + familyName.setPrimary("undefined"); + name.getGivenName().add(authData.getGivenName()); + person.setDateOfBirth(authData.getFormatedDateOfBirth()); + + JAXBContext jc = JAXBContext.newInstance("at.gv.util.xsd.persondata"); + Marshaller m = jc.createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); + +// m.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapper() { +// public String getPreferredPrefix(String arg0, String arg1, boolean arg2) { +// if (Constants.PD_NS_URI.equals(arg0)) +// return Constants.PD_PREFIX; +// else +// return arg1; +// } +// }); + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + m.marshal( + new JAXBElement(new QName(Constants.PD_NS_URI,"Person"), PhysicalPersonType.class, person), + stream); + prPerson = StringUtils.removeXMLDeclaration(new String(stream.toByteArray(), "UTF-8")); + stream.close(); + + + + } + + //set Authblock + String authBlock = ""; + if (authData.getAuthBlock() != null) { + authBlock = saml1parameter.isProvideAUTHBlock() ? authData.getAuthBlock() : ""; + + } else { + Logger.info("\"provideAuthBlock\" is \"true\", but no authblock available"); + + } + + String samlAssertion; + if (authData.isUseMandate()) { + List oaAttributes = authData.getExtendedSAMLAttributesOA(); + + //only provide full mandate if it is included. + //In case of federation only a short mandate could be include + if (saml1parameter.isProvideFullMandatorData() + && authData.getMISMandate().isFullMandateIncluded()) { + + try { + + ExtendedSAMLAttribute[] extendedSAMLAttributes = addExtendedSamlAttributes( + authData.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; + case ExtendedSAMLAttribute.ADD_TO_AUTHBLOCK_ONLY: + 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(oaParam, authData); + + samlAssertion = new AuthenticationDataAssertionBuilder().buildMandate( + authData, + prPerson, + mandateDate, + authBlock, + ilAssertion, + authData.getBkuURL(), + signerCertificateBase64, + oaParam.getBusinessService(), + oaAttributes, + useCondition, + conditionLength); + + } else { + samlAssertion = new AuthenticationDataAssertionBuilder().build( + authData, + prPerson, + authBlock, + ilAssertion, + authData.getBkuURL(), + signerCertificateBase64, + oaParam.getBusinessService(), + authData.getExtendedSAMLAttributesOA(), + useCondition, + conditionLength); + } + + //authData.setSamlAssertion(samlAssertion); + + String samlArtifact = new SAMLArtifactBuilder().build( + authData.getIssuer(), Random.nextRandom(), + sourceID); + + storeAuthenticationData(samlArtifact, samlAssertion); + + Logger.info("Anmeldedaten angelegt, SAML Artifakt " + samlArtifact); + return samlArtifact; + + } catch (Throwable ex) { + throw new BuildException("builder.00", new Object[] { + "AuthenticationData", ex.toString() }, ex); + } + + } + + private String generateMandateDate(OAAuthParameter oaParam, AuthenticationData authData + ) throws AuthenticationException, BuildException, + ParseException, ConfigurationException, ServiceException, + ValidateException { + + if (authData == null) + throw new AuthenticationException("auth.10", new Object[] { + REQ_VERIFY_AUTH_BLOCK, PARAM_SESSIONID }); + + IdentityLink tempIdentityLink = null; + + Element mandate = authData.getMandate(); + + if (authData.isUseMandate()) { + 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()) { + if (oaParam.getIdentityLinkDomainIdentifier().startsWith(AuthenticationSession.REGISTERANDORDNR_PREFIX_)) + oatargetType = oaParam.getIdentityLinkDomainIdentifier(); + else + oatargetType = AuthenticationSession.REGISTERANDORDNR_PREFIX_+oaParam.getIdentityLinkDomainIdentifier(); + + } 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, + String samlAssertion) 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, samlAssertion); + } + + } catch (AuthenticationException ex) { + throw ex; + + } catch (Throwable ex) { + throw new AuthenticationException("auth.06", + new Object[] { samlArtifact }); + } + } + +} diff --git a/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1Protocol.java b/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1Protocol.java new file mode 100644 index 000000000..7416dfb00 --- /dev/null +++ b/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1Protocol.java @@ -0,0 +1,226 @@ +/******************************************************************************* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 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: + * http://www.osor.eu/eupl/ + * + * 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.egovernment.moa.id.protocols.saml1; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringEscapeUtils; + +import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants; +import at.gv.egovernment.moa.id.advancedlogging.MOAReversionLogger; +import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; +import at.gv.egovernment.moa.id.auth.exception.InvalidProtocolRequestException; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.auth.exception.ProtocolNotActiveException; +import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; +import at.gv.egovernment.moa.id.auth.servlet.RedirectServlet; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.config.auth.data.SAML1ConfigurationParameters; +import at.gv.egovernment.moa.id.moduls.IAction; +import at.gv.egovernment.moa.id.moduls.IModulInfo; +import at.gv.egovernment.moa.id.moduls.IRequest; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.id.util.ParamValidatorUtils; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; +import at.gv.egovernment.moa.util.URLEncoder; + +public class SAML1Protocol extends MOAIDAuthConstants implements IModulInfo { + + public static final String NAME = SAML1Protocol.class.getName(); + public static final String PATH = "id_saml1"; + + public static final String GETARTIFACT = "GetArtifact"; + + public static final List DEFAULTREQUESTEDATTRFORINTERFEDERATION = Arrays.asList( + new String[] { + PVPConstants.BPK_NAME, + PVPConstants.EID_SECTOR_FOR_IDENTIFIER_NAME, + PVPConstants.GIVEN_NAME_NAME, + PVPConstants.PRINCIPAL_NAME_NAME, + PVPConstants.BIRTHDATE_NAME, + PVPConstants.EID_CCS_URL_NAME, + PVPConstants.EID_CITIZEN_QAA_LEVEL_NAME, + PVPConstants.EID_IDENTITY_LINK_NAME, + PVPConstants.EID_SOURCE_PIN_NAME, + PVPConstants.EID_SOURCE_PIN_TYPE_NAME + }); + + private static HashMap actions = new HashMap(); + + static { + + actions.put(GETARTIFACT, new GetArtifactAction()); + + instance = new SAML1Protocol(); + } + + private static SAML1Protocol instance = null; + + public static SAML1Protocol getInstance() { + if (instance == null) { + instance = new SAML1Protocol(); + } + return instance; + } + + public String getName() { + return NAME; + } + + public String getPath() { + return PATH; + } + + public IRequest preProcess(HttpServletRequest request, + HttpServletResponse response, String action, + String sessionId, String transactionId) throws MOAIDException { + SAML1RequestImpl config = new SAML1RequestImpl(); + + if (!AuthConfigurationProviderFactory.getInstance().getAllowedProtocols().isSAML1Active()) { + Logger.info("SAML1 is deaktivated!"); + throw new ProtocolNotActiveException("auth.22", new Object[] { "SAML 1" }); + + } + + String oaURL = (String) request.getParameter(PARAM_OA); + //oaURL = StringEscapeUtils.escapeHtml(oaURL); + + String target = (String) request.getParameter(PARAM_TARGET); + target = StringEscapeUtils.escapeHtml(target); + + String sourceID = request.getParameter(PARAM_SOURCEID); + sourceID = StringEscapeUtils.escapeHtml(sourceID); + + //the target parameter is used to define the OA in SAML1 standard + if (target != null && target.startsWith("http")) { + oaURL = target; + target = null; + } + + if (MiscUtil.isEmpty(oaURL)) { + Logger.info("Receive SAML1 request with no OA parameter. Authentication STOPPED!"); + throw new WrongParametersException("StartAuthentication", PARAM_OA, + "auth.12"); + + } + + if (!ParamValidatorUtils.isValidOA(oaURL)) + throw new WrongParametersException("StartAuthentication", PARAM_OA, + "auth.12"); + + config.setOAURL(oaURL); + + Logger.info("Dispatch SAML1 Request: OAURL=" + oaURL); + + if (!ParamValidatorUtils.isValidSourceID(sourceID)) + throw new WrongParametersException("StartAuthentication", PARAM_SOURCEID, "auth.12"); + + + //load Target only from OA config + OAAuthParameter oaParam = AuthConfigurationProviderFactory.getInstance() + .getOnlineApplicationParameter(oaURL); + + if (oaParam == null) + throw new InvalidProtocolRequestException("auth.00", + new Object[] { null }); + + SAML1ConfigurationParameters saml1 = oaParam.getSAML1Parameter(); + if (saml1 == null || !(saml1.isIsActive() != null && saml1.isIsActive()) ) { + Logger.info("Online-Application " + oaURL + " can not use SAML1 for authentication."); + throw new InvalidProtocolRequestException("auth.00", + new Object[] { null }); + } + config.setOnlineApplicationConfiguration(oaParam); + config.setSourceID(sourceID); + + MOAReversionLogger.getInstance().logEvent(sessionId, transactionId, MOAIDEventConstants.AUTHPROTOCOL_SAML1_AUTHNREQUEST); + + if (MiscUtil.isNotEmpty(target)) + config.setTarget(target); + + else + config.setTarget(oaParam.getTarget()); + + + return config; + } + + public boolean generateErrorMessage(Throwable e, + HttpServletRequest request, HttpServletResponse response, + IRequest protocolRequest) + throws Throwable{ + + OAAuthParameter oa = AuthConfigurationProviderFactory.getInstance().getOnlineApplicationParameter(protocolRequest.getOAURL()); + if (!oa.getSAML1Parameter().isProvideAllErrors()) + return false; + + else { + SAML1AuthenticationServer saml1authentication = SAML1AuthenticationServer.getInstace(); + String samlArtifactBase64 = saml1authentication.BuildErrorAssertion(e, protocolRequest); + + String url = AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix() + "/RedirectServlet"; + url = addURLParameter(url, RedirectServlet.REDIRCT_PARAM_URL, URLEncoder.encode(protocolRequest.getOAURL(), "UTF-8")); + url = addURLParameter(url, PARAM_SAMLARTIFACT, URLEncoder.encode(samlArtifactBase64, "UTF-8")); + url = response.encodeRedirectURL(url); + + response.setContentType("text/html"); + response.setStatus(302); + response.addHeader("Location", url); + Logger.debug("REDIRECT TO: " + url); + + return true; + } + } + + public IAction getAction(String action) { + return actions.get(action); + } + + public IAction canHandleRequest(HttpServletRequest request, + HttpServletResponse response) { + return null; + } + + public boolean validate(HttpServletRequest request, + HttpServletResponse response, IRequest pending) { + + return true; + } + + protected static String addURLParameter(String url, String paramname, + String paramvalue) { + String param = paramname + "=" + paramvalue; + if (url.indexOf("?") < 0) + return url + "?" + param; + else + return url + "&" + param; + } + +} diff --git a/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1RequestImpl.java b/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1RequestImpl.java new file mode 100644 index 000000000..5370573a7 --- /dev/null +++ b/id/server/modules/moa-id-modules-saml1/src/main/java/at/gv/egovernment/moa/id/protocols/saml1/SAML1RequestImpl.java @@ -0,0 +1,96 @@ +/* + * Copyright 2014 Federal Chancellery Austria + * MOA-ID has been developed in a cooperation between BRZ, the Federal + * Chancellery Austria - ICT staff unit, and Graz University of Technology. + * + * Licensed under the EUPL, Version 1.1 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: + * http://www.osor.eu/eupl/ + * + * 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.egovernment.moa.id.protocols.saml1; + +import java.util.ArrayList; +import java.util.List; + +import org.opensaml.saml2.core.Attribute; + +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.config.auth.data.SAML1ConfigurationParameters; +import at.gv.egovernment.moa.id.moduls.RequestImpl; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.AttributQueryBuilder; +import at.gv.egovernment.moa.logging.Logger; + +/** + * @author tlenz + * + */ +public class SAML1RequestImpl extends RequestImpl { + + private static final long serialVersionUID = -4961979968425683115L; + + private String sourceID = null; + + /** + * @return the sourceID + */ + public String getSourceID() { + return sourceID; + } + + /** + * @param sourceID the sourceID to set + */ + public void setSourceID(String sourceID) { + this.sourceID = sourceID; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.RequestImpl#getRequestedAttributes() + */ + @Override + public List getRequestedAttributes() { + + List reqAttr = new ArrayList(); + reqAttr.addAll(SAML1Protocol.DEFAULTREQUESTEDATTRFORINTERFEDERATION); + + try { + OAAuthParameter oa = AuthConfigurationProviderFactory.getInstance().getOnlineApplicationParameter(getOAURL()); + SAML1ConfigurationParameters saml1 = oa.getSAML1Parameter(); + if (saml1 != null) { + if (saml1.isProvideAUTHBlock()) + reqAttr.add(PVPConstants.EID_AUTH_BLOCK_NAME); + + if (saml1.isProvideCertificate()) + reqAttr.add(PVPConstants.EID_SIGNER_CERTIFICATE_NAME); + + if (saml1.isProvideFullMandatorData()) + reqAttr.add(PVPConstants.MANDATE_FULL_MANDATE_NAME); + } + + return AttributQueryBuilder.buildSAML2AttributeList(oa, reqAttr.iterator()); + + } catch (ConfigurationException e) { + Logger.error("Load configuration for OA " + getOAURL() + " FAILED", e); + return null; + } + + + } + +} diff --git a/id/server/modules/moa-id-modules-saml1/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.IModulInfo b/id/server/modules/moa-id-modules-saml1/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.IModulInfo new file mode 100644 index 000000000..5bff0dbc2 --- /dev/null +++ b/id/server/modules/moa-id-modules-saml1/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.IModulInfo @@ -0,0 +1 @@ +at.gv.egovernment.moa.id.protocols.saml1.SAML1Protocol \ No newline at end of file -- cgit v1.2.3