/* * 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.internal.tasks; import java.lang.reflect.InvocationTargetException; import java.security.NoSuchAlgorithmException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.joda.time.DateTime; import org.opensaml.common.impl.SecureRandomIdentifierGenerator; import org.opensaml.common.xml.SAMLConstants; import org.opensaml.saml2.core.AuthnContextClassRef; import org.opensaml.saml2.core.AuthnContextComparisonTypeEnumeration; import org.opensaml.saml2.core.AuthnRequest; import org.opensaml.saml2.core.Issuer; import org.opensaml.saml2.core.NameID; import org.opensaml.saml2.core.NameIDPolicy; import org.opensaml.saml2.core.NameIDType; import org.opensaml.saml2.core.RequestedAuthnContext; import org.opensaml.saml2.metadata.EntityDescriptor; import org.opensaml.saml2.metadata.SingleSignOnService; import org.opensaml.saml2.metadata.provider.MetadataProviderException; import org.opensaml.ws.message.encoder.MessageEncodingException; import org.opensaml.xml.security.SecurityException; import org.springframework.stereotype.Service; import at.gv.egovernment.moa.id.advancedlogging.MOAIDEventConstants; 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.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.moduls.IRequest; 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.binding.IEncoder; 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.PVP2Exception; import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider; import at.gv.egovernment.moa.id.protocols.pvp2x.utils.SAML2Utils; import at.gv.egovernment.moa.id.util.PVPtoSTORKMapper; import at.gv.egovernment.moa.logging.Logger; import at.gv.egovernment.moa.util.MiscUtil; /** * @author tlenz * */ @Service("CreateInterfedeartionRequestTask") public class CreateInterfedeartionRequestTask extends AbstractAuthServletTask { /* (non-Javadoc) * @see at.gv.egovernment.moa.id.process.springweb.MoaIdTask#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 { boolean requiredLocalAuthentication = true; IRequest pendingReq = requestStoreage.getPendingRequest( (String) executionContext.get(MOAIDAuthConstants.PARAM_TARGET_PENDINGREQUESTID)); String idpEntityID = (String) executionContext.get(MOAIDAuthConstants.PROCESSCONTEXT_INTERFEDERATION_ENTITYID); if (MiscUtil.isEmpty(idpEntityID)) { Logger.info("Interfederation not possible -> not inderfederation IDP EntityID found!"); throw new TaskExecutionException("Interfederation not possible", new MOAIDException("No inderfederation-IDP EntityID found.", null)); } //TODO: create MOASession //TODO: set relayState to MOASession //TODO: add support for requested attributes (from context and from metadata) try { OAAuthParameter idp = AuthConfigurationProviderFactory.getInstance().getOnlineApplicationParameter(idpEntityID); OAAuthParameter sp = AuthConfigurationProviderFactory.getInstance().getOnlineApplicationParameter(pendingReq.getOAURL()); String requestedIDP = pendingReq.getGenericData(RequestImpl.DATAID_INTERFEDERATIOIDP_URL, String.class); if (!idp.isInderfederationIDP() || !idp.isInboundSSOInterfederationAllowed()) { Logger.info("Requested interfederation IDP " + requestedIDP + " is not valid for interfederation."); Logger.debug("isInderfederationIDP:" + String.valueOf(idp.isInderfederationIDP()) + " isInboundSSOAllowed:" + String.valueOf(idp.isInboundSSOInterfederationAllowed())); Logger.info("Switch to local authentication on this IDP ... "); executionContext.put(MOAIDAuthConstants.PROCESSCONTEXT_REQUIRELOCALAUTHENTICATION, true); return; } EntityDescriptor idpEntity = MOAMetadataProvider.getInstance(). getEntityDescriptor(idpEntityID); if (idpEntity != null ) { //fetch endpoint from IDP metadata SingleSignOnService redirectEndpoint = null; for (SingleSignOnService sss : idpEntity.getIDPSSODescriptor(SAMLConstants.SAML20P_NS).getSingleSignOnServices()) { // use POST binding as default if it exists //TODO: maybe use RedirectBinding as default if (sss.getBinding().equals(SAMLConstants.SAML2_POST_BINDING_URI)) { redirectEndpoint = sss; } else if ( sss.getBinding().equals(SAMLConstants.SAML2_REDIRECT_BINDING_URI) && redirectEndpoint == null ) redirectEndpoint = sss; } if (redirectEndpoint != null) { AuthnRequest authReq = SAML2Utils .createSAMLObject(AuthnRequest.class); SecureRandomIdentifierGenerator gen = new SecureRandomIdentifierGenerator(); authReq.setID(gen.generateIdentifier()); //send passive AuthnRequest authReq.setIsPassive(idp.isPassivRequestUsedForInterfederation()); authReq.setAssertionConsumerServiceIndex(0); authReq.setIssueInstant(new DateTime()); Issuer issuer = SAML2Utils.createSAMLObject(Issuer.class); issuer.setValue(pendingReq.getAuthURLWithOutSlash()); issuer.setFormat(NameIDType.ENTITY); authReq.setIssuer(issuer); NameIDPolicy policy = SAML2Utils .createSAMLObject(NameIDPolicy.class); policy.setAllowCreate(true); policy.setFormat(NameID.TRANSIENT); authReq.setNameIDPolicy(policy); authReq.setDestination(redirectEndpoint.getLocation()); RequestedAuthnContext reqAuthContext = SAML2Utils.createSAMLObject(RequestedAuthnContext.class); AuthnContextClassRef authnClassRef = SAML2Utils.createSAMLObject(AuthnContextClassRef.class); //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)) authnClassRef.setAuthnContextClassRef(secClass); else authnClassRef.setAuthnContextClassRef("http://www.ref.gv.at/ns/names/agiz/pvp/secclass/0-3"); } else { if (storkRequst != null && pendingReq.getClass().isInstance(storkRequst)) { //use requested QAA level from STORK request try { authnClassRef.setAuthnContextClassRef( PVPConstants.STORK_QAA_PREFIX + String.valueOf(storkSecClass)); Logger.debug("Use STORK-QAA level " + authnClassRef.getAuthnContextClassRef() + " from STORK request"); } catch (Exception e) { Logger.warn("STORK-QAA level can not read from STORK request. Use default QAA 4", e); } } if (MiscUtil.isEmpty(authnClassRef.getAuthnContextClassRef())) authnClassRef.setAuthnContextClassRef("http://www.stork.gov.eu/1.0/citizenQAALevel/4"); } reqAuthContext.setComparison(AuthnContextComparisonTypeEnumeration.MINIMUM); reqAuthContext.getAuthnContextClassRefs().add(authnClassRef); authReq.setRequestedAuthnContext(reqAuthContext); IEncoder binding = null; if (redirectEndpoint.getBinding().equals( SAMLConstants.SAML2_REDIRECT_BINDING_URI)) { binding = new RedirectBinding(); } else if (redirectEndpoint.getBinding().equals( SAMLConstants.SAML2_POST_BINDING_URI)) { binding = new PostBinding(); } binding.encodeRequest(request, response, authReq, redirectEndpoint.getLocation(), pendingReq.getRequestID()); //build and send request without an error requiredLocalAuthentication = false; revisionsLogger.logEvent(pendingReq.getOnlineApplicationConfiguration(), pendingReq, MOAIDEventConstants.AUTHPROCESS_INTERFEDERATION_IDP, idpEntity.getEntityID()); } else { Logger.warn("Requested IDP " + requestedIDP + " does not support POST or Redirect Binding."); } } else { Logger.warn("Requested IDP " + requestedIDP + " is not found in InterFederation configuration"); } } catch (MetadataProviderException e) { Logger.error("IDP metadata error." , e); } catch (NoSuchAlgorithmException e) { Logger.error("Build IDP authentication request FAILED.", e); } catch (MessageEncodingException e) { Logger.error("Build IDP authentication request FAILED.", e); } catch (SecurityException e) { Logger.error("Build IDP authentication request FAILED.", e); } catch (PVP2Exception e) { Logger.error("Build IDP authentication request FAILED.", e); } catch (ConfigurationException e1) { Logger.error("Build IDP authentication request FAILED.", e1); } //set flag for next step executionContext.put(MOAIDAuthConstants.PROCESSCONTEXT_REQUIRELOCALAUTHENTICATION, requiredLocalAuthentication); } }