/******************************************************************************* * 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.eidas; import java.io.StringWriter; import java.text.SimpleDateFormat; import java.util.Map.Entry; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.stereotype.Service; import at.gv.egovernment.moa.id.advancedlogging.MOAReversionLogger; import at.gv.egovernment.moa.id.auth.frontend.velocity.VelocityProvider; import at.gv.egovernment.moa.id.auth.modules.eidas.Constants; import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASChainingMetadataProvider; import at.gv.egovernment.moa.id.auth.modules.eidas.engine.MOAeIDASMetadataProviderDecorator; import at.gv.egovernment.moa.id.auth.modules.eidas.utils.MOAPersonalAttributeList; import at.gv.egovernment.moa.id.auth.modules.eidas.utils.SAMLEngineUtils; import at.gv.egovernment.moa.id.commons.api.IRequest; import at.gv.egovernment.moa.id.commons.api.exceptions.MOAIDException; import at.gv.egovernment.moa.id.data.IAuthData; import at.gv.egovernment.moa.id.data.SLOInformationInterface; import at.gv.egovernment.moa.id.moduls.IAction; import at.gv.egovernment.moa.logging.Logger; import eu.eidas.auth.commons.EIDASAuthnResponse; import eu.eidas.auth.commons.EIDASStatusCode; import eu.eidas.auth.commons.EIDASUtil; import eu.eidas.auth.commons.PersonalAttribute; import eu.eidas.auth.engine.EIDASSAMLEngine; import eu.eidas.auth.engine.metadata.MetadataUtil; /** * Second request step - after authentication of the user is done and moasession obtained, * process request and forward the user further to PEPS and/or other entities * * @author tlenz */ @Service("eIDASAuthenticationRequest") public class eIDASAuthenticationRequest implements IAction { @Autowired protected MOAReversionLogger revisionsLogger; @Autowired(required=true) MOAeIDASChainingMetadataProvider eIDASMetadataProvider; @Override public SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp, IAuthData authData) throws MOAIDException { EIDASData eidasRequest; if(req instanceof EIDASData) eidasRequest = (EIDASData) req; else throw new MOAIDException("got wrong IRequest type. is: {}, should be: {}", new String[] {req.getClass().toString(), EIDASData.class.toString()}); // gather attributes MOAPersonalAttributeList resultingAttributeList = (MOAPersonalAttributeList) eidasRequest.getEidasRequestedAttributes().clone(); for(Entry current : resultingAttributeList.entrySet()) { String newValue = ""; // TODO make use of proper builder switch(current.getKey()) { case Constants.eIDAS_ATTR_DATEOFBIRTH: newValue = new SimpleDateFormat("YYYY-MM-dd").format(authData.getDateOfBirth()); break; case Constants.eIDAS_ATTR_CURRENTFAMILYNAME: newValue = authData.getFamilyName();break; case Constants.eIDAS_ATTR_CURRENTGIVENNAME: newValue = authData.getGivenName();break; //TODO: change bPK builder !!!!!! case Constants.eIDAS_ATTR_PERSONALIDENTIFIER: newValue = authData.getBPK(); break; } if("".equals(newValue)) current.getValue().setStatus(EIDASStatusCode.STATUS_NOT_AVAILABLE.toString()); else { current.getValue().getValue().clear(); current.getValue().getValue().add(newValue); current.getValue().setStatus(EIDASStatusCode.STATUS_AVAILABLE.toString()); } } // construct eIDaS response EIDASAuthnResponse response = new EIDASAuthnResponse(); response.setPersonalAttributeList(resultingAttributeList); // - create metadata url String pubURLPrefix = req.getAuthURL(); String metadata_url = pubURLPrefix + Constants.eIDAS_HTTP_ENDPOINT_METADATA; response.setIssuer(metadata_url); response.setAssuranceLevel(authData.getEIDASQAALevel()); String token = null; try { EIDASSAMLEngine engine = SAMLEngineUtils.createSAMLEngine(eIDASMetadataProvider); // encryption is done by the SamlEngine, i.e. by the module we provide in the config // but we need to set the appropriate request issuer engine.setRequestIssuer(eidasRequest.getEidasRequest().getIssuer()); if(null == eidasRequest.getEidasRequest().getAssertionConsumerServiceURL()) { String assertionConsumerUrl = MetadataUtil.getAssertionUrlFromMetadata( new MOAeIDASMetadataProviderDecorator(eIDASMetadataProvider), engine, eidasRequest.getEidasRequest()); eidasRequest.getEidasRequest().setAssertionConsumerServiceURL(assertionConsumerUrl); } response = engine.generateEIDASAuthnResponse(eidasRequest.getEidasRequest(), response, eidasRequest.getRemoteAddress(), true); token = EIDASUtil.encodeSAMLToken(response.getTokenSaml()); } catch(Exception e) { e.printStackTrace(); } revisionsLogger.logEvent(req, Constants.eIDAS_REVERSIONSLOG_IDP_AUTHREQUEST); // send the response try { VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); Template template = velocityEngine.getTemplate("/resources/templates/stork2_postbinding_template.html"); VelocityContext context = new VelocityContext(); context.put("RelayState", eidasRequest.getRemoteRelayState()); context.put("SAMLResponse", token); Logger.debug("SAMLResponse original: " + token); Logger.debug("Putting assertion consumer url as action: " + eidasRequest.getEidasRequest().getAssertionConsumerServiceURL()); context.put("action", eidasRequest.getEidasRequest().getAssertionConsumerServiceURL()); Logger.trace("Starting template merge"); StringWriter writer = new StringWriter(); Logger.trace("Doing template merge"); template.merge(context, writer); Logger.trace("Template merge done"); Logger.trace("Sending html content : " + new String(writer.getBuffer())); httpResp.getOutputStream().write(writer.getBuffer().toString().getBytes("UTF-8")); httpResp.setContentType(MediaType.TEXT_HTML.getType()); } catch (Exception e) { Logger.error("Velocity error: " + e.getMessage()); } return null; } @Override public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) { return true; } @Override public String getDefaultActionName() { return "eIDAS_AuthnRequest"; } }