diff options
Diffstat (limited to 'id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AuthenticationRequest.java')
-rw-r--r-- | id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AuthenticationRequest.java | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AuthenticationRequest.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AuthenticationRequest.java new file mode 100644 index 000000000..59db5797d --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AuthenticationRequest.java @@ -0,0 +1,531 @@ +/******************************************************************************* + * 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.stork2; + +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; +import at.gv.egovernment.moa.id.config.auth.IOAAuthParameters; +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.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.id.storage.AssertionStorage; +import at.gv.egovernment.moa.id.util.VelocityProvider; +import at.gv.egovernment.moa.id.util.client.mis.simple.MISMandate; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; +import eu.stork.peps.auth.commons.*; +import eu.stork.peps.auth.engine.STORKSAMLEngine; +import eu.stork.peps.exceptions.STORKSAMLEngineException; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.runtime.RuntimeConstants; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.StringWriter; +import java.net.MalformedURLException; +import java.net.URL; + + +/** + * 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 bsuzic + */ + +public class AuthenticationRequest implements IAction { + + + private VelocityEngine velocityEngine; + private MOASTORKRequest moaStorkRequest = null; + + + public SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp, IAuthData authData) throws MOAIDException { + + if ((req instanceof MOASTORKRequest)) { // && ( ((MOASTORKRequest) req).getCitizenCountryCode() == null || ((MOASTORKRequest) req).getCitizenCountryCode().equals("AT") )) { + + this.moaStorkRequest = (MOASTORKRequest) req; + + Logger.debug("Entering MOASTORKRequest"); + httpResp.reset(); + + //TODO: CHECK: req.getOAURL() should return the unique OA identifier + OAAuthParameter oaParam = AuthConfigurationProviderFactory.getInstance().getOnlineApplicationParameter(req.getOAURL()); + if (oaParam == null) + throw new AuthenticationException("stork.12", new Object[]{req.getOAURL()}); + + MOASTORKResponse moaStorkResponse = new MOASTORKResponse(); + + // check if it is attribute query + if (moaStorkRequest.isAttrRequest()) { + Logger.debug("Starting AttrQueryRequest"); + + moaStorkResponse.setSTORKAttrResponse(new STORKAttrQueryResponse()); + } + // check if we have authentication request + else if (moaStorkRequest.isAuthnRequest()) { + Logger.debug("Starting AuthenticationRequest"); + moaStorkResponse.setSTORKAuthnResponse(new STORKAuthnResponse()); + + //STORKSAMLEngine engine = STORKSAMLEngine.getInstance("VIDP"); + + // Logger.debug("Starting generation of SAML response"); + // try { + // moaStorkResponse.setSTORKAuthnResponse(engine.generateSTORKAuthnResponse(moaStorkRequest.getStorkAuthnRequest(), moaStorkResponse.getStorkAuthnResponse(), httpReq.getRemoteAddr(), false)); + // } catch (STORKSAMLEngineException ex) { + // Logger.error("Failed to generate STORK SAML Response", ex); + // throw new MOAIDException("stork.05", null); // TODO + // } + + // Get personal attributtes from MOA/IdentityLink + + //build STORK attributes from local authentication information + if (authData != null) { + int reqQaa = -1; + int authQaa = -1; + try { + reqQaa = moaStorkRequest.getStorkAuthnRequest().getQaa(); + authQaa = Integer.valueOf( + authData.getQAALevel().substring(PVPConstants.STORK_QAA_PREFIX.length())); + + if (reqQaa > authQaa) { + Logger.warn("Requested QAA level does not match to authenticated QAA level"); + throw new MOAIDException("stork.21", new Object[]{reqQaa, authQaa}); + + } + + } catch (MOAIDException e) { + throw e; + + } catch (Exception e) { + if (Logger.isDebugEnabled()) + Logger.warn("STORK QAA Level evaluation error", e); + + else + Logger.warn("STORK QAA Level evaluation error (ErrorMessage=" + + e.getMessage() + ")"); + + throw new MOAIDException("stork.21", new Object[]{reqQaa, authQaa}); + + } + + moaStorkResponse.setPersonalAttributeList(populateAttributes(authData, oaParam)); + + } + } + + //moaStorkResponse.setCountry(moaStorkRequest.getSpCountry()); + + // Prepare extended attributes + Logger.debug("Preparing data container"); + + // create fresh container + DataContainer container = new DataContainer(); + + // - fill in the request we extracted above + container.setRequest(moaStorkRequest); + + // - fill in the partial response created above + container.setResponse(moaStorkResponse); + + container.setRemoteAddress(httpReq.getRemoteAddr()); + + Logger.debug("Data container prepared"); + + if(oaParam.isRequireConsentForStorkAttributes()) + new ConsentEvaluator().requestConsent(container, httpReq, httpResp, authData, oaParam); + else + new AttributeCollector().processRequest(container, httpReq, httpResp, authData, oaParam); + + return null; + } +// // check if we are getting request for citizen of some other country +// else if (req instanceof MOASTORKRequest) { +// return handleMOAStorkRequest("VIDP", (MOASTORKRequest) req, httpReq.getRemoteAddr(), httpResp); +// } + + // Check if we got the response from PEPS + // If so then process it and forward to SP + else if ((req instanceof MOASTORKResponse)) { + return handleMOAStorkResponse("VIDP", (MOASTORKResponse) req, httpReq.getRemoteAddr(), httpResp); + } else { + Logger.error("Could not recognize request."); + throw new MOAIDException("stork.15", null); + } + } + + /* + Handles STORKAuthnRequeste received for citizens of other countries + */ + private SLOInformationInterface handleMOAStorkRequest(String instanceName, MOASTORKRequest moastorkRequest, String remoteAddr, HttpServletResponse httpResp) throws MOAIDException { + + STORKAuthnRequest spAuthnRequest = moastorkRequest.getStorkAuthnRequest(); + STORKAuthnRequest storkAuthnRequest = null; + + String citizenCountryCode = spAuthnRequest.getCitizenCountryCode(); + Logger.info("Got authentication request for citizen of " + citizenCountryCode); + + try { + storkAuthnRequest = (STORKAuthnRequest) spAuthnRequest.clone(); + } catch (CloneNotSupportedException e) { + Logger.error("Could not clone AuthnRequest ", e); + throw new MOAIDException("stork.05", null); // TODO + } + + //TODO: in case of Single LogOut -> SLO information has to be stored + // check if citizen country is configured in the system + if (!(AuthConfigurationProviderFactory.getInstance().getStorkConfig().getCpepsMap().containsKey(citizenCountryCode))) { + Logger.error("Citizen country PEPS not configured in MOA instance: " + citizenCountryCode); + throw new MOAIDException("stork.05", null); // TODO + } + + // extracting basic settings and adjusting assertion consumer + String issuer = null; + String assertionConsumerURL = null; + String publicURLPrefix = null; + String destinationURL = null; + + try { + issuer = new URL(AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix()).toString(); + destinationURL = AuthConfigurationProviderFactory.getInstance().getStorkConfig().getCPEPS(citizenCountryCode).getPepsURL().toString(); + publicURLPrefix = AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix(); + assertionConsumerURL = publicURLPrefix + "/stork2/SendPEPSAuthnRequest"; + } catch (MalformedURLException ex) { + Logger.error("Wrong PublicURLPrefix setting of MOA instance: " + AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix(), ex); + throw new MOAIDException("stork.05", null); // TODO + } catch (Exception ex) { + Logger.error("Problem with PEPS configuration of MOA instance.", ex); + throw new MOAIDException("stork.05", null); // TODO + } + + + // drop if we do not have publicprefix url configured on the instance + if (publicURLPrefix == null) + throw new AuthenticationException("stork.12", new String[]{"PublicURLPrefix"}); + + // adjusting request + storkAuthnRequest.setEIDCrossBorderShare(spAuthnRequest.isEIDCrossBorderShare()); + storkAuthnRequest.setEIDSectorShare(spAuthnRequest.isEIDSectorShare()); + storkAuthnRequest.setEIDCrossSectorShare(spAuthnRequest.isEIDCrossSectorShare()); + storkAuthnRequest.setCitizenCountryCode(spAuthnRequest.getCitizenCountryCode()); + storkAuthnRequest.setIssuer(issuer); + storkAuthnRequest.setAssertionConsumerServiceURL(assertionConsumerURL); + storkAuthnRequest.setDestination(destinationURL); + + // regenerate request + try { + //Get SAMLEngine instance + STORKSAMLEngine engine = STORKSAMLEngine.getInstance("VIDP"); + Logger.debug("Starting generation of SAML request"); + storkAuthnRequest = engine.generateSTORKAuthnRequest(storkAuthnRequest); + + //generateSAML Token + Logger.info("SAML response succesfully generated!"); + } catch (STORKSAMLEngineException e) { + Logger.error("Failed to generate STORK SAML Response", e); + throw new MOAIDException("stork.05", null); + } + + // store original request from SP in order to be able to extract it in later iteration/response + DataContainer spRequestContainer = new DataContainer(); + spRequestContainer.setRequest(moastorkRequest); + + try { + AssertionStorage.getInstance().put(storkAuthnRequest.getSamlId(), spRequestContainer); + Logger.info("Storing artifactId " + storkAuthnRequest.getSamlId() + " of SP authentication request with id " + spAuthnRequest.getSamlId()); + } catch (MOADatabaseException e) { + e.printStackTrace(); + } + + // preparing redirection for the client + performRedirection("SAMLRequest", destinationURL, storkAuthnRequest.getTokenSaml(), httpResp); + + SLOInformationImpl sloInfo = new SLOInformationImpl(); + sloInfo.setProtocolType(moastorkRequest.requestedModule()); + return sloInfo; + } + + /* + Handles STORKAuthnResponse received from PEPS (return to SP) + */ + private SLOInformationInterface handleMOAStorkResponse(String instanceName, MOASTORKResponse moastorkResponse, String remoteAddr, HttpServletResponse httpResp) throws MOAIDException { + + STORKAuthnResponse authnResponse = null; + + //Get SAMLEngine instance + STORKSAMLEngine engine = STORKSAMLEngine.getInstance(instanceName); + + try { + authnResponse = engine.validateSTORKAuthnResponse(moastorkResponse.getSTORKAuthnResponseToken(), remoteAddr); + } catch (STORKSAMLEngineException ex) { + Logger.error("Unable to validate Stork AuthenticationResponse: " + ex.getMessage()); + throw new MOAIDException("stork.15", null); // TODO + } + + Logger.debug("Requesting artifactId " + authnResponse.getInResponseTo() + " from store."); + + DataContainer dataContainer = null; + try { + dataContainer = AssertionStorage.getInstance().get(authnResponse.getInResponseTo(), DataContainer.class); + } catch (MOADatabaseException e) { + Logger.error("Unable to retrieve datacontainer with reference authentication request. Database exception."); + throw new MOAIDException("stork.15", null); // TODO + } + + // setting new reference request and return url + authnResponse.setInResponseTo(dataContainer.getRequest().getStorkAuthnRequest().getSamlId()); + authnResponse.setAudienceRestriction(dataContainer.getRequest().getAssertionConsumerServiceURL()); + //AudienceRestrictionBuilder audienceRestrictionBuilder = new AudienceRestrictionBuilder(); + //AudienceRestriction audienceRestriction = audienceRestrictionBuilder.buildObject(dataContainer.getRequest().getAssertionConsumerServiceURL(), "localname", "nameprefix"); + + //authnResponse.getAssertions().get(0).getConditions().getAudienceRestrictions().add(audienceRestriction); + + Logger.debug("Starting generation of SAML response"); + try { + authnResponse = engine.generateSTORKAuthnResponse(dataContainer.getRequest().getStorkAuthnRequest(), authnResponse, remoteAddr, false); + } catch (STORKSAMLEngineException e) { + Logger.error("Failed to generate STORK SAML Response", e); + throw new MOAIDException("stork.05", null); // TODO check + } + + Logger.info("SAML response succesfully generated."); + + // preparing redirection for the client + performRedirection("SAMLResponse", dataContainer.getRequest().getAssertionConsumerServiceURL(), authnResponse.getTokenSaml(), httpResp); + + return null; + } + + /* + Perform redirection of the client based on post binding + */ + private void performRedirection(String actionType, String assertionConsumerURL, byte[] tokenSaml, HttpServletResponse httpResp) throws MOAIDException { + Logger.info("Performing redirection, using action type: " + actionType); + + try { + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/stork2_postbinding_template.html"); + VelocityContext context = new VelocityContext(); + + context.put(actionType, PEPSUtil.encodeSAMLToken(tokenSaml)); + Logger.debug("Encoded " + actionType + " original: " + new String(tokenSaml)); + + Logger.debug("Using assertion consumer url as action: " + assertionConsumerURL); + context.put("action", assertionConsumerURL); + + Logger.debug("Starting template merge"); + StringWriter writer = new StringWriter(); + + Logger.debug("Doing template merge"); + template.merge(context, writer); + Logger.debug("Template merge done"); + + Logger.debug("Sending html content: " + writer.getBuffer().toString()); + Logger.debug("Sending html content2 : " + new String(writer.getBuffer())); + + httpResp.getOutputStream().write(writer.getBuffer().toString().getBytes("UTF-8")); + + } catch (IOException e) { + Logger.error("Velocity IO error: " + e.getMessage()); + throw new MOAIDException("stork.15", null); // TODO + } catch (Exception e) { + Logger.error("Velocity general error: " + e.getMessage()); + throw new MOAIDException("stork.15", null); // TODO + } + + } + + public void generatePEPSRedirect(HttpServletResponse httpResp, DataContainer container) throws MOAIDException { + MOASTORKRequest request = container.getRequest(); + MOASTORKResponse response = container.getResponse(); + + Logger.info("generating stork response..."); + + try { + //Get SAMLEngine instance + STORKSAMLEngine engine = STORKSAMLEngine.getInstance("VIDP"); + Logger.debug("Starting generation of SAML response"); + if (response.isAuthnResponse()) + response.setSTORKAuthnResponse(engine.generateSTORKAuthnResponse(request.getStorkAuthnRequest(), response.getStorkAuthnResponse(), container.getRemoteAddress(), false)); + else + response.setSTORKAttrResponse(engine.generateSTORKAttrQueryResponse(request.getStorkAttrQueryRequest(), response.getStorkAttrQueryResponse(), container.getRemoteAddress(), "", false)); + + + //generateSAML Token + Logger.info("SAML response succesfully generated!"); + } catch (STORKSAMLEngineException e) { + Logger.error("Failed to generate STORK SAML Response", e); + throw new MOAIDException("stork.05", null); + } + + // preparing redirection for the client + try { + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/stork2_postbinding_template.html"); + VelocityContext context = new VelocityContext(); + + byte[] blob; + if (request.isAttrRequest()) + blob = response.getStorkAttrQueryResponse().getTokenSaml(); + else + blob = response.getStorkAuthnResponse().getTokenSaml(); + + context.put("SAMLResponse", PEPSUtil.encodeSAMLToken(blob)); + Logger.debug("SAMLResponse original: " + new String(blob)); + + Logger.debug("Putting assertion consumer url as action: " + request.getAssertionConsumerServiceURL()); + context.put("action", request.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: " + writer.getBuffer().toString()); + Logger.trace("Sending html content2 : " + new String(writer.getBuffer())); + + httpResp.getOutputStream().write(writer.getBuffer().toString().getBytes("UTF-8")); + + } catch (Exception e) { + Logger.error("Velocity error: " + e.getMessage()); + } + } + + + public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) { + + //redirect to national PVP IDP infrastructure if special attributes are requested + if (MiscUtil.isEmpty(req.getRequestedIDP()) && req instanceof MOASTORKRequest) + return !STORKPVPUtilits.performAuthenticationOnNationalIDP((MOASTORKRequest) req); + +// // authentication is not needed if we have authentication request from SP for citizen of configured PEPS country +// if (req instanceof MOASTORKRequest) { +// MOASTORKRequest moastorkRequest = (MOASTORKRequest) req; +// if (moastorkRequest.getStorkAuthnRequest() != null) { +// String citizenCountryCode = moastorkRequest.getStorkAuthnRequest().getCitizenCountryCode(); +// // check if citizen country is configured in the system +// try { +// if (AuthConfigurationProvider.getInstance().getStorkConfig().getCpepsMap().containsKey(citizenCountryCode)) { +// return false; +// } +// } catch (MOAIDException e) { +// Logger.error("Could not initialize AuthConfigurationProvider"); +// } +// } +// // authentication is not required if received authentication response +// } else if (req instanceof MOASTORKResponse) { +// return false; +// } + + return true; + } + + + private void iterate(NamedNodeMap attributesList) { + for (int j = 0; j < attributesList.getLength(); j++) { + Logger.debug("--Attribute: " + + attributesList.item(j).getNodeName() + " = " + + attributesList.item(j).getNodeValue()); + } + } + + + // does nothing + public void mandate(IAuthData authData) { + + if (authData.isUseMandate()) { + try { + MISMandate mandate = authData.getMISMandate(); + String owbpk = mandate.getOWbPK(); + byte[] mand = mandate.getMandate(); + String profprep = mandate.getProfRep(); + //String textdesc = mandate.getTextualDescriptionOfOID(); + Element mndt = authData.getMandate(); + + iterate(mndt.getAttributes()); + Logger.debug("mandate encoded: " + new String(org.bouncycastle.util.encoders.Base64.encode(mand))); + } catch (Exception x) { + Logger.debug("There is no mandate used in transaction"); + } + } + + + } + + public PersonalAttributeList populateAttributes(IAuthData authData, IOAAuthParameters oaParam) { + + IPersonalAttributeList attrLst = moaStorkRequest.getStorkAuthnRequest().getPersonalAttributeList(); + Logger.info("Found " + attrLst.size() + " personal attributes in the request."); + + // Define attribute list to be populated + PersonalAttributeList attributeList = new PersonalAttributeList(); + MOAAttributeProvider moaAttributeProvider = new MOAAttributeProvider(authData, moaStorkRequest); + + try { + for (PersonalAttribute personalAttribute : attrLst) { + try { + Logger.debug("Personal attribute found in request: " + personalAttribute.getName() + " isRequired: " + personalAttribute.isRequired()); + moaAttributeProvider.populateAttribute(attributeList, personalAttribute); + } catch (Exception e) { + Logger.error("Exception, attributes: " + e.getMessage(), e); + } + } + } catch (Exception e) { + Logger.error("Exception, attributes: " + e.getMessage(), e); + } + + Logger.trace("AUTHBLOCK " + authData.getAuthBlock()); + Logger.debug("SESSION IDENTIFIER " + authData.getCcc() + " " + oaParam.getIdentityLinkDomainIdentifier()); + + return attributeList; + } + + public String getDefaultActionName() { + return STORKProtocol.AUTHENTICATIONREQUEST; + } + + + private void initVelocityEngine() throws Exception { + velocityEngine = new VelocityEngine(); + velocityEngine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8"); + velocityEngine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8"); + velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); + velocityEngine.setProperty("classpath.resource.loader.class", + "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + + velocityEngine.init(); + } + +} |