From 101f582d457f3e0bbd42083521360d18168fbd84 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Wed, 24 Feb 2016 06:22:18 +0100 Subject: add federated IDP authentication modul --- .../federatedauth/FederatedAuthConstants.java | 3 + .../FederatedAuthenticationModuleImpl.java | 12 +- .../FederatedAuthnRequestBuilderConfiguration.java | 161 +++++++++++++++ .../FederatedAuthMetadataController.java | 14 +- .../tasks/CreateAuthnRequestTask.java | 220 ++++++++++++++++++++ .../tasks/ReceiveAuthnResponseTask.java | 225 +++++++++++++++++++++ 6 files changed, 630 insertions(+), 5 deletions(-) create mode 100644 id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/config/FederatedAuthnRequestBuilderConfiguration.java create mode 100644 id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/tasks/CreateAuthnRequestTask.java create mode 100644 id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/tasks/ReceiveAuthnResponseTask.java (limited to 'id/server/modules/moa-id-modules-federated_authentication/src/main/java/at') diff --git a/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/FederatedAuthConstants.java b/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/FederatedAuthConstants.java index 97e4c0a20..e2f851132 100644 --- a/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/FederatedAuthConstants.java +++ b/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/FederatedAuthConstants.java @@ -44,4 +44,7 @@ public class FederatedAuthConstants { public static final String CONFIG_PROPS_ENCRYPTION_KEY_PASSWORD = CONFIG_PROPS_PREFIX + "response.encryption.password"; public static final String CONFIG_PROPS_ENCRYPTION_ALIAS_PASSWORD = CONFIG_PROPS_PREFIX + "response.encryption.alias"; + public static final String CONFIG_DEFAULT_QAA_STORK_LEVEL = "http://www.stork.gov.eu/1.0/citizenQAALevel/4"; + public static final String CONFIG_DEFAULT_QAA_SECCLASS_LEVEL = "http://www.ref.gv.at/ns/names/agiz/pvp/secclass/0-3"; + } diff --git a/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/FederatedAuthenticationModuleImpl.java b/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/FederatedAuthenticationModuleImpl.java index 4a610549d..6abc60c46 100644 --- a/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/FederatedAuthenticationModuleImpl.java +++ b/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/FederatedAuthenticationModuleImpl.java @@ -22,6 +22,7 @@ */ package at.gv.egovernment.moa.id.auth.modules.federatedauth; +import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; import at.gv.egovernment.moa.id.auth.modules.AuthModule; import at.gv.egovernment.moa.id.process.api.ExecutionContext; @@ -45,8 +46,15 @@ public class FederatedAuthenticationModuleImpl implements AuthModule { */ @Override public String selectProcess(ExecutionContext context) { - // TODO Auto-generated method stub - return null; + //select interfederation authentication if PERFORM_INTERFEDERATION_AUTH flag is set + Object performfedAuthObj = context.get(MOAIDAuthConstants.PROCESSCONTEXT_PERFORM_INTERFEDERATION_AUTH); + if (performfedAuthObj != null && performfedAuthObj instanceof Boolean) { + if ((boolean) performfedAuthObj) + return "SSOfederationAuthentication"; + + } + + return null; } /* (non-Javadoc) diff --git a/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/config/FederatedAuthnRequestBuilderConfiguration.java b/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/config/FederatedAuthnRequestBuilderConfiguration.java new file mode 100644 index 000000000..eca5c7649 --- /dev/null +++ b/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/config/FederatedAuthnRequestBuilderConfiguration.java @@ -0,0 +1,161 @@ +/* + * 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.modules.federatedauth.config; + +import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration; +import org.opensaml.saml2.core.NameID; +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.xml.security.credential.Credential; + +import at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPAuthnRequestBuilderConfiguruation; + +/** + * @author tlenz + * + */ +public class FederatedAuthnRequestBuilderConfiguration implements IPVPAuthnRequestBuilderConfiguruation { + + private boolean isPassive; + private String SPEntityID; + private String QAA_Level; + private EntityDescriptor idpEntity; + private Credential signCred; + + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPAuthnRequestBuilderConfiguruation#isPassivRequest() + */ + @Override + public Boolean isPassivRequest() { + return this.isPassive; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPAuthnRequestBuilderConfiguruation#getAssertionConsumerServiceId() + */ + @Override + public Integer getAssertionConsumerServiceId() { + return 0; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPAuthnRequestBuilderConfiguruation#getEntityID() + */ + @Override + public String getSPEntityID() { + return this.SPEntityID; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPAuthnRequestBuilderConfiguruation#getNameIDPolicy() + */ + @Override + public String getNameIDPolicyFormat() { + return NameID.TRANSIENT; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPAuthnRequestBuilderConfiguruation#getNameIDPolicy() + */ + @Override + public boolean getNameIDPolicyAllowCreation() { + return true; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPAuthnRequestBuilderConfiguruation#getAuthnContextClassRef() + */ + @Override + public String getAuthnContextClassRef() { + return this.QAA_Level; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPAuthnRequestBuilderConfiguruation#getAuthnContextComparison() + */ + @Override + public AuthnContextComparisonTypeEnumeration getAuthnContextComparison() { + return AuthnContextComparisonTypeEnumeration.MINIMUM; + } + + /** + * @param isPassive the isPassive to set + */ + public void setPassive(boolean isPassive) { + this.isPassive = isPassive; + } + + /** + * @param sPEntityID the sPEntityID to set + */ + public void setSPEntityID(String sPEntityID) { + SPEntityID = sPEntityID; + } + + /** + * @param qAA_Level the qAA_Level to set + */ + public void setQAA_Level(String qAA_Level) { + QAA_Level = qAA_Level; + } + + /** + * @param idpEntity the idpEntity to set + */ + public void setIdpEntity(EntityDescriptor idpEntity) { + this.idpEntity = idpEntity; + } + + /** + * @param signCred the signCred to set + */ + public void setSignCred(Credential signCred) { + this.signCred = signCred; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPAuthnRequestBuilderConfiguruation#getAuthnRequestSigningCredential() + */ + @Override + public Credential getAuthnRequestSigningCredential() { + return this.signCred; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPAuthnRequestBuilderConfiguruation#getIDPEntityDescriptor() + */ + @Override + public EntityDescriptor getIDPEntityDescriptor() { + return this.idpEntity; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPAuthnRequestBuilderConfiguruation#getSubjectNameID() + */ + @Override + public String getSubjectNameID() { + return null; + } + + +} diff --git a/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/controller/FederatedAuthMetadataController.java b/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/controller/FederatedAuthMetadataController.java index d41a25a10..c06800079 100644 --- a/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/controller/FederatedAuthMetadataController.java +++ b/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/controller/FederatedAuthMetadataController.java @@ -33,9 +33,12 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import at.gv.egovernment.moa.id.auth.modules.federatedauth.FederatedAuthConstants; -import at.gv.egovernment.moa.id.auth.modules.federatedauth.builder.FederatedAuthMetadataBuilder; +import at.gv.egovernment.moa.id.auth.modules.federatedauth.config.FederatedAuthMetadataConfiguration; +import at.gv.egovernment.moa.id.auth.modules.federatedauth.utils.FederatedAuthCredentialProvider; import at.gv.egovernment.moa.id.auth.servlet.AbstractController; import at.gv.egovernment.moa.id.config.auth.AuthConfiguration; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.PVPMetadataBuilder; +import at.gv.egovernment.moa.id.protocols.pvp2x.config.IPVPMetadataBuilderConfiguration; import at.gv.egovernment.moa.id.util.HTTPUtils; import at.gv.egovernment.moa.logging.Logger; @@ -46,8 +49,9 @@ import at.gv.egovernment.moa.logging.Logger; @Controller public class FederatedAuthMetadataController extends AbstractController { - @Autowired FederatedAuthMetadataBuilder metadatabuilder; + @Autowired PVPMetadataBuilder metadatabuilder; @Autowired AuthConfiguration authConfig; + @Autowired FederatedAuthCredentialProvider credentialProvider; public FederatedAuthMetadataController() { super(); @@ -68,8 +72,12 @@ public class FederatedAuthMetadataController extends AbstractController { return; } else { + //initialize metadata builder configuration + IPVPMetadataBuilderConfiguration metadataConfig = + new FederatedAuthMetadataConfiguration(authURL, credentialProvider); + //build metadata - String xmlMetadata = metadatabuilder.buildPVPMetadata(authURL); + String xmlMetadata = metadatabuilder.buildPVPMetadata(metadataConfig); //write response resp.setContentType("text/xml"); diff --git a/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/tasks/CreateAuthnRequestTask.java b/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/tasks/CreateAuthnRequestTask.java new file mode 100644 index 000000000..2e134713b --- /dev/null +++ b/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/tasks/CreateAuthnRequestTask.java @@ -0,0 +1,220 @@ +/* + * 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.modules.federatedauth.tasks; + +import java.lang.reflect.InvocationTargetException; +import java.security.NoSuchAlgorithmException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.opensaml.saml2.metadata.EntityDescriptor; +import org.opensaml.saml2.metadata.provider.MetadataProviderException; +import org.opensaml.ws.message.encoder.MessageEncodingException; +import org.opensaml.xml.security.SecurityException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; +import at.gv.egovernment.moa.id.auth.modules.TaskExecutionException; +import at.gv.egovernment.moa.id.auth.modules.federatedauth.FederatedAuthConstants; +import at.gv.egovernment.moa.id.auth.modules.federatedauth.config.FederatedAuthnRequestBuilderConfiguration; +import at.gv.egovernment.moa.id.auth.modules.federatedauth.utils.FederatedAuthCredentialProvider; +import at.gv.egovernment.moa.id.config.auth.IOAAuthParameters; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.moduls.RequestImpl; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.PVPAuthnRequestBuilder; +import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AuthnRequestBuildException; +import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider; +import at.gv.egovernment.moa.id.util.PVPtoSTORKMapper; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; + +/** + * @author tlenz + * + */ +@Component("CreateFederatedAuthnRequestTask") +public class CreateAuthnRequestTask extends AbstractAuthServletTask { + + @Autowired PVPAuthnRequestBuilder authnReqBuilder; + @Autowired FederatedAuthCredentialProvider credential; + + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask#execute(at.gv.egovernment.moa.id.process.api.ExecutionContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) + throws TaskExecutionException { + try{ + // get IDP entityID + String idpEntityID = pendingReq.getGenericData(RequestImpl.DATAID_INTERFEDERATIOIDP_URL, String.class); + + if (MiscUtil.isEmpty(idpEntityID)) { + Logger.info("Interfederation not possible -> not inderfederation IDP EntityID found!"); + throw new TaskExecutionException(pendingReq, "Interfederation not possible", new MOAIDException("No inderfederation-IDP EntityID found.", null)); + + } + + //load IDP configuration from MOA-ID Configuration + OAAuthParameter idpConfig = authConfig.getOnlineApplicationParameter(idpEntityID); + //validate IDP + if (!idpConfig.isInderfederationIDP() || !idpConfig.isInboundSSOInterfederationAllowed()) { + Logger.info("Requested interfederation IDP " + idpEntityID + " is not valid for interfederation."); + Logger.debug("isInderfederationIDP:" + String.valueOf(idpConfig.isInderfederationIDP()) + + " isInboundSSOAllowed:" + String.valueOf(idpConfig.isInboundSSOInterfederationAllowed())); + + handleAuthnRequestBuildProblem(executionContext, idpConfig, "sp.pvp2.01", new Object[]{idpEntityID}); + + return; + + } + + //load IDP SAML2 entitydescriptor + EntityDescriptor idpEntity = MOAMetadataProvider.getInstance(). + getEntityDescriptor(idpEntityID); + if (idpEntity == null) { + Logger.warn("Requested IDP " + idpEntityID + + " has no valid metadata or metadata is not found"); + + handleAuthnRequestBuildProblem(executionContext, idpConfig, "sp.pvp2.02", new Object[]{idpEntityID}); + return; + + } + + //setup AuthnRequestBuilder configuration + FederatedAuthnRequestBuilderConfiguration authnReqConfig = new FederatedAuthnRequestBuilderConfiguration(); + authnReqConfig.setIdpEntity(idpEntity); + authnReqConfig.setPassive(idpConfig.isPassivRequestUsedForInterfederation()); + authnReqConfig.setSignCred(credential.getIDPAssertionSigningCredential()); + authnReqConfig.setSPEntityID(pendingReq.getAuthURL() + FederatedAuthConstants.ENDPOINT_METADATA); + authnReqConfig.setQAA_Level(evaluateRequiredQAALevel()); + + //build and transmit AuthnRequest + authnReqBuilder.buildAuthnRequest(pendingReq, authnReqConfig , response); + + } catch (MOAIDException | MetadataProviderException e) { + throw new TaskExecutionException(pendingReq, "Build PVP2.1 AuthnRequest for SSO inderfederation FAILED.", e); + + } catch (MessageEncodingException | NoSuchAlgorithmException | SecurityException e) { + Logger.error("Build PVP2.1 AuthnRequest for SSO inderfederation FAILED", e); + throw new TaskExecutionException(pendingReq, e.getMessage(), e); + + } catch (Exception e) { + Logger.error("Build PVP2.1 AuthnRequest for SSO inderfederation FAILED", e); + throw new TaskExecutionException(pendingReq, e.getMessage(), e); + + } + } + + /** + * @param executionContext + * @param idpConfig + * @param message + * @param objects + * @throws AuthnRequestBuildException + */ + private void handleAuthnRequestBuildProblem(ExecutionContext executionContext, OAAuthParameter idpConfig, String msgCode, Object[] objects) throws AuthnRequestBuildException { + + if (idpConfig.isPerformLocalAuthenticationOnInterfederationError()) { + Logger.info("Switch to local authentication on this IDP ... "); + + executionContext.put(MOAIDAuthConstants.PROCESSCONTEXT_REQUIRELOCALAUTHENTICATION, true); + executionContext.put(MOAIDAuthConstants.PROCESSCONTEXT_PERFORM_BKUSELECTION, true); + + executionContext.remove(MOAIDAuthConstants.PROCESSCONTEXT_PERFORM_INTERFEDERATION_AUTH); + + } else { + throw new AuthnRequestBuildException(msgCode, objects); + + } + + } + + private String evaluateRequiredQAALevel() { + IOAAuthParameters sp = pendingReq.getOnlineApplicationConfiguration(); + + //check if STORK protocol module is in ClassPath + Object storkRequst = null; + Integer storkSecClass = null; + try { + storkRequst = Class.forName("at.gv.egovernment.moa.id.protocols.stork2.MOASTORKRequest").newInstance(); + if (storkRequst != null && + pendingReq.getClass().isInstance(storkRequst)) { + Object storkAuthnRequest = pendingReq.getClass().getMethod("getStorkAuthnRequest", null).invoke(pendingReq, null); + storkSecClass = (Integer) storkAuthnRequest.getClass().getMethod("getQaa", null).invoke(storkAuthnRequest, null); + + } + + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | java.lang.SecurityException ex) { + + + } + + if (sp != null && sp.isSTORKPVPGateway()){ + //use PVP SecClass instead of STORK QAA level + String secClass = null; + if (storkRequst != null && + pendingReq.getClass().isInstance(storkRequst)) { + + try { + secClass = PVPtoSTORKMapper.getInstance().mapToSecClass( + PVPConstants.STORK_QAA_PREFIX + String.valueOf(storkSecClass)); + + } catch (Exception e) { + Logger.warn("STORK-QAA level can not read from STORK request. Use default QAA 4", e); + + } + } + + if (MiscUtil.isNotEmpty(secClass)) + return secClass; + else + return FederatedAuthConstants.CONFIG_DEFAULT_QAA_SECCLASS_LEVEL; + + } else { + if (storkRequst != null && pendingReq.getClass().isInstance(storkRequst)) { + //use requested QAA level from STORK request + try { + String qaaLevel = PVPConstants.STORK_QAA_PREFIX + String.valueOf(storkSecClass); + Logger.debug("Use STORK-QAA level " + qaaLevel + " from STORK request"); + return qaaLevel; + + + } catch (Exception e) { + Logger.warn("Read STORK-QAA level FAILED with an exception.", e); + + } + } + Logger.warn("STORK-QAA level can not read from STORK request. Use default QAA 4"); + return FederatedAuthConstants.CONFIG_DEFAULT_QAA_STORK_LEVEL; + + } + } + +} diff --git a/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/tasks/ReceiveAuthnResponseTask.java b/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/tasks/ReceiveAuthnResponseTask.java new file mode 100644 index 000000000..49f9782ae --- /dev/null +++ b/id/server/modules/moa-id-modules-federated_authentication/src/main/java/at/gv/egovernment/moa/id/auth/modules/federatedauth/tasks/ReceiveAuthnResponseTask.java @@ -0,0 +1,225 @@ +/* + * 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.modules.federatedauth.tasks; + +import java.io.IOException; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.transform.TransformerException; + +import org.opensaml.saml2.core.Response; +import org.opensaml.saml2.core.StatusCode; +import org.opensaml.ws.message.decoder.MessageDecodingException; +import org.opensaml.xml.io.MarshallingException; +import org.opensaml.xml.security.SecurityException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants; +import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; +import at.gv.egovernment.moa.id.auth.exception.InvalidProtocolRequestException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; +import at.gv.egovernment.moa.id.auth.modules.TaskExecutionException; +import at.gv.egovernment.moa.id.auth.modules.federatedauth.utils.FederatedAuthCredentialProvider; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.moduls.RequestImpl; +import at.gv.egovernment.moa.id.moduls.SSOManager; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.IDecoder; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.PostBinding; +import at.gv.egovernment.moa.id.protocols.pvp2x.binding.RedirectBinding; +import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AssertionValidationExeption; +import at.gv.egovernment.moa.id.protocols.pvp2x.exceptions.AuthnResponseValidationException; +import at.gv.egovernment.moa.id.protocols.pvp2x.messages.InboundMessage; +import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOAResponse; +import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException; +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.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; + +/** + * @author tlenz + * + */ +@Component("ReceiveFederatedAuthnResponseTask") +public class ReceiveAuthnResponseTask extends AbstractAuthServletTask { + + @Autowired SAMLVerificationEngine samlVerificationEngine; + @Autowired FederatedAuthCredentialProvider credentialProvider; + @Autowired SSOManager ssoManager; + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask#execute(at.gv.egovernment.moa.id.process.api.ExecutionContext, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) + throws TaskExecutionException { + InboundMessage msg = null; + + try { + + IDecoder decoder = null; + //select Response Binding + if (request.getMethod().equalsIgnoreCase("POST")) { + decoder = new PostBinding(); + Logger.trace("Receive PVP Response from federated IDP, by using POST-Binding."); + + } else if (request.getMethod().equalsIgnoreCase("GET")) { + decoder = new RedirectBinding(); + Logger.trace("Receive PVP Response from federated IDP, by using Redirect-Binding."); + + } else { + Logger.warn("Receive PVP Response, but Binding (" + + request.getMethod() + ") is not supported."); + throw new AuthnResponseValidationException("sp.pvp2.03", null); + + } + + //decode PVP response object + msg = (InboundMessage) decoder.decode(request, response, true); + + if (MiscUtil.isEmpty(msg.getEntityID())) { + throw new InvalidProtocolRequestException("sp.pvp2.04", new Object[] {}); + + } + + //validate response signature + if(!msg.isVerified()) { + samlVerificationEngine.verify(msg, TrustEngineFactory.getSignatureKnownKeysTrustEngine()); + msg.setVerified(true); + + } + + revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROTOCOL_PVP_REQUEST_AUTHRESPONSE); + + //validate assertion + MOAResponse processedMsg = preProcessAuthResponse((MOAResponse) msg); + + //store valid assertion into pending-request + pendingReq.setGenericDataToSession(RequestImpl.DATAID_INTERFEDERATIOIDP_RESPONSE, processedMsg); + + //update MOASession with federation information + authenticatedSessionStorage.createInterfederatedSession(pendingReq, true); + + //store pending-request + requestStoreage.storePendingRequest(pendingReq); + + //write log entries + revisionsLogger.logEvent(pendingReq, MOAIDEventConstants.AUTHPROCESS_INTERFEDERATION_REVEIVED); + Logger.info("Receive a valid assertion from IDP " + msg.getEntityID()); + + } catch (MessageDecodingException | SecurityException e) { + String samlRequest = request.getParameter("SAMLRequest"); + Logger.warn("Receive INVALID PVP Response from federated IDP: " + samlRequest, e); + throw new TaskExecutionException(pendingReq, "Receive INVALID PVP Response from federated IDP", e); + + } catch (IOException | MarshallingException | TransformerException e) { + Logger.warn("Processing PVP response from federated IDP FAILED.", e); + throw new TaskExecutionException(pendingReq, "Processing PVP response from federated IDP FAILED.", e); + + } catch (CredentialsNotAvailableException e) { + Logger.error("PVP response decrytion FAILED. No credential found.", e); + throw new TaskExecutionException(pendingReq, "PVP response decrytion FAILED. No credential found.", e); + + } catch (AssertionValidationExeption | AuthnResponseValidationException e) { + Logger.info("PVP response validation FAILED. Msg:" + e.getMessage()); + if (msg != null) { + OAAuthParameter idpConfig = authConfig.getOnlineApplicationParameter(msg.getEntityID()); + + //remove federated IDP from SSO session if exists + ssoManager.removeInterfederatedSSOIDP(msg.getEntityID(), request); + + //select next step + handleAuthnResponseValidationProblem(executionContext, idpConfig, e); + + } else + throw new TaskExecutionException(pendingReq, "PVP response validation FAILED.", e); + + } catch (Exception e) { + + + } + + } + + /** + * @param executionContext + * @param idpConfig + * @param message + * @param objects + * @throws TaskExecutionException + * @throws Throwable + */ + private void handleAuthnResponseValidationProblem(ExecutionContext executionContext, OAAuthParameter idpConfig, Throwable e) throws TaskExecutionException { + + if (idpConfig != null && idpConfig.isPerformLocalAuthenticationOnInterfederationError()) { + Logger.info("Switch to local authentication on this IDP ... "); + + executionContext.put(MOAIDAuthConstants.PROCESSCONTEXT_REQUIRELOCALAUTHENTICATION, true); + executionContext.put(MOAIDAuthConstants.PROCESSCONTEXT_PERFORM_BKUSELECTION, true); + + executionContext.remove(MOAIDAuthConstants.PROCESSCONTEXT_PERFORM_INTERFEDERATION_AUTH); + + } else { + throw new TaskExecutionException(pendingReq, "PVP response validation FAILED.", e); + + } + + } + + /** + * PreProcess AuthResponse and Assertion + * @param msg + * @throws TransformerException + * @throws MarshallingException + * @throws IOException + * @throws CredentialsNotAvailableException + * @throws AssertionValidationExeption + * @throws AuthnResponseValidationException + */ + private MOAResponse preProcessAuthResponse(MOAResponse msg) throws IOException, MarshallingException, TransformerException, AssertionValidationExeption, CredentialsNotAvailableException, AuthnResponseValidationException { + Logger.debug("Start PVP21 assertion processing... "); + Response samlResp = (Response) msg.getResponse(); + + // check SAML2 response status-code + if (samlResp.getStatus().getStatusCode().getValue().equals(StatusCode.SUCCESS_URI)) { + //validate PVP 2.1 assertion + samlVerificationEngine.validateAssertion(samlResp, true, credentialProvider.getIDPAssertionEncryptionCredential()); + + msg.setSAMLMessage(SAML2Utils.asDOMDocument(samlResp).getDocumentElement()); + return msg; + + } else { + Logger.info("Receive StatusCode " + samlResp.getStatus().getStatusCode().getValue() + + " from federated IDP."); + throw new AuthnResponseValidationException("sp.pvp2.04", + new Object[]{samlResp.getIssuer().getValue(), samlResp.getStatus().getStatusCode().getValue()}); + + } + + } + +} -- cgit v1.2.3