/* * 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.egiz.eaaf.core.api.data.ILoALevelMapper; import at.gv.egiz.eaaf.core.api.idp.process.ExecutionContext; import at.gv.egiz.eaaf.core.exceptions.TaskExecutionException; import at.gv.egiz.eaaf.core.impl.idp.auth.modules.AbstractAuthServletTask; import at.gv.egiz.eaaf.modules.pvp2.sp.exception.AuthnRequestBuildException; import at.gv.egiz.eaaf.modules.pvp2.sp.impl.PVPAuthnRequestBuilder; 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.commons.MOAIDAuthConstants; import at.gv.egovernment.moa.id.commons.api.IOAAuthParameters; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; import at.gv.egovernment.moa.id.moduls.SSOManager; import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider; 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; @Autowired(required=true) MOAMetadataProvider metadataProvider; @Autowired(required=true) ILoALevelMapper loaMapper; /* (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.getRawData(SSOManager.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 IOAAuthParameters idpConfig = authConfig.getServiceProviderConfiguration(idpEntityID, IOAAuthParameters.class); //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[]{FederatedAuthConstants.MODULE_NAME_FOR_LOGGING, idpEntityID}); return; } //load IDP SAML2 entitydescriptor EntityDescriptor idpEntity = metadataProvider. 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[]{FederatedAuthConstants.MODULE_NAME_FOR_LOGGING, 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 (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, IOAAuthParameters 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.getServiceProviderConfiguration(IOAAuthParameters.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 = loaMapper.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; } } }