From 3536b99c17250772f253ea5925da72a29e327c58 Mon Sep 17 00:00:00 2001 From: Thomas Lenz Date: Fri, 11 Sep 2015 18:23:33 +0200 Subject: move authentication protocol implementation to separate modules. authentication protocol modules are loaded by SPI now. --- .../id/protocols/stork2/AttributeCollector.java | 367 +++++++++++ .../protocols/stork2/AttributeProviderFactory.java | 101 +++ .../id/protocols/stork2/AuthenticationRequest.java | 531 ++++++++++++++++ .../moa/id/protocols/stork2/ConsentEvaluator.java | 249 ++++++++ .../stork2/CorporateBodyMandateContainer.java | 115 ++++ .../moa/id/protocols/stork2/DataContainer.java | 100 +++ .../ExternalAttributeRequestRequiredException.java | 53 ++ .../id/protocols/stork2/MOAAttributeProvider.java | 248 ++++++++ .../moa/id/protocols/stork2/MOASTORKRequest.java | 254 ++++++++ .../moa/id/protocols/stork2/MOASTORKResponse.java | 296 +++++++++ .../moa/id/protocols/stork2/MandateContainer.java | 182 ++++++ .../protocols/stork2/MandateRetrievalRequest.java | 602 ++++++++++++++++++ .../stork2/PhyPersonMandateContainer.java | 132 ++++ .../moa/id/protocols/stork2/S2Constants.java | 66 ++ .../moa/id/protocols/stork2/STORKPVPUtilits.java | 49 ++ .../moa/id/protocols/stork2/STORKProtocol.java | 233 +++++++ .../protocols/stork2/SimpleNamespaceContext.java | 83 +++ .../stork2/UnsupportedAttributeException.java | 29 + .../attributeproviders/AttributeProvider.java | 139 +++++ .../EHvdAttributeProviderPlugin.java | 254 ++++++++ .../MandateAttributeRequestProvider.java | 231 +++++++ .../PVPAuthenticationProvider.java | 238 +++++++ .../SignedDocAttributeRequestProvider.java | 688 +++++++++++++++++++++ .../StorkAttributeRequestProvider.java | 193 ++++++ 24 files changed, 5433 insertions(+) create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeCollector.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeProviderFactory.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AuthenticationRequest.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ConsentEvaluator.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/CorporateBodyMandateContainer.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/DataContainer.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ExternalAttributeRequestRequiredException.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOAAttributeProvider.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKRequest.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKResponse.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateContainer.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateRetrievalRequest.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/PhyPersonMandateContainer.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/S2Constants.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/STORKPVPUtilits.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/STORKProtocol.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/SimpleNamespaceContext.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/UnsupportedAttributeException.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/AttributeProvider.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/EHvdAttributeProviderPlugin.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/MandateAttributeRequestProvider.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/PVPAuthenticationProvider.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/SignedDocAttributeRequestProvider.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/StorkAttributeRequestProvider.java (limited to 'id/server/modules/module-stork/src/main/java') diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeCollector.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeCollector.java new file mode 100644 index 000000000..25cb952d7 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeCollector.java @@ -0,0 +1,367 @@ +/******************************************************************************* + * 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 java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +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.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.stork2.attributeproviders.AttributeProvider; +import at.gv.egovernment.moa.id.storage.AssertionStorage; +import at.gv.egovernment.moa.logging.Logger; +import eu.stork.peps.auth.commons.*; +import eu.stork.peps.auth.engine.STORKSAMLEngine; +import eu.stork.peps.complex.attributes.eu.stork.names.tc.stork._1_0.assertion.AttributeStatusType; +import eu.stork.peps.exceptions.STORKSAMLEngineException; + +import org.opensaml.common.impl.SecureRandomIdentifierGenerator; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * The AttributeCollector Action tries to get all requested attributes from a set of {@link AttributeProvider} Plugins. + * The class is called whenever the {@link AuthenticationRequest} Action is invoked and checks for missing attributes. + * Furthermore, the class can handle direct posts. That is when the class triggers an attribute query which needs user + * interaction, redirect to another portal, etc. The redirect will hit here and the class can continue to fetch attributes. + * + * TODO how do we treat mandatory and optional attributes? + */ +public class AttributeCollector implements IAction { + + /** + * The Constant ARTIFACT_ID. + */ + private static final String ARTIFACT_ID = "artifactId"; + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IAction#processRequest(at.gv.egovernment.moa.id.moduls.IRequest, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, at.gv.egovernment.moa.id.auth.data.AuthenticationSession) + */ + public SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp, IAuthData authData) throws MOAIDException { + + // - fetch the container + String artifactId = (String) httpReq.getParameter(ARTIFACT_ID); + DataContainer container; + try { + container = AssertionStorage.getInstance().get(artifactId, DataContainer.class); + } catch (MOADatabaseException e) { + Logger.error("Error fetching incomplete Stork response from temporary storage. Most likely a timeout occured.", e); + throw new MOAIDException("stork.11", null); + } + + + if (httpReq.getParameter("SAMLResponse") != null) { + Logger.info("Got SAML response from external attribute provider."); + + MOASTORKResponse STORK2Response = new MOASTORKResponse(); + + //extract STORK Response from HTTP Request + byte[] decSamlToken; + try { + decSamlToken = PEPSUtil.decodeSAMLToken(httpReq.getParameter("SAMLResponse")); + } catch (NullPointerException e) { + if (httpReq.getRemoteHost().contains("129.27.142")) { + Logger.warn("Availability check by " + httpReq.getRemoteHost() + " on URI: " + httpReq.getRequestURI()); + } else { + Logger.error("Unable to retrieve STORK Request for host: " + httpReq.getRemoteHost() + " and URI: " + httpReq.getRequestURI(), e); + } + throw new MOAIDException("stork.04", null); + } + + //Get SAMLEngine instance + STORKSAMLEngine engine = STORKSAMLEngine.getInstance("VIDP"); + + STORKAuthnResponse authnResponse = null; + + + // check if valid authn response is contained + try { + authnResponse = engine.validateSTORKAuthnResponse(decSamlToken, httpReq.getRemoteAddr()); + } catch (STORKSAMLEngineException ex) { + Logger.error("Unable to validate Stork AuthenticationResponse: " + ex.getMessage()); + } + + STORK2Response.setSTORKAuthnResponseToken(decSamlToken); + + // check if the attributes are provided for the same person from request + // requires presence of eIdentifier for unambigious correlation + Logger.debug("Checking if the attribute relates to the correct person.."); + try { + String remoteEIdentifier= authnResponse.getPersonalAttributeList().get("eIdentifier").getValue().get(0); + String localEidentifier= container.getResponse().getStorkAuthnResponse().getPersonalAttributeList().get("eIdentifier").getValue().get(0); + if (!remoteEIdentifier.equals(localEidentifier)) { + Logger.error("The attribute is not provided for the same person!"); + throw new MOAIDException("stork.25", null); + } + } catch (NullPointerException ex) { + Logger.warn("Could not check the correlation of attributes from external provider. Ignoring the check."); + //Logger.debug(ex); + //throw new MOAIDException("stork.04", null); // TODO revise message, raise exception when ehvd checked + } + + if (authnResponse.getPersonalAttributeList().size() > 0) { + Logger.info("Response from external attribute provider contains " + authnResponse.getPersonalAttributeList().size() + " attributes."); + container.getResponse().setPersonalAttributeList(addOrUpdateAll(container.getResponse().getPersonalAttributeList(), authnResponse.getPersonalAttributeList())); + } + + } + + // end addition + + + // read configuration parameters of OA + OAAuthParameter oaParam = AuthConfigurationProviderFactory.getInstance().getOnlineApplicationParameter(container.getRequest().getAssertionConsumerServiceURL()); + if (oaParam == null) + throw new AuthenticationException("stork.12", new Object[]{container.getRequest().getAssertionConsumerServiceURL()}); + + // find the attribute provider plugin that can handle the response + IPersonalAttributeList newAttributes = null; + + Iterator attibuteProvidersInterator = AttributeProviderFactory.getConfiguredPlugins(oaParam.getStorkAPs()); + while(attibuteProvidersInterator.hasNext()) + try { + newAttributes = attibuteProvidersInterator.next().parse(httpReq); + + // stop as soon as we hit a capable plugin + break; + } catch (UnsupportedAttributeException e1) { + // the current provider cannot find anything familiar within the + // provided httpreq. Try the next one. + } + + if (null == newAttributes) { + // we do not have a provider which is capable of fetching something + // from the received httpreq. + Logger.error("No attribute could be retrieved from the response the attribute provider gave us."); + } + + // - insert the embedded attribute(s) into the container + if (null != newAttributes) + container.getResponse().setPersonalAttributeList(addOrUpdateAll(container.getResponse().getPersonalAttributeList(), newAttributes)); + + // see if we need some more attributes + SLOInformationImpl sloInfo = (SLOInformationImpl) processRequest(container, httpReq, httpResp, authData, oaParam); + + if (sloInfo == null) { + sloInfo = new SLOInformationImpl(null, null, null, req.requestedModule()); + } + + return sloInfo; + + } + + /** + * Checks if there are missing attributes and tries to fetch them. If there are no more attribute to fetch, + * this very method creates and sends the protocol result to the asking S-PEPS. + * + * @param container the {@link DataContainer} representing the status of the overall query. + * @return the string + * @throws MOAIDException + */ + public SLOInformationInterface processRequest(DataContainer container, HttpServletRequest request, HttpServletResponse response, IAuthData authData, OAAuthParameter oaParam) throws MOAIDException { + // check if there are attributes we need to fetch + + IPersonalAttributeList requestAttributeList = container.getRequest().getPersonalAttributeList(); + IPersonalAttributeList responseAttributeList = container.getResponse().getPersonalAttributeList(); + List missingAttributes = new ArrayList(); + Logger.debug("aquire list of missing attributes"); + for (PersonalAttribute current : requestAttributeList) + if (!responseAttributeList.containsKey(current.getName())) { + if(null == current.getStatus() || (null != current.getStatus() && !current.getStatus().equals(AttributeStatusType.WITHHELD.value()))) { + // add the ones we need + missingAttributes.add(current); + Logger.debug("add " + current.getName() + " to the list of missing attributes"); + } + } else { + // remove the ones we do not want to share from the response list + if(null != current.getStatus() && current.getStatus().equals(AttributeStatusType.WITHHELD.value())) { + responseAttributeList.remove(current.getName()); + Logger.debug("remove " + current.getName() + " from the list of resulting attributes because the user does not want to disclose the data"); + } + } + + Logger.info("collecting attributes..."); + Logger.debug("found " + missingAttributes.size() + " missing attributes"); + + // Try to get all missing attributes + try { + // for each attribute still missing + for (PersonalAttribute currentAttribute : missingAttributes) { + + /* + * prefill attributes with "notAvailable". If we get them later, we override the value and status. + * This way, there is no error case in which an attribute is left unanswered. + */ + IPersonalAttributeList aquiredAttributes = new PersonalAttributeList(); + currentAttribute.setStatus(AttributeStatusType.NOT_AVAILABLE.value()); + aquiredAttributes.add((PersonalAttribute) currentAttribute.clone()); + container.getResponse().setPersonalAttributeList( + addOrUpdateAll(container.getResponse().getPersonalAttributeList(), aquiredAttributes)); + // - check if we can find a suitable AttributeProvider Plugin + + Iterator attibuteProvidersInterator = AttributeProviderFactory.getConfiguredPlugins(oaParam.getStorkAPs()); + while(attibuteProvidersInterator.hasNext()) { + AttributeProvider currentProvider = attibuteProvidersInterator.next(); + + // build a section of attribute provider's predefined attributes and missing attributes + // only missing attributes that can be handled by attribute provider will be sent to it + List currentProviderConfiguredAttributes = new ArrayList(); + for (String attributeName : currentProvider.getSupportedAttributeNames()) { + for (PersonalAttribute missingAttribute : missingAttributes) { + if (missingAttribute.getName().equals(attributeName)) { + currentProviderConfiguredAttributes.add(missingAttribute); + break; + } + } + } + + try { + // - hand over control to the suitable plugin + Logger.info(currentProvider.getClass().getSimpleName() + " called to handle attribute '" + currentAttribute.getName() + "'"); + + //aquiredAttributes = currentProvider.acquire(currentAttribute, container.getRequest().getSpCountry(), moasession); + //aquiredAttributes = currentProvider.acquire(missingAttributes, container.getRequest().getSpCountry(), moasession); + aquiredAttributes = currentProvider.acquire(currentProviderConfiguredAttributes, container.getRequest(), authData); + + Logger.info(currentProvider.getClass().getSimpleName() + " can handle attribute '" + currentAttribute.getName() + "'"); + break; + } catch (UnsupportedAttributeException e) { + // ok, try the next attributeprovider + Logger.info(currentProvider.getClass().getSimpleName() + " could not handle attribute '" + currentAttribute.getName() + "'"); + } catch (MOAIDException e) { + // the current plugin had an error. Try the next one. + Logger.info(currentProvider.getClass().getSimpleName() + " could not handle attribute '" + currentAttribute.getName() + "' due to an error"); + } + } + + // check if we could fetch the attribute + if (null == aquiredAttributes) { + // if not + Logger.error("We have no suitable plugin for obtaining the attribute '" + currentAttribute.getName() + "'"); + } else + // else, update any existing attributes + container.getResponse().setPersonalAttributeList(addOrUpdateAll(container.getResponse().getPersonalAttributeList(), aquiredAttributes)); + } + Logger.info("collecting attributes done"); + + // ask for consent if necessary + new ConsentEvaluator().generateSTORKResponse(response, container); + + return null; // AssertionId + // TODO + + } catch (ExternalAttributeRequestRequiredException e) { + // the attribute request is ongoing and requires an external service. + try { + // memorize the container again + Logger.debug("prepare putting the container into temporary storage..."); + + // - generate new key + String newArtifactId = new SecureRandomIdentifierGenerator() + .generateIdentifier(); + // - put container in temporary store. + AssertionStorage.getInstance().put(newArtifactId, container); + + Logger.debug("...successful"); + + Logger.info(e.getAp().getClass().getSimpleName() + " is going to ask an external service provider for the requested attributes"); + + // add container-key to redirect embedded within the return URL + e.getAp().performRedirect(AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix() + "/stork2/ResumeAuthentication?" + ARTIFACT_ID + "=" + newArtifactId, request, response, oaParam); + + } catch (Exception e1) { + // TODO should we return the response as is to the PEPS? + Logger.error("Error putting incomplete Stork response into temporary storage", e1); + e1.printStackTrace(); + throw new MOAIDException("stork.11", null); + } + + //TODO: in case of Single LogOut -> SLO information has to be stored + return null; // TODO what to do here? + } + } + + /** + * Adds or updates all {@link PersonalAttribute} objects given in {@code source} to/in {@code target}. + * + * @param target the target + * @param source the source + * @return + * @throws MOAIDException + */ + private PersonalAttributeList addOrUpdateAll(IPersonalAttributeList target, IPersonalAttributeList source) throws MOAIDException { + + PersonalAttributeList updatedList = new PersonalAttributeList(); + for (PersonalAttribute el : target) + updatedList.add(el); + + Logger.debug("Updating " + source.size() + " attributes..."); + for (PersonalAttribute current : source) { + Logger.debug("treating " + current.getName()); + + // check if we need to update the current pa + if (updatedList.containsKey(current.getName())) { + PersonalAttribute existing = target.get(current.getName()); + if(!(existing.isEmptyValue() && existing.isEmptyComplexValue())) + if(!(existing.getValue().equals(current.getValue()) || existing.getComplexValue().equals(current.getComplexValue()))) { + Logger.error("Attribute Value does not match the value from first authentication!"); + throw new MOAIDException("stork.16", new Object[] {existing.getName()}); + } + + updatedList.get(current.getName()).setStatus(current.getStatus()); + updatedList.get(current.getName()).setValue(current.getValue()); + updatedList.get(current.getName()).setComplexValue(current.getComplexValue()); + } else + updatedList.add(current); + + Logger.debug("...successfully treated " + current.getName()); + } + + return updatedList; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IAction#needAuthentication(at.gv.egovernment.moa.id.moduls.IRequest, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) { + // this action does not need any authentication. The authentication is already done by the preceding AuthenticationRequest-Action. + return false; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IAction#getDefaultActionName() + */ + public String getDefaultActionName() { + return STORKProtocol.ATTRIBUTE_COLLECTOR; + } +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeProviderFactory.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeProviderFactory.java new file mode 100644 index 000000000..aadbbd959 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeProviderFactory.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * 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.commons.MOAIDConstants; +import at.gv.egovernment.moa.id.config.stork.StorkAttributeProviderPlugin; +import at.gv.egovernment.moa.id.protocols.stork2.attributeproviders.AttributeProvider; +import at.gv.egovernment.moa.id.protocols.stork2.attributeproviders.EHvdAttributeProviderPlugin; +import at.gv.egovernment.moa.id.protocols.stork2.attributeproviders.MandateAttributeRequestProvider; +import at.gv.egovernment.moa.id.protocols.stork2.attributeproviders.PVPAuthenticationProvider; +import at.gv.egovernment.moa.id.protocols.stork2.attributeproviders.SignedDocAttributeRequestProvider; +import at.gv.egovernment.moa.id.protocols.stork2.attributeproviders.StorkAttributeRequestProvider; +import at.gv.egovernment.moa.logging.Logger; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.PriorityQueue; + +/** + * A factory for creating AttributeProvider objects. + */ +public class AttributeProviderFactory { + + /** + * Gets the available plugins. + * + * @return the available plugins + */ + public static List getAvailablePlugins() { + return MOAIDConstants.ALLOWED_STORKATTRIBUTEPROVIDERS; + } + + /** + * Creates an AttributeProvider object for the given shortname. Returns + * {@code null} if there is no such provider available. + * + * @param shortname the simpleName for the providers class + * @return the attribute provider + */ + public static AttributeProvider create(String shortname, String url, String attributes) { + if (shortname.equals("StorkAttributeRequestProvider")) { + return new StorkAttributeRequestProvider(url, attributes); + } else if (shortname.equals("EHvdAttributeProvider")) { + return new EHvdAttributeProviderPlugin(url, attributes); + } else if (shortname.equals("SignedDocAttributeRequestProvider")) { + return new SignedDocAttributeRequestProvider(url, attributes); + } else if (shortname.equals("MandateAttributeRequestProvider")) { + try { + return new MandateAttributeRequestProvider(url, attributes); + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + } else if (shortname.equals("PVPAuthenticationProvider")) { + return new PVPAuthenticationProvider(url, attributes); + } else { + return null; + } + } + + /** + * Gets fresh instances of the configured plugins. + * + * @param collection the configured a ps + * @return the configured plugins + */ + public static Iterator getConfiguredPlugins( + Collection collection) { + + PriorityQueue result = new PriorityQueue(); + for (StorkAttributeProviderPlugin current : collection) { + + result.add(create(current.getName(), current.getUrl(), current.getAttributes())); + Logger.debug("Adding configured attribute provider: " + current.getClass().getName() + current.getName() + " at " + current.getUrl()); + } + + return result.iterator(); + } +} 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(); + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ConsentEvaluator.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ConsentEvaluator.java new file mode 100644 index 000000000..bde0f362d --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ConsentEvaluator.java @@ -0,0 +1,249 @@ +/******************************************************************************* + * 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 java.io.StringWriter; + +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map.Entry; + +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.OAAuthParameter; +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.id.moduls.IRequest; +import at.gv.egovernment.moa.id.storage.AssertionStorage; +import at.gv.egovernment.moa.id.util.VelocityProvider; +import at.gv.egovernment.moa.logging.Logger; +import eu.stork.peps.auth.commons.PEPSUtil; +import eu.stork.peps.auth.commons.PersonalAttribute; +import eu.stork.peps.auth.engine.STORKSAMLEngine; +import eu.stork.peps.complex.attributes.eu.stork.names.tc.stork._1_0.assertion.AttributeStatusType; +import eu.stork.peps.exceptions.STORKSAMLEngineException; + +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.opensaml.common.impl.SecureRandomIdentifierGenerator; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * The ConsentEvaluator assists with fetching user consent on the list of attributes to be sent to the asking S-PEPS. + */ +public class ConsentEvaluator implements IAction { + + /** + * The Constant ARTIFACT_ID. + */ + private static final String ARTIFACT_ID = "artifactId"; + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IAction#processRequest(at.gv.egovernment.moa.id.moduls.IRequest, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, at.gv.egovernment.moa.id.auth.data.AuthenticationSession) + */ + public SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp, IAuthData authData) throws MOAIDException { + + // - fetch the container + String artifactId = (String) httpReq.getParameter(ARTIFACT_ID); + DataContainer container; + try { + container = AssertionStorage.getInstance().get(artifactId, DataContainer.class); + req = container.getRequest(); + } catch (MOADatabaseException e) { + Logger.error("Error fetching incomplete Stork response from temporary storage. Most likely a timeout occured.", e); + throw new MOAIDException("stork.17", null); + } + + // evaluate response + for(PersonalAttribute current : container.getRequest().getPersonalAttributeList()) { + if(null == httpReq.getParameter(current.getName())) { + current.setStatus(AttributeStatusType.WITHHELD.value()); + current.setValue(new ArrayList()); + current.setComplexValue(new HashMap()); + } + } + + //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()}); + + new AttributeCollector().processRequest(container, httpReq, httpResp, authData, oaParam); + + return null; // AssertionId + } + + /** + * Fills the given HttpResponse with the required web page. + * + * @param container the container + * @param authData + * @param response the response + * @param oaParam the oa param + * @return the string + * @throws MOAIDException the mOAID exception + */ + public String requestConsent(DataContainer container, HttpServletRequest httpReq, HttpServletResponse httpResp, IAuthData authData, OAAuthParameter oaParam) throws MOAIDException { + //check if we need to collect consent + if(!oaParam.isRequireConsentForStorkAttributes()) { + (new AttributeCollector()).processRequest(container, httpReq, httpResp, authData, oaParam); + return ""; + } + + // prepare redirect + String newArtifactId; + try { + + // memorize the container again + Logger.debug("prepare putting the container into temporary storage..."); + + // - generate new key + newArtifactId = new SecureRandomIdentifierGenerator().generateIdentifier(); + + // - put container in temporary store. + AssertionStorage.getInstance().put(newArtifactId, container); + + Logger.debug("...successful"); + + } catch (Exception e1) { + // TODO should we return the response as is to the PEPS? + e1.printStackTrace(); + Logger.error("Error putting incomplete Stork response into temporary storage", e1); + throw new MOAIDException("stork.17", null); + } + + // ask for consent + try { + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/stork2_consent.html"); + VelocityContext context = new VelocityContext(); + + context.put("action", AuthConfigurationProviderFactory.getInstance().getPublicURLPrefix() + "/stork2/CompleteAuthentication?" + ARTIFACT_ID + "=" + newArtifactId); + + // assemble table + String table = ""; + for (PersonalAttribute current : container.getRequest().getPersonalAttributeList()) + table += "" + current.getName() + (current.isRequired() ? "" : " (optional)") + "\n"; + + context.put("tablecontent", table); + for(Entry current : oaParam.getFormCustomizaten().entrySet()) + context.put(current.getKey().replace("#", ""), current.getValue()); + + StringWriter writer = new StringWriter(); + template.merge(context, writer); + httpResp.getOutputStream().write(writer.getBuffer().toString().getBytes("UTF-8")); + + } catch (Exception e) { + Logger.error("Velocity error: " + e.getMessage()); + throw new MOAIDException("stork.17", null); + } + + return "12345"; // AssertionId + } + + /** + * generates binary response from given response class and fill the given HttpResponse with a SAML Post Binding template. + * + * @param httpResp the http resp + * @param container the container + * @throws MOAIDException the mOAID exception + */ + public void generateSTORKResponse(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()); + } + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IAction#needAuthentication(at.gv.egovernment.moa.id.moduls.IRequest, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) { + // this action does not need any authentication. The authentication is already done by the preceding AuthenticationRequest-Action. + return false; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IAction#getDefaultActionName() + */ + public String getDefaultActionName() { + return STORKProtocol.CONSENT_EVALUATOR; + } +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/CorporateBodyMandateContainer.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/CorporateBodyMandateContainer.java new file mode 100644 index 000000000..acbf1678a --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/CorporateBodyMandateContainer.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * 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.MOAIDException; +import at.gv.egovernment.moa.logging.Logger; +import org.xml.sax.InputSource; + +import javax.xml.xpath.XPathExpressionException; +import java.io.StringReader; +/** + * Physical person representing corporate body + * + * @author bsuzic + * Date: 4/29/14, Time: 3:40 PM + */ +public class CorporateBodyMandateContainer extends MandateContainer { + + protected String corpMandatorIdentificationValue = null; + protected String corpMandatorIdentificationType = null; + protected String corpMandatorFullName = null; + + + String localMethods[] = new String[]{"getCorpMandatorIdentificationValue", "getCorpMandatorIdentificationType", "getCorpMandatorFullName", + "getMandateIssuePlace", "getMandateIssueDate", "getMandateIssueTime", "getSimpleMandateContent", "getMandateValidFrom", + "getMandateValidTo", "getPhysicalRepresentativeIdentificationValue", "getPhysicalRepresentativeIdentificationType", "getAnnotation", + "getPhysicalRepresentativeGivenName", "getPhysicalRepresentativeFamilyName", "getPhysicalRepresentativeBirthDate" + }; + + public CorporateBodyMandateContainer(String mandate) throws XPathExpressionException, MOAIDException { + super(mandate); + Logger.debug("Initializing corporate body mandate container."); + + setAnnotation(xPath.evaluate(S2Constants.MANDATE_ANNOTATION_QUERY, new InputSource(new StringReader(mandate)))); + setCorpMandatorFullName(xPath.evaluate(S2Constants.MANDATE_MANDATOR_CORPBODY_FULLNAME_QUERY, new InputSource(new StringReader(mandate)))); + setCorpMandatorIdentificationType(xPath.evaluate(S2Constants.MANDATE_MANDATOR_CORPBODY_IDTYPE_QUERY, new InputSource(new StringReader(mandate)))); + setCorpMandatorIdentificationValue(xPath.evaluate(S2Constants.MANDATE_MANDATOR_CORPBODY_IDVALUE_QUERY, new InputSource(new StringReader(mandate)))); + setMandateIssueDate(xPath.evaluate(S2Constants.MANDATE_ISSUEDDATE_QUERY, new InputSource(new StringReader(mandate)))); + setMandateIssuePlace(xPath.evaluate(S2Constants.MANDATE_ISSUEDPLACE_QUERY, new InputSource(new StringReader(mandate)))); + setMandateIssueTime(xPath.evaluate(S2Constants.MANDATE_ISSUEDTIME_QUERY, new InputSource(new StringReader(mandate)))); + setMandateValidFrom(xPath.evaluate(S2Constants.MANDATE_SIMPLEMANDATECONTENT_VALIDFROM_QUERY, new InputSource(new StringReader(mandate)))); + setMandateValidTo(xPath.evaluate(S2Constants.MANDATE_SIMPLEMANDATECONTENT_VALIDTO_QUERY, new InputSource(new StringReader(mandate)))); + setPhysicalRepresentativeBirthDate(xPath.evaluate(S2Constants.MANDATE_REPRESENTATIVE_PHYPERS_DATEOFBIRTH_QUERY, new InputSource(new StringReader(mandate)))); + setPhysicalRepresentativeFamilyName(xPath.evaluate(S2Constants.MANDATE_REPRESENTATIVE_PHYPERS_FAMILYNAME_QUERY, new InputSource(new StringReader(mandate)))); + setPhysicalRepresentativeGivenName(xPath.evaluate(S2Constants.MANDATE_REPRESENTATIVE_PHYPERS_GIVENNAME_QUERY, new InputSource(new StringReader(mandate)))); + setPhysicalRepresentativeIdentificationType(xPath.evaluate(S2Constants.MANDATE_REPRESENTATIVE_PHYPERS_IDTYPE_QUERY, new InputSource(new StringReader(mandate)))); + setPhysicalRepresentativeIdentificationValue(xPath.evaluate(S2Constants.MANDATE_REPRESENTATIVE_PHYPERS_IDVALUE_QUERY, new InputSource(new StringReader(mandate)))); + setSimpleMandateContent(xPath.evaluate(S2Constants.MANDATE_SIMPLEMANDATECONTENT_TXTDESC_QUERY, new InputSource(new StringReader(mandate)))); + + // check if all necessary fields are present + Logger.debug("Starting mandate structure validation"); + try { + validateMandateStructure(localMethods); // TODO + } catch (Exception e) { + + if (e instanceof MOAIDException) { + Logger.error("Could not validate mandate structure."); + throw new MOAIDException("stork.16", new Object[] {e.getMessage()}); // TODO + } else { + Logger.error("Error during mandate structure validation."); + throw new MOAIDException("stork.16", new Object[] {e.getMessage()}); // TODO + } + + } + + } + + public String getCorpMandatorIdentificationValue() { + return corpMandatorIdentificationValue; + } + + public void setCorpMandatorIdentificationValue(String corpMandatorIdentificationValue) { + Logger.debug("Setting corpMandatorIdentificationValue to AT/" + corpMandatorIdentificationValue); + this.corpMandatorIdentificationValue = "AT/" + corpMandatorIdentificationValue; + } + + public String getCorpMandatorIdentificationType() { + return corpMandatorIdentificationType; + } + + public void setCorpMandatorIdentificationType(String corpMandatorIdentificationType) { + this.corpMandatorIdentificationType = corpMandatorIdentificationType; + } + + public String getCorpMandatorFullName() { + return corpMandatorFullName; + } + + public void setCorpMandatorFullName(String corpMandatorFullName) { + this.corpMandatorFullName = corpMandatorFullName; + } + + + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/DataContainer.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/DataContainer.java new file mode 100644 index 000000000..e01a7526a --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/DataContainer.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * 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 java.io.Serializable; + +/** + * Holds info about an ongoing but yet incomplete stork authnrequest process. + */ +public class DataContainer implements Serializable { + + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = -8765997480582363012L; + + /** The incoming request. */ + private MOASTORKRequest request; + + /** The yet incomplete response. */ + private MOASTORKResponse response; + + /** The target. */ + private String target; + + /** The remote address. */ + private String remoteAddress; + + /** + * Gets the request. + * + * @return the request + */ + public MOASTORKRequest getRequest() { + return request; + } + + /** + * Sets the request. + * + * @param moaStorkRequest the new request + */ + public void setRequest(MOASTORKRequest moaStorkRequest) { + this.request = moaStorkRequest; + } + + /** + * Gets the response. + * + * @return the response + */ + public MOASTORKResponse getResponse() { + return response; + } + + /** + * Sets the response. + * + * @param moaStorkResponse the new response + */ + public void setResponse(MOASTORKResponse moaStorkResponse) { + this.response = moaStorkResponse; + } + + /** + * Gets the remote address. + * + * @return the remote address + */ + public String getRemoteAddress() { + return remoteAddress; + } + + /** + * Sets the remote address. + * + * @param remoteAddress the new remote address + */ + public void setRemoteAddress(String remoteAddress) { + this.remoteAddress = remoteAddress; + } +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ExternalAttributeRequestRequiredException.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ExternalAttributeRequestRequiredException.java new file mode 100644 index 000000000..096f223d7 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ExternalAttributeRequestRequiredException.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * 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.protocols.stork2.attributeproviders.AttributeProvider; + +public class ExternalAttributeRequestRequiredException extends Exception { + + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 5207631348933518908L; + + /** The ap. */ + private AttributeProvider ap; + + /** + * Instantiates a new external attribute request required exception. + * + * @param provider the provider + */ + public ExternalAttributeRequestRequiredException(AttributeProvider provider) { + ap = provider; + } + + /** + * Gets the ap that caused the exception. + * + * @return the ap + */ + public AttributeProvider getAp() { + return ap; + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOAAttributeProvider.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOAAttributeProvider.java new file mode 100644 index 000000000..2c7e5b539 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOAAttributeProvider.java @@ -0,0 +1,248 @@ +/******************************************************************************* + * 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.builder.BPKBuilder; +import at.gv.egovernment.moa.id.auth.exception.BuildException; +import at.gv.egovernment.moa.id.data.AuthenticationRole; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.id.util.PVPtoSTORKMapper; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; +import eu.stork.peps.auth.commons.PersonalAttribute; +import eu.stork.peps.auth.commons.PersonalAttributeList; +import eu.stork.peps.complex.attributes.eu.stork.names.tc.stork._1_0.assertion.AttributeStatusType; +import org.joda.time.Period; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * @author bsuzic + * Date: 2/19/14, Time: 4:42 PM + * + * @author tlenz + * Date: 23.10.14 + */ +public class MOAAttributeProvider { + private final IAuthData authData; + private static final Map storkAttributeSimpleMapping; + private static final Map storkAttributeFunctionMapping; + private final MOASTORKRequest moastorkRequest; + + // mappings for attribute population methods + // based on mapping of moa authndata and executing functions to extract attributes + static { + Map tempSimpleMap = new HashMap(); + tempSimpleMap.put("givenName", "getGivenName"); + tempSimpleMap.put("surname", "getFamilyName"); + tempSimpleMap.put("MSOrganization", "getPvpAttribute_OU"); + storkAttributeSimpleMapping = Collections.unmodifiableMap(tempSimpleMap); + + Map tempFunctionMap = new HashMap(); + tempFunctionMap.put("eIdentifier", "geteIdentifier"); + tempFunctionMap.put("ECApplicationRole","getECApplicationRole"); + tempFunctionMap.put("dateOfBirth", "getFormatedDateOfBirth"); + tempFunctionMap.put("MSOrganization", "getMSOrganization"); + tempFunctionMap.put("age", "getAge"); + tempFunctionMap.put("isAgeOver", "getIsAgeOver"); + tempFunctionMap.put("citizenQAALevel", "getQAALevel"); + storkAttributeFunctionMapping = Collections.unmodifiableMap(tempFunctionMap); + + } + + public MOAAttributeProvider(IAuthData authData, MOASTORKRequest moastorkRequest) { + this.authData = authData; + this.moastorkRequest = moastorkRequest; + + } + + public void populateAttribute(PersonalAttributeList attributeList, PersonalAttribute requestedAttribute ) { + String storkAttribute = requestedAttribute.getName(); + + // TODO: check if authData gets populated with stork attributtes during previous steps; it seems it is not + if (null != authData && null != authData.getStorkAttributes() && authData.getStorkAttributes().containsKey(requestedAttribute.getName())) { + Logger.debug("Trying to get value for attribute directly from STORK2 response [" + storkAttribute + "]"); + try { + PersonalAttribute tmp = authData.getStorkAttributes().get(requestedAttribute.getName()); + attributeList.add((PersonalAttribute) tmp.clone()); + } catch(Exception e) { + Logger.error("Could not retrieve attribute from STORK2 response: " + storkAttribute); + Logger.debug(e); + } + } else if (storkAttributeSimpleMapping.containsKey(storkAttribute)) { + Logger.debug("Trying to get value for attribute using simple mapping [" + storkAttribute + "]"); + try { + Method method = authData.getClass().getDeclaredMethod(storkAttributeSimpleMapping.get(storkAttribute)); + populateAttributeWithMethod(method, authData, attributeList, storkAttribute, requestedAttribute); + } catch (NoSuchMethodException e) { + Logger.error("Could not found MOA extraction method while getting attribute: " + storkAttribute); + Logger.debug(e); + } catch (NullPointerException e) { + Logger.error("Error getting MOA extraction method while getting attribute: " + storkAttribute); + Logger.debug(e); + } + + } else if (storkAttributeFunctionMapping.containsKey(storkAttribute)) { + + Logger.debug("Trying to get value for attribute using function mapping [" + storkAttribute + "]"); + try { + Method method = this.getClass().getDeclaredMethod(storkAttributeFunctionMapping.get(storkAttribute), PersonalAttribute.class); + populateAttributeWithMethod(method, this, attributeList, storkAttribute, requestedAttribute); + } catch (NoSuchMethodException e) { + Logger.error("Could not found MOA extraction method while getting attribute: " + storkAttribute); + } + } else { + Logger.debug("MOA method for extraction of attribute " + storkAttribute + " not defined."); + } + } + + private String getAge(PersonalAttribute personalAttribute) { + if (authData.getDateOfBirth() != null) { + Integer age = new Period(authData.getDateOfBirth().getTime(), Calendar.getInstance().getTime().getTime()).getYears(); + return age >= 0 ? age.toString() : null; + } + return null; // WP4 D4.2, Table 12:age, description - considerations + } + + private String getIsAgeOver(PersonalAttribute personalAttribute) + { + try { + if ((authData.getDateOfBirth() != null) && (personalAttribute.getValue() != null) && (personalAttribute.getValue().size() > 0)) { + Integer ageOver = Integer.parseInt(personalAttribute.getValue().get(0)); + Integer age = new Period(authData.getDateOfBirth().getTime(), Calendar.getInstance().getTime().getTime()).getYears(); + return age >= ageOver ? ageOver.toString() : ""; + } + } catch (Exception ex) { + Logger.error("Error encountered when determining isAgeOver"); + Logger.debug(ex); + } + return null; + } + + public String getQAALevel(PersonalAttribute personalAttribute) { + if (authData.getQAALevel().startsWith(PVPConstants.STORK_QAA_PREFIX)) + return authData.getQAALevel().substring(PVPConstants.STORK_QAA_PREFIX.length()); + else + return null; + } + + + private String geteIdentifier(PersonalAttribute personalAttribute) { + Logger.debug("Using base urn for identification value: " + authData.getIdentificationType() + " and target country: " + moastorkRequest.getStorkAuthnRequest().getSpCountry()); + try { + return new BPKBuilder().buildStorkeIdentifier(authData.getIdentificationType(), authData.getIdentificationValue(), + moastorkRequest.getStorkAuthnRequest().getSpCountry()); + } catch (BuildException be) { + Logger.error("Stork eid could not be constructed; " + be.getMessage()); + return null; // TODO error + } + } + + private List getECApplicationRole(PersonalAttribute personalAttribute) { + List storkRoles = null; + + if (authData.getAuthenticationRoles() != null + && authData.getAuthenticationRoles().size() > 0) { + + storkRoles = new ArrayList(); + PVPtoSTORKMapper mapper = PVPtoSTORKMapper.getInstance(); + for (AuthenticationRole el : authData.getAuthenticationRoles()) { + String storkRole = mapper.map(el); + if (MiscUtil.isNotEmpty(storkRole)) + storkRoles.add(storkRole); + } + } + return storkRoles; + } + + private String getFormatedDateOfBirth(PersonalAttribute personalAttribute) { + if (authData.getDateOfBirth() != null) { + DateFormat fmt = new SimpleDateFormat("yyyyMMdd"); + return fmt.format(authData.getDateOfBirth()); + } + else + return null; + } + + private void populateAttributeWithMethod(Method method, Object object, PersonalAttributeList attributeList, String storkAttribute, PersonalAttribute requestedAttribute) { + try { + Object attributeValue; + if (storkAttributeSimpleMapping.containsValue(method.getName())) { + attributeValue = method.invoke(object, new Class[]{}); + } else { + attributeValue = method.invoke(object, requestedAttribute); + } + + PersonalAttribute newAttribute = new PersonalAttribute(); + newAttribute.setName(storkAttribute); + newAttribute.setIsRequired(requestedAttribute.isRequired()); + + if (attributeValue != null) { + newAttribute.setStatus(AttributeStatusType.AVAILABLE.value()); + Logger.info("Got attribute value: " + attributeValue); + + if (attributeValue instanceof String) + newAttribute.setValue(new ArrayList(Collections.singletonList((String)attributeValue))); + + else if (attributeValue instanceof List) { + List attributeValueList = (List) attributeValue; + if (attributeValueList.size() > 0 && attributeValueList.get(0) instanceof String) { + newAttribute.setValue((List) attributeValueList); + + } else { + Logger.info("Attribute " + storkAttribute + " is not available."); + newAttribute.setStatus(AttributeStatusType.NOT_AVAILABLE.value()); + + } + + } else { + Logger.error("Receive an unsupported type for attribute " + storkAttribute); + + } + attributeList.add(newAttribute); + + } else { + Logger.info("Attribute " + storkAttribute + " is not available."); + newAttribute.setStatus(AttributeStatusType.NOT_AVAILABLE.value()); + } + + } catch (InvocationTargetException e) { + Logger.error("Invocation target exception while getting attribute: " + storkAttribute); + Logger.debug(e); + } catch (IllegalAccessException e) { + Logger.error("Illegal access exception while getting attribute: " + storkAttribute); + Logger.debug(e); + } catch (NullPointerException e) { + Logger.error("Could not find method: " + storkAttribute); + Logger.debug(e); + } + } + + +} + diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKRequest.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKRequest.java new file mode 100644 index 000000000..11eb01453 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKRequest.java @@ -0,0 +1,254 @@ +/******************************************************************************* + * 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 java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.opensaml.saml2.core.Attribute; + +import at.gv.egovernment.moa.id.auth.builder.DynamicOAAuthParameterBuilder; +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.IOAAuthParameters; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.config.auth.data.DynamicOAAuthParameters; +import at.gv.egovernment.moa.id.moduls.RequestImpl; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.id.protocols.pvp2x.builder.AttributQueryBuilder; +import at.gv.egovernment.moa.id.protocols.pvp2x.messages.MOAResponse; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Constants; +import eu.stork.peps.auth.commons.IPersonalAttributeList; +import eu.stork.peps.auth.commons.STORKAttrQueryRequest; +import eu.stork.peps.auth.commons.STORKAuthnRequest; +import eu.stork.peps.auth.commons.STORKAuthnResponse; + +/** + * Implements MOA request and stores StorkAuthn/Attr-Request related data. + * + * @author bsuzic + */ +public class MOASTORKRequest extends RequestImpl { + + public static final List DEFAULTREQUESTEDATTRFORINTERFEDERATION = Arrays.asList( + new String[] { + PVPConstants.BPK_NAME, + PVPConstants.EID_SECTOR_FOR_IDENTIFIER_NAME, + PVPConstants.GIVEN_NAME_NAME, + PVPConstants.PRINCIPAL_NAME_NAME, + PVPConstants.BIRTHDATE_NAME, + PVPConstants.EID_CITIZEN_QAA_LEVEL_NAME, + }); + + /** The Constant serialVersionUID. */ + private static final long serialVersionUID = 4581953368724501376L; + + /** The request id. */ + private String requestID; + + /** The stork authn request. */ + private STORKAuthnRequest storkAuthnRequest; + + /** The stork attr query request. */ + private STORKAttrQueryRequest storkAttrQueryRequest; + + + /** + * Sets the sTORK authn request. + * + * @param request the new sTORK authn request + */ + public void setSTORKAuthnRequest(STORKAuthnRequest request) { + this.storkAuthnRequest = request; + } + + /** + * Sets the sTORK attr request. + * + * @param request the new sTORK attr request + */ + public void setSTORKAttrRequest(STORKAttrQueryRequest request) { + this.storkAttrQueryRequest = request; + } + + /** + * Checks if the container holds an AttrQueryRequest + * + * @return true, if is attr request + */ + public boolean isAttrRequest() { + return null != storkAttrQueryRequest; + } + + /** + * Checks if the container holds an AuthnRequest + * + * @return true, if is authn request + */ + public boolean isAuthnRequest() { + return null != storkAuthnRequest; + } + + /** + * Gets the stork authn request. + * + * @return the stork authn request + */ + public STORKAuthnRequest getStorkAuthnRequest() { + return this.storkAuthnRequest; + } + + /** + * Gets the stork attr query request. + * + * @return the stork attr query request + */ + public STORKAttrQueryRequest getStorkAttrQueryRequest() { + return this.storkAttrQueryRequest; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#getOAURL() + */ + public String getOAURL() { + if (isAuthnRequest()) + return storkAuthnRequest.getAssertionConsumerServiceURL(); + else if (isAttrRequest()) + return storkAttrQueryRequest.getAssertionConsumerServiceURL(); + else { + Logger.error("There is no authentication or attribute request contained in MOASTORKRequest."); + return null; + } + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#isPassiv() + */ + public boolean isPassiv() { + return false; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#forceAuth() + */ + public boolean forceAuth() { + return false; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#isSSOSupported() + */ + public boolean isSSOSupported() { + return false; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#setRequestID(java.lang.String) + */ + public void setRequestID(String id) { + this.requestID = id; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#getRequestID() + */ + public String getRequestID() { + return this.requestID; + } + + /** + * Gets the personal attribute list. + * + * @return the personal attribute list + */ + public IPersonalAttributeList getPersonalAttributeList() { + if(isAttrRequest()) + return this.storkAttrQueryRequest.getPersonalAttributeList(); + else + return this.storkAuthnRequest.getPersonalAttributeList(); + } + + /** + * Gets the sp country. + * + * @return the sp country + */ + public String getSpCountry() { + if(isAttrRequest()) + return this.storkAttrQueryRequest.getSpCountry(); + else + return this.storkAuthnRequest.getSpCountry(); + } + + /** + * Gets the assertion consumer service url. + * + * @return the assertion consumer service url + */ + public String getAssertionConsumerServiceURL() { + if(isAttrRequest()) + return this.storkAttrQueryRequest.getAssertionConsumerServiceURL(); + else + return this.storkAuthnRequest.getAssertionConsumerServiceURL(); + } + + /** + * Gets the citizen country code. + * + * @return the citizen country code + */ + public String getCitizenCountryCode() { + if(isAttrRequest()) + return this.storkAttrQueryRequest.getCitizenCountryCode(); + else + return this.storkAuthnRequest.getCitizenCountryCode(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.RequestImpl#getRequestedAttributes() + */ + @Override + public List getRequestedAttributes() { + //TODO: only for testing with MOA-ID as PVP Stammportal + IOAAuthParameters oa; + try { + oa = AuthConfigurationProviderFactory.getInstance().getOnlineApplicationParameter(getOAURL()); + oa = DynamicOAAuthParameterBuilder.buildFromAuthnRequest(oa, this); + + DynamicOAAuthParameters tmp = (DynamicOAAuthParameters) oa; + tmp.setBusinessTarget(Constants.URN_PREFIX_CDID + "+BF"); + + return AttributQueryBuilder.buildSAML2AttributeList(tmp, DEFAULTREQUESTEDATTRFORINTERFEDERATION.iterator()); + + } catch (ConfigurationException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + + //return new ArrayList(); + + } +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKResponse.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKResponse.java new file mode 100644 index 000000000..d2cf2e813 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKResponse.java @@ -0,0 +1,296 @@ +/******************************************************************************* + * 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.moduls.IRequest; +import at.gv.egovernment.moa.id.moduls.RequestImpl; +import at.gv.egovernment.moa.logging.Logger; +import eu.stork.peps.auth.commons.IPersonalAttributeList; +import eu.stork.peps.auth.commons.PersonalAttributeList; +import eu.stork.peps.auth.commons.STORKAttrQueryResponse; +import eu.stork.peps.auth.commons.STORKAuthnResponse; + +import java.io.Serializable; +import java.util.List; + +import org.opensaml.saml2.core.Attribute; + +/** + * Implements MOA request and stores StorkAuthn/Attr-Request related data. + * + * @author bsuzic + */ +public class MOASTORKResponse extends RequestImpl { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = -5798803155055518747L; + + /** + * The stork authn request. + */ + private STORKAuthnResponse storkAuthnResponse; + + /** + * The stork attr query request. + */ + private STORKAttrQueryResponse storkAttrQueryResponse; + + /** + * The action. + */ + String action = null; + + /** + * The token + */ + private byte[] storkAuthnResponseToken = null; + + /** + * The request id. + */ + private String requestID; + + + /** + * The module. + */ + String module = null; + + /** + * The target. + */ + private String target = null; + + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#requestedModule() + */ + public String requestedModule() { + return this.module; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#requestedAction() + */ + public String requestedAction() { + return action; + } + + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#getRequestID() + */ + public String getRequestID() { + return this.requestID; + } + + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#getTarget() + */ + public String getTarget() { + return this.target; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#isSSOSupported() + */ + public boolean isSSOSupported() { + return false; + } + + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#forceAuth() + */ + public boolean forceAuth() { + return false; + } + + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#setModule(java.lang.String) + */ + public void setModule(String module) { + this.module = module; + } + + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#setRequestID(java.lang.String) + */ + public void setRequestID(String id) { + this.requestID = id; + } + + /** + * Sets the sTORK authn response. + * + * @param request the new sTORK authn response + */ + public void setSTORKAuthnResponse(STORKAuthnResponse request) { + this.storkAuthnResponse = request; + } + + /** + * Sets the sTORK authn response token + * + * @param request the new sTORK authn response token + */ + public void setSTORKAuthnResponseToken(byte[] token) { + this.storkAuthnResponseToken = token; + } + + /** + * Gets the sTORK authn response token . + * + * @param request the new sTORK authn response + */ + public byte[] getSTORKAuthnResponseToken() { + return this.storkAuthnResponseToken; + } + /** + * Sets the sTORK attr response. + * + * @param request the new sTORK attr response + */ + public void setSTORKAttrResponse(STORKAttrQueryResponse request) { + this.storkAttrQueryResponse = request; + } + + /** + * Checks if the container holds an AttrQuery + * + * @return true, if is attr response + */ + public boolean isAttrResponse() { + return null != storkAttrQueryResponse; + } + + /** + * Checks if the container holds an AuthnRequest + * + * @return true, if is authn response + */ + public boolean isAuthnResponse() { + return null != storkAuthnResponse; + } + + + /** + * Gets the AuthnResponse. + * + * @return the stork authn response + */ + public STORKAuthnResponse getStorkAuthnResponse() { + return this.storkAuthnResponse; + } + + /** + * Gets the AttrQueryResponse. + * + * @return the stork attr query response + */ + public STORKAttrQueryResponse getStorkAttrQueryResponse() { + return this.storkAttrQueryResponse; + } + + /** + * Gets the personal attribute list. + * + * @return the personal attribute list + */ + public IPersonalAttributeList getPersonalAttributeList() { + if (isAttrResponse()) + return this.storkAttrQueryResponse.getPersonalAttributeList(); + else + return this.storkAuthnResponse.getPersonalAttributeList(); + } + + /** + * Sets the personal attribute list. + * + * @param populateAttributes the new personal attribute list + */ + public void setPersonalAttributeList(PersonalAttributeList populateAttributes) { + if (isAttrResponse()) + this.storkAttrQueryResponse.setPersonalAttributeList(populateAttributes); + else + this.storkAuthnResponse.setPersonalAttributeList(populateAttributes); + } + + /** + * Sets the country. + * + * @param spCountry the new country + */ + public void setCountry(String spCountry) { + if (isAttrResponse()) + this.storkAttrQueryResponse.setCountry(spCountry); + else + this.storkAuthnResponse.setCountry(spCountry); + } + + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#getOAURL() + */ + public String getOAURL() { + if (isAuthnResponse()) + return storkAuthnResponse.getAudienceRestriction(); + else if (isAttrResponse()) + return storkAttrQueryResponse.getAudienceRestriction(); + else { + Logger.error("There is no authentication or attribute request contained in MOASTORKRequest."); + return null; + } + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#isPassiv() + */ + public boolean isPassiv() { + return false; + } + + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.IRequest#setAction(java.lang.String) + */ + public void setAction(String action) { + this.action = action; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.moduls.RequestImpl#getRequestedAttributes() + */ + @Override + public List getRequestedAttributes() { + // TODO Auto-generated method stub + return null; + } + + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateContainer.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateContainer.java new file mode 100644 index 000000000..a3fac0f6e --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateContainer.java @@ -0,0 +1,182 @@ +/******************************************************************************* + * 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.MOAIDException; +import at.gv.egovernment.moa.logging.Logger; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; + +/** + * @author bsuzic + * Date: 5/5/14, Time: 2:35 PM + */ +public abstract class MandateContainer { + protected String mandateIssuePlace = null; + protected String mandateIssueDate = null; + protected String mandateIssueTime = null; + protected String simpleMandateContent = null; + protected String mandateValidFrom = null; + protected String mandateValidTo = null; + protected String annotation = null; + protected String physicalRepresentativeIdentificationValue = null; + protected String physicalRepresentativeIdentificationType = null; + protected String physicalRepresentativeGivenName = null; + protected String physicalRepresentativeFamilyName = null; + protected String physicalRepresentativeBirthDate = null; + protected XPath xPath = null; + + + public MandateContainer(String mandate) throws XPathExpressionException, MOAIDException { + Logger.debug("Received mandate content for processing: " + mandate); + + xPath = XPathFactory.newInstance().newXPath(); + HashMap prefMap = new HashMap() {{ + put(S2Constants.MANDATE_PREFIX, S2Constants.MANDATE_NS); + put(S2Constants.PERSONDATA_PREFIX, S2Constants.PERSONDATA_NS); + put(S2Constants.XMLDSIG_PREFIX, S2Constants.XMLDSIG_NS); + }}; + + SimpleNamespaceContext namespace = new SimpleNamespaceContext(prefMap); + xPath.setNamespaceContext(namespace); + } + + + public void validateMandateStructure(String localMethods[]) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, MOAIDException { + for (String localMethod : localMethods) { + Method method = this.getClass().getMethod(localMethod); + Object x = method.invoke(this); + if ((x == null) || x.toString().length() == 0) { + throw new MOAIDException("stork.16", new Object[] {localMethod}); // TODO + } + } + Logger.debug("Mandate structure validated"); + } + + + public String getMandateIssuePlace() { + return mandateIssuePlace; + } + + public void setMandateIssuePlace(String mandateIssuePlace) { + this.mandateIssuePlace = mandateIssuePlace; + } + + public String getMandateIssueDate() { + return mandateIssueDate; + } + + public void setMandateIssueDate(String mandateIssueDate) { + this.mandateIssueDate = mandateIssueDate; + } + + public String getMandateIssueTime() { + return mandateIssueTime; + } + + public void setMandateIssueTime(String mandateIssueTime) { + this.mandateIssueTime = mandateIssueTime; + } + + public String getSimpleMandateContent() { + return simpleMandateContent; + } + + public void setSimpleMandateContent(String simpleMandateContent) { + this.simpleMandateContent = simpleMandateContent; + } + + public String getMandateValidFrom() { + return mandateValidFrom; + } + + public void setMandateValidFrom(String mandateValidFrom) { + this.mandateValidFrom = mandateValidFrom; + } + + public String getMandateValidTo() { + return mandateValidTo; + } + + public void setMandateValidTo(String mandateValidTo) { + this.mandateValidTo = mandateValidTo; + } + + public String getPhysicalRepresentativeIdentificationValue() { + return physicalRepresentativeIdentificationValue; + } + + public void setPhysicalRepresentativeIdentificationValue(String physicalRepresentativeIdentificationValue) { + this.physicalRepresentativeIdentificationValue = physicalRepresentativeIdentificationValue; + } + + public String getPhysicalRepresentativeIdentificationType() { + return physicalRepresentativeIdentificationType; + } + + public void setPhysicalRepresentativeIdentificationType(String physicalRepresentativeIdentificationType) { + this.physicalRepresentativeIdentificationType = physicalRepresentativeIdentificationType; + } + + public String getPhysicalRepresentativeGivenName() { + return physicalRepresentativeGivenName; + } + + public void setPhysicalRepresentativeGivenName(String physicalRepresentativeGivenName) { + this.physicalRepresentativeGivenName = physicalRepresentativeGivenName; + } + + public String getPhysicalRepresentativeFamilyName() { + return physicalRepresentativeFamilyName; + } + + public void setPhysicalRepresentativeFamilyName(String physicalRepresentativeFamilyName) { + this.physicalRepresentativeFamilyName = physicalRepresentativeFamilyName; + } + + public String getPhysicalRepresentativeBirthDate() { + return physicalRepresentativeBirthDate; + } + + public void setPhysicalRepresentativeBirthDate(String physicalRepresentativeBirthDate) { + // making it conform to STORK dateOfBirth specifications, removing dash + this.physicalRepresentativeBirthDate = physicalRepresentativeBirthDate.replaceAll("-",""); + } + + public String getAnnotation() { + return annotation; + } + + public void setAnnotation(String annotation) { + this.annotation = annotation; + } + + + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateRetrievalRequest.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateRetrievalRequest.java new file mode 100644 index 000000000..e58fe804f --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateRetrievalRequest.java @@ -0,0 +1,602 @@ +/******************************************************************************* + * 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.builder.BPKBuilder; +import at.gv.egovernment.moa.id.auth.data.IdentityLink; +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; +import at.gv.egovernment.moa.id.auth.exception.BuildException; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +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.id.moduls.IRequest; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Constants; +import eu.stork.peps.auth.commons.IPersonalAttributeList; +import eu.stork.peps.auth.commons.PersonalAttribute; +import eu.stork.peps.auth.commons.PersonalAttributeList; +import eu.stork.peps.auth.commons.STORKAttrQueryResponse; +import eu.stork.peps.complex.attributes.eu.stork.names.tc.stork._1_0.assertion.*; +import org.apache.commons.codec.binary.StringUtils; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.Marshaller; +import javax.xml.datatype.DatatypeConfigurationException; +import javax.xml.datatype.DatatypeFactory; +import javax.xml.datatype.XMLGregorianCalendar; +import javax.xml.namespace.QName; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.regex.Pattern; + +/** + * Entry point for mandate retrieval. Processes MIS data and transforms into STORK mandate attribute. + * Additionally provides eIdentifier attribute (if requested) in order to enable identity correlation + */ +public class MandateRetrievalRequest implements IAction { + + private IAuthData authData; + private MOASTORKRequest moaStorkRequest; + private IdentityLink representingIdentityLink; + private Integer QAALevel; + private byte[] originalContent; + + public SLOInformationInterface processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp, IAuthData authData) throws MOAIDException { + Logger.debug("Entering AttributeRequest for MandateProvider"); + httpResp.reset(); + this.representingIdentityLink = authData.getIdentityLink(); + this.QAALevel = translateQAALevel(authData.getQAALevel()); + + // preparing original content and removing sensitive data from it + try { + this.originalContent = authData.getMISMandate().getMandate(); + } catch (Exception e) { + Logger.error("Could not extract mandate"); + Logger.debug(e); + throw new MOAIDException("stork.26", new Object[]{}); + } + String originalMandate = StringUtils.newStringUtf8(authData.getMISMandate().getMandate()).replaceAll(".*?==urn:publicid:gv.at:baseid","");; + Logger.debug("Removing personal identification value and type from original mandate "); + originalContent = StringUtils.getBytesUtf8(originalMandate); + + OAAuthParameter oaParam = AuthConfigurationProviderFactory.getInstance().getOnlineApplicationParameter(req.getOAURL()); + if (oaParam == null) + throw new AuthenticationException("stork.12", new Object[]{req.getOAURL()}); + + MOASTORKResponse moaStorkResponse = new MOASTORKResponse(); + STORKAttrQueryResponse attrResponse = new STORKAttrQueryResponse(); + + this.authData = authData; + + if ((req instanceof MOASTORKRequest)) { + this.moaStorkRequest = (MOASTORKRequest) req; + } else { + Logger.error("Internal error - did not receive MOASTORKRequest as expected"); + throw new MOAIDException("stork.27", new Object[]{}); + } + + + if (!(moaStorkRequest.isAttrRequest() || moaStorkRequest.getStorkAttrQueryRequest() == null)) { + Logger.error("Did not receive attribute request as expected"); + throw new MOAIDException("stork.27", new Object[]{}); + } + + MandateContainer mandateContainer = null; + + try { + mandateContainer = new CorporateBodyMandateContainer(new String(authData.getMISMandate().getMandate(), "UTF-8")); + } catch (Exception ex) { + try { + mandateContainer = new PhyPersonMandateContainer(new String(authData.getMISMandate().getMandate(), "UTF-8")); + } catch (Exception ex2) { + Logger.error("Could not extract data and create mandate container."); + throw new MOAIDException("stork.27", new Object[]{}); + } + } + + IPersonalAttributeList sourceAttributeList = moaStorkRequest.getStorkAttrQueryRequest().getPersonalAttributeList(); + + IPersonalAttributeList attributeList = new PersonalAttributeList(); + + // according to new mapping, only mandate attribute is directly relevant + for (PersonalAttribute currentAttribute : sourceAttributeList) { + Logger.debug("Evaluating attributes, current attribute: " + currentAttribute.getName()); + if (currentAttribute.getName().equals("mandateContent")) { // deprecated + MandateContentType mandateContent = getMandateContent(mandateContainer, currentAttribute); + attributeList.add(marshallComplexAttribute(currentAttribute, mandateContent)); + } else if (currentAttribute.getName().equals("representative")) { // deprecated + RepresentationPersonType representative = getRepresentative(mandateContainer, currentAttribute); + attributeList.add(marshallComplexAttribute(currentAttribute, representative)); + } else if (currentAttribute.getName().equals("represented")) { + RepresentationPersonType represented = getRepresented(mandateContainer, currentAttribute); + attributeList.add(marshallComplexAttribute(currentAttribute, represented)); + } else if (currentAttribute.getName().equals("mandate")) { + MandateType mandateType = getMandateType(mandateContainer, currentAttribute); + attributeList.add(marshallComplexAttribute(currentAttribute, mandateType)); + } else if (currentAttribute.getName().equals("legalName")) { + String legalName = getLegalName(mandateContainer, currentAttribute); + if (legalName.length() > 0) { + attributeList.add(new PersonalAttribute(currentAttribute.getName(), currentAttribute.isRequired(), Arrays.asList(legalName), AttributeStatusType.AVAILABLE.value())); + } else { + attributeList.add(new PersonalAttribute(currentAttribute.getName(), currentAttribute.isRequired(), Arrays.asList(legalName), AttributeStatusType.NOT_AVAILABLE.value())); + } + } else if (currentAttribute.getName().equals("eLPIdentifier")) { + String eLPIdentifier = geteLPIdentifier(mandateContainer, currentAttribute); + if (eLPIdentifier.length() > 0) { + attributeList.add(new PersonalAttribute(currentAttribute.getName(), currentAttribute.isRequired(), Arrays.asList(eLPIdentifier), AttributeStatusType.AVAILABLE.value())); + } else { + attributeList.add(new PersonalAttribute(currentAttribute.getName(), currentAttribute.isRequired(), Arrays.asList(eLPIdentifier), AttributeStatusType.NOT_AVAILABLE.value())); + } + } else if (currentAttribute.getName().equals("type")) { + String type = getCompanyType(mandateContainer, currentAttribute); + if (type.length() > 0) { + attributeList.add(new PersonalAttribute(currentAttribute.getName(), currentAttribute.isRequired(), Arrays.asList(type), AttributeStatusType.AVAILABLE.value())); + } else { + attributeList.add(new PersonalAttribute(currentAttribute.getName(), currentAttribute.isRequired(), Arrays.asList(type), AttributeStatusType.NOT_AVAILABLE.value())); + } + } else if (currentAttribute.getName().equals("status")) { + String status = getCompanyStatus(mandateContainer, currentAttribute); + if (status.length() > 0) { + attributeList.add(new PersonalAttribute(currentAttribute.getName(), currentAttribute.isRequired(), Arrays.asList(status), AttributeStatusType.AVAILABLE.value())); + } else { + attributeList.add(new PersonalAttribute(currentAttribute.getName(), currentAttribute.isRequired(), Arrays.asList(status), AttributeStatusType.NOT_AVAILABLE.value())); + } + } else if (currentAttribute.getName().equals("translatableType")) { + String translatableType = getCompanyTranslatableType(mandateContainer, currentAttribute); + if (translatableType.length() > 0) { + attributeList.add(new PersonalAttribute(currentAttribute.getName(), currentAttribute.isRequired(), Arrays.asList(translatableType), AttributeStatusType.AVAILABLE.value())); + } else { + attributeList.add(new PersonalAttribute(currentAttribute.getName(), currentAttribute.isRequired(), Arrays.asList(translatableType), AttributeStatusType.NOT_AVAILABLE.value())); + } + } + + if (currentAttribute.getName().equals("eIdentifier")) { + attributeList.add(new PersonalAttribute(currentAttribute.getName(), currentAttribute.isRequired(), Arrays.asList(geteIdentifier(authData.getIdentificationType(), authData.getIdentificationValue(), moaStorkRequest.getStorkAttrQueryRequest().getSpCountry())), AttributeStatusType.AVAILABLE.value())); + Logger.info("Adding eIdentifier for mandate holder using SP country: " + moaStorkRequest.getStorkAttrQueryRequest().getSpCountry()); + } + + } + + +// if (attrResponse.getPersonalAttributeList().size() == 0) { +// Logger.error("AttributeList empty - could not retrieve attributes"); +// throw new MOAIDException("stork.16", new Object[]{}); // TODO MESSAGE +// } + + attrResponse.setPersonalAttributeList(attributeList); + moaStorkResponse.setSTORKAttrResponse(attrResponse); + + Logger.debug("Attributes retrieved: " + moaStorkResponse.getStorkAttrQueryResponse().getPersonalAttributeList().size() + " for SP country " + attrResponse.getCountry()); + + // 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"); + + // ask for consent if necessary + if (oaParam.isRequireConsentForStorkAttributes()) + new ConsentEvaluator().requestConsent(container, httpReq, httpResp, authData, oaParam); + else + new ConsentEvaluator().generateSTORKResponse(httpResp, container); + + return null; + } + + private Integer translateQAALevel(String qaaLevel) throws MOAIDException { + if (qaaLevel.equals(PVPConstants.STORK_QAA_1_1)) + return 1; + if (qaaLevel.equals(PVPConstants.STORK_QAA_1_2)) + return 2; + if (qaaLevel.equals(PVPConstants.STORK_QAA_1_3)) + return 3; + if (qaaLevel.equals(PVPConstants.STORK_QAA_1_4)) + return 4; + Logger.error("Wrong QAA Number format"); + throw new MOAIDException("stork.28", new Object[]{}); + } + + private String geteLPIdentifier(MandateContainer mandateContainer, PersonalAttribute currentAttribute) throws MOAIDException { + RepresentationPersonType represented = getRepresented(mandateContainer, currentAttribute); + if (mandateContainer instanceof CorporateBodyMandateContainer) { + return represented.getELPIdentifier(); + } else if (currentAttribute.isRequired()) { + Logger.error("Cannot provide eLPIdentifier for natural person."); + throw new MOAIDException("stork.29", new Object[]{currentAttribute.getName()}); + } + return ""; + } + + private String geteIdentifier(String identificationType, String identificationValue, String destinationCountry) throws MOAIDException { + BPKBuilder bpkBuilder = new BPKBuilder(); + try { + return bpkBuilder.buildStorkeIdentifier(identificationType, identificationValue, destinationCountry); + } catch (BuildException be) { + Logger.error("Could not build STORK eIdentifier while generating mandate assertion."); + throw new MOAIDException("stork.29", new Object[]{}); + } + } + + private PersonalAttribute marshallComplexAttribute(PersonalAttribute currentAttribute, Object obj) { // TODO refactor + StringWriter stringWriter = new StringWriter(); + try { + if (obj instanceof MandateContentType) { + final Marshaller marshaller = JAXBContext.newInstance(MandateContentType.class).createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); + marshaller.marshal(new JAXBElement(new QName("urn:eu:stork:names:tc:STORK:1.0:assertion", currentAttribute.getName()), MandateContentType.class, null, (MandateContentType) obj), stringWriter); + } else if (obj instanceof MandateType) { + final Marshaller marshaller = JAXBContext.newInstance(MandateType.class).createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); + marshaller.marshal(new JAXBElement(new QName("urn:eu:stork:names:tc:STORK:1.0:assertion", currentAttribute.getName()), MandateType.class, null, (MandateType) obj), stringWriter); + } else if (obj instanceof RepresentationPersonType) { + final Marshaller marshaller = JAXBContext.newInstance(RepresentationPersonType.class).createMarshaller(); + marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); + marshaller.marshal(new JAXBElement(new QName("urn:eu:stork:names:tc:STORK:1.0:assertion", currentAttribute.getName()), RepresentationPersonType.class, null, (RepresentationPersonType) obj), stringWriter); + } + + } catch (Exception ex) { + Logger.error("Could not marshall atrribute: " + currentAttribute.getName() + ", " + ex.getMessage()); + return new PersonalAttribute(currentAttribute.getName(), currentAttribute.isRequired(), new ArrayList(), AttributeStatusType.NOT_AVAILABLE.value()); + } + ArrayList value = new ArrayList(); + value.add(stringWriter.toString()); + + PersonalAttribute personalAttribute = new PersonalAttribute(currentAttribute.getName(), currentAttribute.isRequired(), value, AttributeStatusType.AVAILABLE.value()); + return personalAttribute; + } + + + private String mapPowersType(MandateContainer mandateContainer) { + Logger.debug("Analyzing mandate of type: " + mandateContainer.getAnnotation() + "."); + // using if for java 6 compatibility if necessary + if (mandateContainer.getAnnotation().equals("ELGABilateral")) { + return "6"; // Health Powers + } else if (mandateContainer.getAnnotation().equals("ERsB")) { + return "0"; // General Powers + } else if (mandateContainer.getAnnotation().equals("Gesetzliche Vollmacht auf Basis Ergäzungsregister für sonstige Betroffene")) { + return "0"; // General Powers + } else if (mandateContainer.getAnnotation().equals("Gesetzliche Vollmacht auf Basis Ergänzungsregister für sonstige Betroffene")) { + return "0"; // General Powers + } else if (mandateContainer.getAnnotation().contains("Gesetzliche Vollmacht auf Basis Erg")) { + return "0"; // General Powers + } else if (mandateContainer.getAnnotation().equals("GeneralvollmachtBilateral")) { + return "0"; // General Powers + } else if (mandateContainer.getAnnotation().contains("Gesetzliche Vollmacht auf Basis Firmenbuch")) { + return "0"; // General Powers + } else if (mandateContainer.getAnnotation().equals("ERsBMitPostvollmacht")) { + return "0"; // General Powers + } else if (mandateContainer.getAnnotation().equals("ZVR")) { + return "0"; // General Powers + } else if (mandateContainer.getAnnotation().equals("ZVRMitPostvollmacht")) { + return "0"; // General Powers + } else if (mandateContainer.getAnnotation().equals("EVB")) { + return "0"; // General Powers + } else if (mandateContainer.getAnnotation().equals("Einzelvertretungsbefugnis")) { + return "0"; // General Powers + } else if (mandateContainer.getAnnotation().equals("Prokura")) { + return "0"; // General Powers + } else if (mandateContainer.getAnnotation().equals("Notar")) { + return "0"; // General Powers + } else if (mandateContainer.getAnnotation().equals("Organwalter")) { + return "0"; // General Powers + } else if (mandateContainer.getAnnotation().equals("Rechtsanwalt")) { + return "0"; // General Powers + } else if (mandateContainer.getAnnotation().equals("Ziviltechniker")) { + return "0"; // General Powers + } + Logger.debug("Returning other type of mandate"); + return "9"; + } + + private MandateType getMandateType(MandateContainer mandateContainer, PersonalAttribute sourceAttribute) throws MOAIDException { + MandateType mandateType = new MandateType(); + RepresentationPersonType representative = getRepresentative(mandateContainer, sourceAttribute); + RepresentationPersonType represented = getRepresented(mandateContainer, sourceAttribute); + MandateContentType mandateContent = getMandateContent(mandateContainer, sourceAttribute); + mandateType.setRepresentative(representative); + mandateType.setRepresented(represented); + mandateType.getMandateContent().add(mandateContent); + Logger.debug("Complex attribute extracted: " + sourceAttribute.getName()); + return mandateType; + } + + private String getLegalName(MandateContainer mandateContainer, PersonalAttribute sourceAttribute) throws MOAIDException { + RepresentationPersonType represented = getRepresented(mandateContainer, sourceAttribute); + if (mandateContainer instanceof CorporateBodyMandateContainer) { + represented.getLegalName(); + //return represented.getName(); + } else if (sourceAttribute.isRequired()) { + Logger.error("Cannot provide legalName for natural person."); + throw new MOAIDException("stork.19", new Object[]{sourceAttribute.getName()}); + } + return ""; + } + + + private String getLegalIdentificationType(MandateContainer mandateContainer, PersonalAttribute sourceAttribute) throws MOAIDException { + if (mandateContainer instanceof CorporateBodyMandateContainer) { + return ((CorporateBodyMandateContainer) mandateContainer).getCorpMandatorIdentificationType(); + } else if (sourceAttribute.isRequired()) { + Logger.error("Cannot provide type for natural person."); + throw new MOAIDException("stork.19", new Object[]{sourceAttribute.getName()}); // TODO + } + return ""; + } + + private String getCompanyStatus(MandateContainer mandateContainer, PersonalAttribute sourceAttribute) throws MOAIDException { + String legalName = getLegalName(mandateContainer, sourceAttribute); + if (legalName.contains("in Liquidation") || legalName.contains("in Liqu.")) { + return "L"; // liqudation + } + return "R"; + } + + private String getCompanyType(String legalName, String legalIdentificationType, PersonalAttribute sourceAttrivbute) throws MOAIDException { + // compile patterns for different organisation types + // sources: USP, WKO, LexAndTax + + // gmbh patterns + ArrayList gmbhPatterns = new ArrayList(); + gmbhPatterns.add(Pattern.compile(".+ GmbH(( in Liquidation)|( in Liqu.)){0,1}$")); + gmbhPatterns.add(Pattern.compile(".+ GesmbH$")); + gmbhPatterns.add(Pattern.compile(".+ Gesellschaft mit beschränkter Haftung$")); + gmbhPatterns.add(Pattern.compile(".+ Ges\\.m\\.b\\.H\\.$")); + gmbhPatterns.add(Pattern.compile(".+ G\\.m\\.b\\.H\\.$")); + gmbhPatterns.add(Pattern.compile(".+ Handelsges\\.m\\.b\\.H\\.$")); + gmbhPatterns.add(Pattern.compile(".+ Gesellschaft m\\.b\\.H\\.$")); + + // ag patterns + ArrayList agPatterns = new ArrayList(); + agPatterns.add(Pattern.compile(".+ AG$")); + agPatterns.add(Pattern.compile(".+ Aktiengesellschaft$")); + + // og patterns + ArrayList ogPatterns = new ArrayList(); + ogPatterns.add(Pattern.compile(".+ OG$")); + ogPatterns.add(Pattern.compile(".+ OHG$")); + ogPatterns.add(Pattern.compile(".+ offene Gesellschaft$")); + + // kg patterns + ArrayList kgPatterns = new ArrayList(); + kgPatterns.add(Pattern.compile(".+ KG$")); + kgPatterns.add(Pattern.compile(".+ Kommanditgesellschaft$")); + + // eu patterns + ArrayList euPatterns = new ArrayList(); + euPatterns.add(Pattern.compile(".+ eingetragene Unternehmerin$")); + euPatterns.add(Pattern.compile(".+ eingetragener Unternehmer$")); + euPatterns.add(Pattern.compile(".+ e\\.U\\.$")); + + + // company patterns + HashMap> companyPatterns = new HashMap>(); + companyPatterns.put("GmbH", gmbhPatterns); + companyPatterns.put("AG", agPatterns); + companyPatterns.put("OG", ogPatterns); + companyPatterns.put("KG", kgPatterns); + companyPatterns.put("e.U.", euPatterns); + + // iterate over different types of companies and check if the name ending matches + if (S2Constants.IDENTIFICATION_TYPE_COMPANY.equals(legalIdentificationType)) { + for (String companyType : companyPatterns.keySet()) { + for (Pattern pattern : companyPatterns.get(companyType)) { + if (pattern.matcher(legalName).matches()) { + return companyType; + } + } + } + } + + // check if the subject is association + if (S2Constants.IDENTIFICATION_TYPE_ASSOCIATION.equals(legalIdentificationType)) { + return "Verein"; + } + + // check if the subject falls under category of others + if (S2Constants.IDENTIFICATION_TYPE_OTHERS.equals(legalIdentificationType)) { + return "ERsB"; + } + + return ""; + } + + private String getCompanyType(MandateContainer mandateContainer, PersonalAttribute sourceAttribute) throws MOAIDException { + // retrieve the registered subject name and identification type + String legalName = getLegalName(mandateContainer, sourceAttribute); + String legalIdentificationType = getLegalIdentificationType(mandateContainer, sourceAttribute); + return getCompanyType(legalName, legalIdentificationType, sourceAttribute); + } + + private String getCompanyTranslatableType(MandateContainer mandateContainer, PersonalAttribute sourceAttribute) throws MOAIDException { + // retrieve first the company type + String companyType = getCompanyType(mandateContainer, sourceAttribute); + + // translate company type based on the section 5.6 in STORK 2 D4.11 + if (companyType.length() == 0) { + return ""; + } else if (companyType.equals("GmbH")) { + return "G"; + } else if (companyType.equals("AG")) { + return "A"; + } else if (companyType.equals("OG")) { + return "O"; + } else if (companyType.equals("KG")) { + return "K"; + } else { + return ""; + } + } + + + private String getRepresentedStorkeIdentifier(MandateContainer mandateContainer) throws MOAIDException { + + if (!(mandateContainer instanceof PhyPersonMandateContainer)) { + Logger.error("Physical person mandate container missing"); + throw new MOAIDException("stork.20", new Object[]{}); // TODO + } + + PhyPersonMandateContainer phyPersonMandateContainer = (PhyPersonMandateContainer) mandateContainer; + + if (!phyPersonMandateContainer.getPhyPersMandatorIdentificationType().equals(Constants.URN_PREFIX_BASEID)) { + Logger.error("Identification type of represented person from MIS is not correct"); + throw new MOAIDException("stork.20", new Object[]{}); // TODO + } + + if (phyPersonMandateContainer.getPhyPersMandatorIdentificationValue().length() != 24) { + Logger.error("Identification value of represented person from MIS is not correct"); + throw new MOAIDException("stork.20", new Object[]{}); // TODO + } + + if ((this.moaStorkRequest.getStorkAttrQueryRequest().getSpCountry() == null) || (this.moaStorkRequest.getStorkAttrQueryRequest().getSpCountry().length() == 0)) { + Logger.error("Error accessing SP country code"); + throw new MOAIDException("stork.20", new Object[]{}); // TODO + } + + return geteIdentifier(phyPersonMandateContainer.getPhyPersMandatorIdentificationType(), phyPersonMandateContainer.getPhyPersMandatorIdentificationValue(), this.moaStorkRequest.getStorkAttrQueryRequest().getSpCountry()); + } + + private String getRepresentingStorkeIdentifier(MandateContainer mandateContainer) throws MOAIDException { + if ((this.representingIdentityLink == null)) { + Logger.error("Error accessing identityLink while fetching mandate attribute"); + throw new MOAIDException("stork.20", new Object[]{}); // TODO + } + + if ((this.moaStorkRequest.getStorkAttrQueryRequest().getSpCountry() == null) || (this.moaStorkRequest.getStorkAttrQueryRequest().getSpCountry().length() == 0)) { + Logger.error("Error accessing SP country code"); + throw new MOAIDException("stork.20", new Object[]{}); // TODO + } + + if (!this.representingIdentityLink.getIdentificationType().equals(Constants.URN_PREFIX_BASEID)) { + Logger.error("Incorrect identity link (local): identification type is not correct! Got: " + this.representingIdentityLink.getIdentificationType()); + throw new MOAIDException("stork.20", new Object[]{}); // TODO + } + + if (!mandateContainer.getPhysicalRepresentativeIdentificationType().equals(Constants.URN_PREFIX_BASEID)) { + Logger.error("Incorrect identity link (MIS): identification type is not correct! Got: " + this.representingIdentityLink.getIdentificationType() + " (representingIdentityLink) and " + mandateContainer.getPhysicalRepresentativeIdentificationType() + " (mandateContainer.phyRepresentative)"); + Logger.debug("mandatecontainervalue: " + mandateContainer.getPhysicalRepresentativeIdentificationValue() + ", representingidentitylinkvalue: " + this.representingIdentityLink.getIdentificationValue()); + throw new MOAIDException("stork.20", new Object[]{}); // TODO + } + + if (!mandateContainer.getPhysicalRepresentativeIdentificationValue().equals(this.representingIdentityLink.getIdentificationValue())) { + Logger.error("Identification values from MIS and local service are not equal!"); + throw new MOAIDException("stork.20", new Object[]{}); // TODO + } + + BPKBuilder bpkBuilder = new BPKBuilder(); + try { + return bpkBuilder.buildStorkeIdentifier(this.representingIdentityLink, this.moaStorkRequest.getStorkAttrQueryRequest().getSpCountry()); + } catch (BuildException be) { + Logger.error("Could not build STORK eIdentifier while generating mandate assertion."); + throw new MOAIDException("stork.20", new Object[]{}); // TODO + } + + } + + private RepresentationPersonType getRepresentative(MandateContainer mandateContainer, PersonalAttribute sourceAttribute) throws MOAIDException { + RepresentationPersonType representative = new RepresentationPersonType(); + + representative.setEIdentifier(getRepresentingStorkeIdentifier(mandateContainer)); + representative.setGivenName(mandateContainer.getPhysicalRepresentativeGivenName()); + representative.setSurname(mandateContainer.getPhysicalRepresentativeFamilyName()); + representative.setDateOfBirth(mandateContainer.getPhysicalRepresentativeBirthDate()); + + Logger.debug("Complex attribute extracted: " + sourceAttribute.getName()); + return representative; + } + + private RepresentationPersonType getRepresented(MandateContainer mandateContainer, PersonalAttribute sourceAttribute) throws MOAIDException { + RepresentationPersonType represented = new RepresentationPersonType(); + + if (mandateContainer instanceof CorporateBodyMandateContainer) { + CorporateBodyMandateContainer corporateBodyMandateContainer = (CorporateBodyMandateContainer) mandateContainer; + represented.setELPIdentifier(corporateBodyMandateContainer.getCorpMandatorIdentificationValue()); + represented.setLegalName(corporateBodyMandateContainer.getCorpMandatorFullName()); + represented.setTextRegisteredAddress(null); + represented.setCanonicalRegisteredAddress(new CanonicalAddressType()); + represented.setLegalForm(getCompanyType(corporateBodyMandateContainer.corpMandatorFullName, corporateBodyMandateContainer.corpMandatorIdentificationType, sourceAttribute)); + } else if (mandateContainer instanceof PhyPersonMandateContainer) { + PhyPersonMandateContainer phyPersonMandateContainer = (PhyPersonMandateContainer) mandateContainer; + represented.setEIdentifier(getRepresentedStorkeIdentifier(mandateContainer)); + represented.setGivenName(phyPersonMandateContainer.getPhyPersMandatorGivenName()); + represented.setSurname(phyPersonMandateContainer.getPhyPersMandatorFamilyName()); + represented.setDateOfBirth(phyPersonMandateContainer.getPhyPersMandatorBirthDate()); + } + + Logger.debug("Complex attribute extracted: " + sourceAttribute.getName()); + + return represented; + } + + + private MandateContentType getMandateContent(MandateContainer mandateContainer, PersonalAttribute sourceAttribute) throws MOAIDException { + MandateContentType mandateContent = new MandateContentType(); + try { + XMLGregorianCalendar validFrom = DatatypeFactory.newInstance().newXMLGregorianCalendar(mandateContainer.getMandateValidFrom()); + XMLGregorianCalendar validTo = DatatypeFactory.newInstance().newXMLGregorianCalendar(mandateContainer.getMandateValidTo()); + TimeRestrictionType timeRestriction = new TimeRestrictionType(); + timeRestriction.setValidFrom(validFrom); + timeRestriction.setValidTo(validTo); + mandateContent.setTimeRestriction(timeRestriction); + } catch (DatatypeConfigurationException dte) { + Logger.error("Error converting date from mandate: " + mandateContainer.getMandateValidFrom() + ", " + mandateContainer.getMandateValidTo()); + throw new MOAIDException("stork.20", new Object[]{}); + } + mandateContent.setAQAA(this.QAALevel); + mandateContent.setOriginalMandate(originalContent); + mandateContent.setOriginalMandateType("application/xml"); + TransactionLimitRestrictionType transactionLimit = new TransactionLimitRestrictionType(); + mandateContent.setTransactionLimit(transactionLimit); + mandateContent.setIsJoint(""); + mandateContent.setIsChained(false); + mandateContent.setTypeOfPower(mapPowersType(mandateContainer)); // TODO check + Logger.debug("Complex attribute extracted: " + sourceAttribute.getName()); + return mandateContent; + } + + public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) { + return true; + } + + public String getDefaultActionName() { + return STORKProtocol.MANDATERETRIEVALREQUEST; + } +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/PhyPersonMandateContainer.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/PhyPersonMandateContainer.java new file mode 100644 index 000000000..c715b65eb --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/PhyPersonMandateContainer.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * 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.MOAIDException; +import at.gv.egovernment.moa.logging.Logger; +import org.xml.sax.InputSource; + +import javax.xml.xpath.XPathExpressionException; +import java.io.StringReader; + +/** + * Physical person representing physical person + * @author bsuzic + * Date: 4/30/14, Time: 11:29 AM + */ +public class PhyPersonMandateContainer extends MandateContainer { + + private String phyPersMandatorIdentificationValue = null; + private String phyPersMandatorIdentificationType = null; + private String phyPersMandatorGivenName = null; + private String phyPersMandatorFamilyName = null; + private String phyPersMandatorBirthDate = null; + + String localMethods[] = new String[]{"getPhyPersMandatorGivenName", "getPhyPersMandatorFamilyName", "getPhyPersMandatorBirthDate", "getPhyPersMandatorIdentificationValue", + "getPhyPersMandatorIdentificationType", "getMandateIssuePlace", "getMandateIssueDate", "getMandateIssueTime", "getSimpleMandateContent", "getMandateValidFrom", + "getMandateValidTo", "getPhysicalRepresentativeIdentificationValue", "getPhysicalRepresentativeIdentificationType", "getAnnotation", + "getPhysicalRepresentativeGivenName", "getPhysicalRepresentativeFamilyName", "getPhysicalRepresentativeBirthDate" + }; + + + public PhyPersonMandateContainer(String mandate) throws XPathExpressionException, MOAIDException { + super(mandate); + + setAnnotation(xPath.evaluate(S2Constants.MANDATE_ANNOTATION_QUERY, new InputSource(new StringReader(mandate)))); + setPhyPersMandatorIdentificationType(xPath.evaluate(S2Constants.MANDATE_MANDATOR_PHYPERS_IDTYPE_QUERY, new InputSource(new StringReader(mandate)))); + setPhyPersMandatorIdentificationValue(xPath.evaluate(S2Constants.MANDATE_MANDATOR_PHYPERS_IDVALUE_QUERY, new InputSource(new StringReader(mandate)))); + setPhyPersMandatorGivenName(xPath.evaluate(S2Constants.MANDATE_MANDATOR_PHYPERS_GIVENNAME_QUERY, new InputSource(new StringReader(mandate)))); + setPhyPersMandatorFamilyName(xPath.evaluate(S2Constants.MANDATE_MANDATOR_PHYPERS_FAMILYNAME_QUERY, new InputSource(new StringReader(mandate)))); + setPhyPersMandatorBirthDate(xPath.evaluate(S2Constants.MANDATE_MANDATOR_PHYPERS_DATEOFBIRTH_QUERY, new InputSource(new StringReader(mandate)))); + setMandateIssueDate(xPath.evaluate(S2Constants.MANDATE_ISSUEDDATE_QUERY, new InputSource(new StringReader(mandate)))); + setMandateIssuePlace(xPath.evaluate(S2Constants.MANDATE_ISSUEDPLACE_QUERY, new InputSource(new StringReader(mandate)))); + setMandateIssueTime(xPath.evaluate(S2Constants.MANDATE_ISSUEDTIME_QUERY, new InputSource(new StringReader(mandate)))); + setMandateValidFrom(xPath.evaluate(S2Constants.MANDATE_SIMPLEMANDATECONTENT_VALIDFROM_QUERY, new InputSource(new StringReader(mandate)))); + setMandateValidTo(xPath.evaluate(S2Constants.MANDATE_SIMPLEMANDATECONTENT_VALIDTO_QUERY, new InputSource(new StringReader(mandate)))); + setPhysicalRepresentativeBirthDate(xPath.evaluate(S2Constants.MANDATE_REPRESENTATIVE_PHYPERS_DATEOFBIRTH_QUERY, new InputSource(new StringReader(mandate)))); + setPhysicalRepresentativeFamilyName(xPath.evaluate(S2Constants.MANDATE_REPRESENTATIVE_PHYPERS_FAMILYNAME_QUERY, new InputSource(new StringReader(mandate)))); + setPhysicalRepresentativeGivenName(xPath.evaluate(S2Constants.MANDATE_REPRESENTATIVE_PHYPERS_GIVENNAME_QUERY, new InputSource(new StringReader(mandate)))); + setPhysicalRepresentativeIdentificationType(xPath.evaluate(S2Constants.MANDATE_REPRESENTATIVE_PHYPERS_IDTYPE_QUERY, new InputSource(new StringReader(mandate)))); + setPhysicalRepresentativeIdentificationValue(xPath.evaluate(S2Constants.MANDATE_REPRESENTATIVE_PHYPERS_IDVALUE_QUERY, new InputSource(new StringReader(mandate)))); + setSimpleMandateContent(xPath.evaluate(S2Constants.MANDATE_SIMPLEMANDATECONTENT_TXTDESC_QUERY, new InputSource(new StringReader(mandate)))); + + // check if all necessary fields are present + Logger.debug("Starting mandate structure validation"); + try { + validateMandateStructure(localMethods); // TODO + } catch (Exception e) { + if (e instanceof MOAIDException) { + Logger.error("Could not validate mandate structure."); + throw new MOAIDException("stork.16", new Object[] {e.getMessage()}); // TODO + } else { + Logger.error("Error during mandate structure validation."); + throw new MOAIDException("stork.16", new Object[] {e.getMessage()}); // TODO + } + + } + } + + + + public String getPhyPersMandatorGivenName() { + return phyPersMandatorGivenName; + } + + public void setPhyPersMandatorGivenName(String phyPersMandatorGivenName) { + this.phyPersMandatorGivenName = phyPersMandatorGivenName; + } + + public String getPhyPersMandatorFamilyName() { + return phyPersMandatorFamilyName; + } + + public void setPhyPersMandatorFamilyName(String phyPersMandatorFamilyName) { + this.phyPersMandatorFamilyName = phyPersMandatorFamilyName; + } + + public String getPhyPersMandatorBirthDate() { + return phyPersMandatorBirthDate; + } + + public void setPhyPersMandatorBirthDate(String phyPersMandatorBirthDate) { + // making it conform to STORK dateOfBirth specifications, removing dash + this.phyPersMandatorBirthDate = phyPersMandatorBirthDate.replaceAll("-",""); + } + + public String getPhyPersMandatorIdentificationValue() { + return phyPersMandatorIdentificationValue; + } + + public void setPhyPersMandatorIdentificationValue(String phyPersMandatorIdentificationValue) { + this.phyPersMandatorIdentificationValue = phyPersMandatorIdentificationValue; + } + + public String getPhyPersMandatorIdentificationType() { + return phyPersMandatorIdentificationType; + } + + public void setPhyPersMandatorIdentificationType(String phyPersMandatorIdentificationType) { + this.phyPersMandatorIdentificationType = phyPersMandatorIdentificationType; + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/S2Constants.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/S2Constants.java new file mode 100644 index 000000000..a560bdaff --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/S2Constants.java @@ -0,0 +1,66 @@ +/******************************************************************************* + * 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; + +/** + * @author bsuzic + * Date: 4/29/14, Time: 5:34 PM + */ +public interface S2Constants { + public static final String MANDATE_PREFIX = "mandate"; + public static final String PERSONDATA_PREFIX = "persondata"; + public static final String XMLDSIG_PREFIX = "xmldsig"; + + public static final String MANDATE_NS = "http://reference.e-government.gv.at/namespace/mandates/20040701#"; + public static final String PERSONDATA_NS = "http://reference.e-government.gv.at/namespace/persondata/20020228#"; + public static final String XMLDSIG_NS = "http://www.w3.org/2000/09/xmldsig#"; + + public static final String MANDATE_ANNOTATION_QUERY = "/mandate:Mandate/mandate:Annotation/text()"; + public static final String MANDATE_REPRESENTATIVE_PHYPERS_IDVALUE_QUERY = "/mandate:Mandate/mandate:Representative/persondata:PhysicalPerson/persondata:Identification/persondata:Value/text()"; + public static final String MANDATE_REPRESENTATIVE_PHYPERS_IDTYPE_QUERY = "/mandate:Mandate/mandate:Representative/persondata:PhysicalPerson/persondata:Identification/persondata:Type/text()"; + public static final String MANDATE_REPRESENTATIVE_PHYPERS_GIVENNAME_QUERY = "/mandate:Mandate/mandate:Representative/persondata:PhysicalPerson/persondata:Name/persondata:GivenName/text()"; + public static final String MANDATE_REPRESENTATIVE_PHYPERS_FAMILYNAME_QUERY = "/mandate:Mandate/mandate:Representative/persondata:PhysicalPerson/persondata:Name/persondata:FamilyName/text()"; + public static final String MANDATE_REPRESENTATIVE_PHYPERS_DATEOFBIRTH_QUERY = "/mandate:Mandate/mandate:Representative/persondata:PhysicalPerson/persondata:DateOfBirth/text()"; + public static final String MANDATE_MANDATOR_CORPBODY_IDVALUE_QUERY = "/mandate:Mandate/mandate:Mandator/persondata:CorporateBody/persondata:Identification/persondata:Value/text()"; + public static final String MANDATE_MANDATOR_CORPBODY_IDTYPE_QUERY = "/mandate:Mandate/mandate:Mandator/persondata:CorporateBody/persondata:Identification/persondata:Type/text()"; + public static final String MANDATE_MANDATOR_CORPBODY_FULLNAME_QUERY = "/mandate:Mandate/mandate:Mandator/persondata:CorporateBody/persondata:FullName/text()"; + public static final String MANDATE_ISSUEDPLACE_QUERY = "/mandate:Mandate/mandate:Issued/mandate:Place/text()"; + public static final String MANDATE_ISSUEDDATE_QUERY = "/mandate:Mandate/mandate:Issued/mandate:Date/text()"; + public static final String MANDATE_ISSUEDTIME_QUERY = "/mandate:Mandate/mandate:Issued/mandate:Time/text()"; + public static final String MANDATE_SIMPLEMANDATECONTENT_TXTDESC_QUERY = "/mandate:Mandate/mandate:SimpleMandateContent/mandate:TextualDescription/text()"; + public static final String MANDATE_SIMPLEMANDATECONTENT_VALIDFROM_QUERY = "/mandate:Mandate/mandate:SimpleMandateContent/mandate:TimeConstraint/mandate:ValidFrom/text()"; + public static final String MANDATE_SIMPLEMANDATECONTENT_VALIDTO_QUERY = "/mandate:Mandate/mandate:SimpleMandateContent/mandate:TimeConstraint/mandate:ValidTo/text()"; + + public static final String MANDATE_MANDATOR_PHYPERS_IDVALUE_QUERY = "/mandate:Mandate/mandate:Mandator/persondata:PhysicalPerson/persondata:Identification/persondata:Value/text()"; + public static final String MANDATE_MANDATOR_PHYPERS_IDTYPE_QUERY = "/mandate:Mandate/mandate:Mandator/persondata:PhysicalPerson/persondata:Identification/persondata:Type/text()"; + public static final String MANDATE_MANDATOR_PHYPERS_GIVENNAME_QUERY = "/mandate:Mandate/mandate:Mandator/persondata:PhysicalPerson/persondata:Name/persondata:GivenName/text()"; + public static final String MANDATE_MANDATOR_PHYPERS_FAMILYNAME_QUERY = "/mandate:Mandate/mandate:Mandator/persondata:PhysicalPerson/persondata:Name/persondata:FamilyName/text()"; + public static final String MANDATE_MANDATOR_PHYPERS_DATEOFBIRTH_QUERY = "/mandate:Mandate/mandate:Mandator/persondata:PhysicalPerson/persondata:DateOfBirth/text()"; + + public static final String IDENTIFICATION_TYPE_COMPANY = "urn:publicid:gv.at:baseid+XFN"; + public static final String IDENTIFICATION_TYPE_ASSOCIATION = "urn:publicid:gv.at:baseid+XZVR"; + public static final String IDENTIFICATION_TYPE_OTHERS = "urn:publicid:gv.at:baseid+XERSB"; + + + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/STORKPVPUtilits.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/STORKPVPUtilits.java new file mode 100644 index 000000000..123d32af4 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/STORKPVPUtilits.java @@ -0,0 +1,49 @@ +/* + * 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 java.util.Arrays; +import java.util.List; + +/** + * @author tlenz + * + */ +public class STORKPVPUtilits { + + public static final List attributesRequirePVPAuthentication = + Arrays.asList("ECApplicationRole", "MSOrganization"); + + + + public static boolean performAuthenticationOnNationalIDP(MOASTORKRequest moastorkRequest) { + for (String el : attributesRequirePVPAuthentication) { + if (moastorkRequest.getPersonalAttributeList().containsKey(el)) { + return true; + + } + } + return false; + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/STORKProtocol.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/STORKProtocol.java new file mode 100644 index 000000000..071b5ae8a --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/STORKProtocol.java @@ -0,0 +1,233 @@ +/******************************************************************************* + * 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.MOAIDAuthConstants; +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +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.IAction; +import at.gv.egovernment.moa.id.moduls.IModulInfo; +import at.gv.egovernment.moa.id.moduls.IRequest; +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 javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.HashMap; + +/** + * Stork 2 Protocol Support + * + * @author bsuzic + */ +public class STORKProtocol extends MOAIDAuthConstants implements IModulInfo { + + public static final String NAME = STORKProtocol.class.getName(); + public static final String PATH = "id_stork2"; + + public static final String AUTHENTICATIONREQUEST = "AuthenticationRequest"; + public static final String ATTRIBUTE_COLLECTOR = "AttributeCollector"; + public static final String MANDATERETRIEVALREQUEST = "MandateRetrievalRequest"; + public static final String CONSENT_EVALUATOR = "ConsentEvaluator"; + + private static HashMap actions = new HashMap(); + + static { + actions.put(AUTHENTICATIONREQUEST, new AuthenticationRequest()); + actions.put(ATTRIBUTE_COLLECTOR, new AttributeCollector()); + actions.put(CONSENT_EVALUATOR, new ConsentEvaluator()); + actions.put(MANDATERETRIEVALREQUEST, new MandateRetrievalRequest()); + } + + public String getName() { + return NAME; + } + + public String getPath() { + return PATH; + } + + public IAction getAction(String action) { + return actions.get(action); + } + + public STORKProtocol() { + super(); + } + + /* + First request step - send it to BKU selection for user authentication. After the user credentials + and other info are obtained, in the second step the request will be processed and the user redirected + */ + public IRequest preProcess(HttpServletRequest request, HttpServletResponse response, String action, + String sessionId, String transactionId) throws MOAIDException { + Logger.info("Starting preprocessing for Stork2 protocol"); + Logger.debug("Request method: " + request.getMethod()); + Logger.debug("Request content length: " + request.getContentLength()); + Logger.debug("Initiating action: " + action); + + MOASTORKRequest STORK2Request = new MOASTORKRequest(); + MOASTORKResponse STORK2Response = new MOASTORKResponse(); + + + if (AttributeCollector.class.getSimpleName().equals(action) || ConsentEvaluator.class.getSimpleName().equals(action)) + return STORK2Request; + + + if (request.getParameter("SAMLResponse") != null) { // TODO check attribute collector + //extract STORK Response from HTTP Request + byte[] decSamlToken; + try { + decSamlToken = PEPSUtil.decodeSAMLToken(request.getParameter("SAMLResponse")); + } catch (NullPointerException e) { + if (request.getRemoteHost().contains("129.27.142")) { + Logger.warn("Availability check by " + request.getRemoteHost() + " on URI: " + request.getRequestURI()); + } else { + Logger.error("Unable to retrieve STORK Request for host: " + request.getRemoteHost() + " and URI: " + request.getRequestURI(), e); + } + throw new MOAIDException("stork.04", null); + } + + //Get SAMLEngine instance + STORKSAMLEngine engine = STORKSAMLEngine.getInstance("VIDP"); + + STORKAuthnResponse authnResponse = null; + + + // check if valid authn request is contained + try { + authnResponse = engine.validateSTORKAuthnResponse(decSamlToken, request.getRemoteAddr()); + } catch (STORKSAMLEngineException ex) { + Logger.error("Unable to validate Stork AuthenticationResponse: " + ex.getMessage()); + } + + STORK2Response.setSTORKAuthnResponseToken(decSamlToken); + + return STORK2Response; + + } else if (request.getParameter("SAMLRequest") != null) { + + //extract STORK Response from HTTP Request + byte[] decSamlToken; + try { + decSamlToken = PEPSUtil.decodeSAMLToken(request.getParameter("SAMLRequest")); + } catch (NullPointerException e) { + if (request.getRemoteHost().contains("129.27.142")) { + Logger.warn("Availability check by " + request.getRemoteHost() + " on URI: " + request.getRequestURI()); + } else { + Logger.error("Unable to retrieve STORK Request for host: " + request.getRemoteHost() + " and URI: " + request.getRequestURI(), e); + } + throw new MOAIDException("stork.04", null); + } + + //Get SAMLEngine instance + STORKSAMLEngine engine = STORKSAMLEngine.getInstance("VIDP"); + + STORKAuthnRequest authnRequest = null; + STORKAttrQueryRequest attrRequest = null; + + // check if valid authn request is contained + try { + authnRequest = engine.validateSTORKAuthnRequest(decSamlToken); + + } catch (STORKSAMLEngineException ex) { + Logger.error("Unable to validate Stork AuthenticationRequest: " + ex.getMessage()); + + } catch (ClassCastException e) { + // we do not have a authnRequest + // check if a valid attr request is container + try { + attrRequest = engine.validateSTORKAttrQueryRequest(decSamlToken); + + } catch (STORKSAMLEngineException ex) { + Logger.error("Unable to validate Stork AuthenticationRequest: " + ex.getMessage()); + + } + } + + // if there is no authn or attr request, raise error + if ((authnRequest == null) && (attrRequest == null)) { + Logger.error("There is no authentication or attribute request contained."); + throw new MOAIDException("stork.14", null); + } + // list attributes in the request + try { + for (PersonalAttribute personalAttribute : authnRequest.getPersonalAttributeList()) { + Logger.debug("Personal attribute found in request: " + personalAttribute.getName() + " isRequired: " + personalAttribute.isRequired()); + } + } catch (Exception e) { + Logger.error("Exception, attributes: " + e.getMessage()); + } + + STORK2Request.setSTORKAuthnRequest(authnRequest); + STORK2Request.setSTORKAttrRequest(attrRequest); + + //check if OA is instance of VIDP or STORKPVPGateway + OAAuthParameter oaParam = AuthConfigurationProviderFactory.getInstance().getOnlineApplicationParameter(STORK2Request.getOAURL()); + if (oaParam == null) + throw new AuthenticationException("stork.12", new Object[]{STORK2Request.getOAURL()}); + + else { + STORK2Request.setOnlineApplicationConfiguration(oaParam); + if (oaParam.isSTORKPVPGateway()) { + if (MiscUtil.isNotEmpty(oaParam.getSTORKPVPForwardEntity())) { + Logger.info("Received request for STORK->PVP gateway. " + + "Forward to PVP portal with entiyID " + oaParam.getSTORKPVPForwardEntity() + + " ..." ); + STORK2Request.setRequestedIDP(oaParam.getSTORKPVPForwardEntity()); + + } else { + Logger.error("InterfederatedGateway configuration with ID " + STORK2Request.getOAURL() + + " not configure a forward entityID."); + throw new MOAIDException("", null); + + } + } + + } + + return STORK2Request; + } else { + throw new MOAIDException("stork.14", null); // TODO Specify message + } + } + + public IAction canHandleRequest(HttpServletRequest request, HttpServletResponse response) { + return null; + } + + public boolean generateErrorMessage(Throwable e, HttpServletRequest request, HttpServletResponse response, IRequest protocolRequest) throws Throwable { + return false; + } + + public boolean validate(HttpServletRequest request, HttpServletResponse response, IRequest pending) { + return false; + } +} + + diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/SimpleNamespaceContext.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/SimpleNamespaceContext.java new file mode 100644 index 000000000..2c2df3e54 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/SimpleNamespaceContext.java @@ -0,0 +1,83 @@ +/* + * 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 java.util.HashMap; +import java.util.Iterator; +import java.util.Map.Entry; +import java.util.Set; + +import javax.xml.namespace.NamespaceContext; + +/** + * @author tlenz + * + */ +public class SimpleNamespaceContext implements NamespaceContext { + + HashMap prefMap = null; + /** + * @param prefMap + */ + SimpleNamespaceContext(HashMap prefMap) { + this.prefMap = prefMap; + } + + /* (non-Javadoc) + * @see javax.xml.namespace.NamespaceContext#getNamespaceURI(java.lang.String) + */ + @Override + public String getNamespaceURI(String prefix) { + if (prefMap.containsKey(prefix)) + return prefMap.get(prefix); + else + return null; + } + + /* (non-Javadoc) + * @see javax.xml.namespace.NamespaceContext#getPrefix(java.lang.String) + */ + @Override + public String getPrefix(String namespaceURI) { + if (prefMap.containsValue(namespaceURI)) { + Set> set = prefMap.entrySet(); + for (Entry el : set) { + if (el.getValue().equals(namespaceURI)) + return el.getKey(); + + } + } + + return null; + } + + /* (non-Javadoc) + * @see javax.xml.namespace.NamespaceContext#getPrefixes(java.lang.String) + */ + @Override + public Iterator getPrefixes(String namespaceURI) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/UnsupportedAttributeException.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/UnsupportedAttributeException.java new file mode 100644 index 000000000..31b9c9c0a --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/UnsupportedAttributeException.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * 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; + +public class UnsupportedAttributeException extends Exception { + + private static final long serialVersionUID = -7720066381435378111L; + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/AttributeProvider.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/AttributeProvider.java new file mode 100644 index 000000000..aaf13a779 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/AttributeProvider.java @@ -0,0 +1,139 @@ +/******************************************************************************* + * 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.attributeproviders; + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.protocols.stork2.ExternalAttributeRequestRequiredException; +import at.gv.egovernment.moa.id.protocols.stork2.MOASTORKRequest; +import at.gv.egovernment.moa.id.protocols.stork2.UnsupportedAttributeException; +import eu.stork.peps.auth.commons.IPersonalAttributeList; +import eu.stork.peps.auth.commons.PersonalAttribute; + +/** + * An {@link AttributeProvider} can fetch a set of stork attributes. It might complete the query within one method call, + * but might also need to redirect to another webservice to accomplish its task. + */ +public abstract class AttributeProvider implements Comparable{ + + protected String attributes; + + public AttributeProvider(String attributes){ + this.attributes = attributes; + } + + /** + * Acquire the specified attribute. Returns {@code null} when attribute retrieval is in progress, but requires for + * for redirecting the user to an external service. Use {@link AttributeProvider#parse(HttpServletRequest)} to parse + * the response. + * + * @param currentProviderConfiguredAttributes the list of attributes to be acquired + * @param moastorkRequest the sp county code + * @param authData the moasession + * @return the personal attribute + * @throws UnsupportedAttributeException the unsupported attribute exception + * @throws ExternalAttributeRequestRequiredException an attribute request to an external service has to be done + * @throws MOAIDException the mOAID exception + */ + protected abstract IPersonalAttributeList acquire(PersonalAttribute currentProviderConfiguredAttributes, MOASTORKRequest moastorkRequest, IAuthData authData) throws UnsupportedAttributeException, ExternalAttributeRequestRequiredException, MOAIDException; + + public IPersonalAttributeList acquire(List attributes, MOASTORKRequest moastorkRequest, IAuthData authData) throws UnsupportedAttributeException, ExternalAttributeRequestRequiredException, MOAIDException { + if (attributes.size() == 1) { + return acquire(attributes.get(0), moastorkRequest, authData); + } else { + throw new MOAIDException("stork.13", new Object[] { }); // TODO message only one attribute supported by this provider + + } + } + + /** + * Perform redirect. + * + * @param url the return URL ending with ?artifactId=... + * @param req the request we got from the S-PEPS and for which we have to ask our APs + * @param resp the response to the preceding request + * @param oaParam the oa param + * @throws MOAIDException the mOAID exception + */ + public abstract void performRedirect(String url, HttpServletRequest req, HttpServletResponse resp, OAAuthParameter oaParam) throws MOAIDException; + + /** + * Parses the response we got from the external attribute provider. + * + * @param httpReq the http req + * @return a list of attributes + * @throws UnsupportedAttributeException if the provider cannot find anything familiar in the provided httpReq + * @throws MOAIDException if something went wrong + */ + public abstract IPersonalAttributeList parse(HttpServletRequest httpReq) throws UnsupportedAttributeException, MOAIDException; + + /** + * Returns the list of supported attributes + * + * @return a list of attributes + * @throws MOAIDException if something went wrong + */ + public List getSupportedAttributeNames() throws MOAIDException { + ArrayList supportedAttributeNames = new ArrayList(); + for (String attributeName : this.attributes.split(",")) { + supportedAttributeNames.add(attributeName); + } + return supportedAttributeNames; + } + + + /** + * Returns the sequence priority of this attribute provider. + * Providers with small numbers are requested first. + * + * @return a sequence priority of this provider + */ + public abstract int getPriority(); + + /** + * Compare the sequence priority of two attribute providers + * @param o attribute provider + * @return 0 if priority is equal + * @return -1 if priority if this is higher then from o + * @return +1 if priority if o is higher then from this + */ + @Override + public int compareTo(AttributeProvider o) { + if (this.getPriority() == o.getPriority()) + return 0; + + if (this.getPriority() < o.getPriority()) + return -1; + + else + return +1; + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/EHvdAttributeProviderPlugin.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/EHvdAttributeProviderPlugin.java new file mode 100644 index 000000000..bd1576020 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/EHvdAttributeProviderPlugin.java @@ -0,0 +1,254 @@ +/******************************************************************************* + * 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.attributeproviders; + +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.Marshaller; +import javax.xml.soap.MessageFactory; +import javax.xml.soap.SOAPBody; +import javax.xml.soap.SOAPConnection; +import javax.xml.soap.SOAPConnectionFactory; +import javax.xml.soap.SOAPElement; +import javax.xml.soap.SOAPEnvelope; +import javax.xml.soap.SOAPMessage; +import javax.xml.soap.SOAPPart; + +import at.gv.egovernment.moa.id.auth.builder.BPKBuilder; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.protocols.stork2.ExternalAttributeRequestRequiredException; +import at.gv.egovernment.moa.id.protocols.stork2.MOASTORKRequest; +import at.gv.egovernment.moa.id.protocols.stork2.UnsupportedAttributeException; +import at.gv.egovernment.moa.logging.Logger; +import eu.stork.peps.auth.commons.IPersonalAttributeList; +import eu.stork.peps.auth.commons.PersonalAttribute; +import eu.stork.peps.auth.commons.PersonalAttributeList; +import eu.stork.peps.complex.attributes.eu.stork.names.tc.stork._1_0.assertion.AttributeStatusType; +import eu.stork.peps.complex.attributes.eu.stork.names.tc.stork._1_0.assertion.IsHealthCareProfessionalType; +import eu.stork.peps.complex.attributes.eu.stork.names.tc.stork._1_0.assertion.ObjectFactory; + +/** + * Fetches the attribute IsHealthcareProfessional from the BAGDAD SOAP service + */ +public class EHvdAttributeProviderPlugin extends AttributeProvider { + + /** The destination. */ + private Object destination; + + /** + * Instantiates a new e hvd attribute provider plugin. + * + * @param url the service url + * @param supportedAttributes + */ + public EHvdAttributeProviderPlugin(String url, String supportedAttributes) { + super(supportedAttributes); + destination = url; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#acquire(eu.stork.peps.auth.commons.PersonalAttribute) + */ + @Override + protected IPersonalAttributeList acquire(PersonalAttribute attribute, MOASTORKRequest moastorkRequest, IAuthData authData) + throws UnsupportedAttributeException, + ExternalAttributeRequestRequiredException, MOAIDException { + + // break when we cannot handle the requested attribute + if(!attributes.contains(attribute.getName())) + throw new UnsupportedAttributeException(); + + try { + Logger.debug("initializing SOAP connections..."); + // create SOAP connection + SOAPConnection soapConnection = SOAPConnectionFactory.newInstance().createConnection(); + + // assemble SOAP request + MessageFactory messageFactory = MessageFactory.newInstance(); + SOAPMessage requestMessage = messageFactory.createMessage(); + SOAPPart requestPart = requestMessage.getSOAPPart(); + + // (soap 1.1 relevant part. could not find a solution to use soap 1.2 in time. + requestMessage.getMimeHeaders().setHeader("SOAPAction", "http://gesundheit.gv.at/BAGDAD/DataAccessService/IsHealthcareProfessional"); + + /* + Construct SOAP Request Message: + + + + string + + + + + see https://stork.ehealth.gv.at/GDAService.asmx?op=IsHealthcareProfessional + */ + + // SOAP Envelope + SOAPEnvelope envelope = requestPart.getEnvelope(); + + // SOAP Body + SOAPBody requestBody = envelope.getBody(); + SOAPElement requestBodyElem = requestBody.addChildElement("IsHealthcareProfessional"); + requestBodyElem.addAttribute(envelope.createName("xmlns"), "http://gesundheit.gv.at/BAGDAD/DataAccessService"); + + SOAPElement requestBodyElem1 = requestBodyElem.addChildElement("bPK"); + + //TODO: CHECK: IdentificationValue containts wbPK if MOA-ID is used as VIDP + requestBodyElem1.addTextNode(new BPKBuilder().buildBPK(authData.getIdentificationValue(), "GH")); + + requestMessage.saveChanges(); + + // perform SOAP call + Logger.debug("call..."); + SOAPMessage responseMessage = soapConnection.call(requestMessage, destination); + + // parse SOAP response + + /* + + + + + boolean + string + boolean + string + string + string + + + + + + see https://stork.ehealth.gv.at/GDAService.asmx?op=IsHealthcareProfessional + */ + Logger.debug("call successful. Parse..."); + SOAPBody responseBody = responseMessage.getSOAPBody(); + + // iterate through tree + SOAPElement responseElement = (SOAPElement) responseBody.getChildElements().next(); + SOAPElement resultElement = (SOAPElement) responseElement.getChildElements().next(); + + // collect all info in a map + Iterator it = resultElement.getChildElements(); + Map collection = new HashMap(); + while (it.hasNext()) { + SOAPElement current = (SOAPElement) it.next(); + + collection.put(current.getNodeName(), current.getTextContent()); + } + + // check if there is anything valid in the map + if (collection.isEmpty() || collection.size() != 6) { + Logger.warn("eHVD returned an unexpected count of values. Expected 6 got " + collection.size()); + throw new IndexOutOfBoundsException("response attributes not like specified"); + } + + // - fetch request validity + if (collection.get("RequestOK").equals("false")) { + Logger.warn("eHVD reported an invalid request. The error message is: " + collection.get("Message")); + throw new Exception("eHVD reported an invalid request"); + } + + PersonalAttribute acquiredAttribute = null; + + if (collection.get("IsHealthcareProfessional").equals("false") || !collection.get("Type").equals("Medical doctor")) { + // the citizen is no HCP + acquiredAttribute = new PersonalAttribute("isHealthCareProfessional", false, new ArrayList(), AttributeStatusType.NOT_AVAILABLE.value()); + } else { + // go on and parse the data + IsHealthCareProfessionalType result = new IsHealthCareProfessionalType(); + + // TODO: we do not have any list of possible values yet. Fix as soon as we get some. +// if (collection.get("Type").equals("Medical doctor")) + result.setTypeOfHCP("physician"); + + result.setNameOfOrganisation(collection.get("NameOfOrganisation")); + //result.setTypeOfOrganisation("Unknown"); // TODO used in previous version, check what to do with this + + result.setAQAA(4); + + final Marshaller m = JAXBContext.newInstance(IsHealthCareProfessionalType.class).createMarshaller(); + m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); + + StringWriter stringWriter = new StringWriter(); + m.marshal(new ObjectFactory().createIsHealthCareProfessional(result), stringWriter); + + ArrayList value = new ArrayList(); + value.add(stringWriter.toString()); + + acquiredAttribute = new PersonalAttribute("isHealthCareProfessional", false, value, AttributeStatusType.AVAILABLE.value()); + } + + // pack and return the result + PersonalAttributeList result = new PersonalAttributeList(); + result.add(acquiredAttribute); + + // add stork id for verification + ArrayList value = new ArrayList(); + value.add(new BPKBuilder().buildStorkeIdentifier(authData.getIdentityLink(), moastorkRequest.getSpCountry())); + result.add(new PersonalAttribute("eIdentifier", false, value, AttributeStatusType.AVAILABLE.value())); + + return result; + } catch (Exception e) { + throw new MOAIDException("stork.13", new Object[] { e }); + } + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#performRedirect(java.lang.String, java.lang.String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, at.gv.egovernment.moa.id.config.auth.OAAuthParameter) + */ + public void performRedirect(String url, + HttpServletRequest req, HttpServletResponse resp, + OAAuthParameter oaParam) throws MOAIDException { + // there is no redirect required + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#parse(javax.servlet.http.HttpServletRequest) + */ + public IPersonalAttributeList parse(HttpServletRequest httpReq) + throws UnsupportedAttributeException, MOAIDException { + // there is no redirect required, so we throw an exception when someone asks us to parse a response + throw new UnsupportedAttributeException(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.attributeproviders.AttributeProvider#getPriority() + */ + @Override + public int getPriority() { + return 99; + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/MandateAttributeRequestProvider.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/MandateAttributeRequestProvider.java new file mode 100644 index 000000000..f671f0807 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/MandateAttributeRequestProvider.java @@ -0,0 +1,231 @@ +/******************************************************************************* + * 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.attributeproviders; + +import java.io.StringWriter; +import java.util.List; + +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 at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.protocols.stork2.ExternalAttributeRequestRequiredException; +import at.gv.egovernment.moa.id.protocols.stork2.MOASTORKRequest; +import at.gv.egovernment.moa.id.protocols.stork2.UnsupportedAttributeException; +import at.gv.egovernment.moa.id.util.HTTPUtils; +import at.gv.egovernment.moa.id.util.VelocityProvider; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.StringUtils; +import eu.stork.peps.auth.commons.IPersonalAttributeList; +import eu.stork.peps.auth.commons.PEPSUtil; +import eu.stork.peps.auth.commons.PersonalAttribute; +import eu.stork.peps.auth.commons.PersonalAttributeList; +import eu.stork.peps.auth.commons.STORKAttrQueryRequest; +import eu.stork.peps.auth.engine.STORKSAMLEngine; +import eu.stork.peps.exceptions.STORKSAMLEngineException; + +/** + * Provides mandate attribute from MIS + */ +public class MandateAttributeRequestProvider extends AttributeProvider { + /** + * The destination. + */ + private String destination; + + private String spCountryCode; + + private PersonalAttributeList requestedAttributes; + + public MandateAttributeRequestProvider(String aPurl, String supportedAttributes) throws MOAIDException { + super(supportedAttributes); + destination = aPurl; + + } + + public String getAttrProviderName() { + return "MandateAttributeRequestProvider"; + } + + // TODO check if used + @Override + protected IPersonalAttributeList acquire(PersonalAttribute attribute, MOASTORKRequest moastorkRequest, IAuthData authData) throws UnsupportedAttributeException, ExternalAttributeRequestRequiredException, MOAIDException { + Logger.info("Acquiring attribute: " + attribute.getName() + ", by: " + getAttrProviderName()); + this.spCountryCode = moastorkRequest.getSpCountry(); + requestedAttributes = new PersonalAttributeList(1); + requestedAttributes.add(attribute); + + // break if we cannot handle the requested attribute + if (!attributes.contains(attribute.getName())) { + Logger.info("Attribute " + attribute.getName() + " not supported by the provider: " + getAttrProviderName()); + throw new UnsupportedAttributeException(); + } + + // check if there is eIdentifier included and add if necessary +// if (!requestedAttributes.containsKey("eIdentifier")) { +// PersonalAttribute eIdentifier = new PersonalAttribute(); + // eIdentifier.setName("eIdentifier"); +// eIdentifier.setIsRequired(true); +// requestedAttributes.add(eIdentifier); +// } + + Logger.info("Thrown external request by: " + getAttrProviderName()); + throw new ExternalAttributeRequestRequiredException(this); + } + + @Override + public IPersonalAttributeList acquire(List attributes, MOASTORKRequest moastorkRequest, IAuthData moasession) throws UnsupportedAttributeException, ExternalAttributeRequestRequiredException, MOAIDException { + Logger.info("Acquiring " + attributes.size() + " attributes, by: " + getAttrProviderName()); + this.spCountryCode = moastorkRequest.getSpCountry(); + requestedAttributes = new PersonalAttributeList(attributes.size()); + + for (PersonalAttribute personalAttribute : attributes) { + // break if we cannot handle the requested attribute + if (!this.attributes.contains(personalAttribute.getName())) { + Logger.info("Attribute " + personalAttribute.getName() + " not supported by the provider: " + getAttrProviderName()); + throw new UnsupportedAttributeException(); + } + requestedAttributes.add(personalAttribute); + } + + // continue with other attribute providers if there are no attributes current provider is able to handle + if (requestedAttributes.size() == 0) { + Logger.info("Attribute(s) " + attributes.toString() + " not supported by the provider: " + getAttrProviderName()); + throw new UnsupportedAttributeException(); + } + + + + Logger.info("Thrown external request by: " + getAttrProviderName()); + throw new ExternalAttributeRequestRequiredException(this); + } + + + + + public void performRedirect(String url, HttpServletRequest req, HttpServletResponse resp, OAAuthParameter oaParam) throws MOAIDException { + + String spSector = "Business"; + String spInstitution = StringUtils.isEmpty(oaParam.getFriendlyName()) ? "UNKNOWN" : oaParam.getFriendlyName(); + String spApplication = spInstitution; + + if ((spCountryCode == null) || (spCountryCode.length()<2)) { + spCountryCode = oaParam.getTarget(); + Logger.info("Setting spcountry target: " + oaParam.getTarget()); + Logger.info("idlink ident " + oaParam.getIdentityLinkDomainIdentifier()); + Logger.info("idlink type " + oaParam.getIdentityLinkDomainIdentifierType()); + Logger.info("Setting spcountry target friendly : " + oaParam.getTargetFriendlyName()); + Logger.info("Oatype : " + oaParam.getOaType()); + Logger.info("puburl : " + oaParam.getPublicURLPrefix()); + if ("STORK".equals(oaParam.getIdentityLinkDomainIdentifierType())) { + + spCountryCode = oaParam.getIdentityLinkDomainIdentifier().substring(oaParam.getIdentityLinkDomainIdentifier().length()-2); + Logger.info("Set to " +spCountryCode); + } + + } + + // TODO ensure that other providers request eidentifier + // check if there is eIdentifier included and add if necessary + if (!requestedAttributes.containsKey("eIdentifier")) { + PersonalAttribute eIdentifier = new PersonalAttribute(); + eIdentifier.setName("eIdentifier"); + eIdentifier.setIsRequired(true); + requestedAttributes.add(eIdentifier); + } + + //generate AttrQueryRequest + STORKAttrQueryRequest attributeRequest = new STORKAttrQueryRequest(); + attributeRequest.setDestination(destination); + attributeRequest.setAssertionConsumerServiceURL(url); + attributeRequest.setIssuer(HTTPUtils.getBaseURL(req)); + attributeRequest.setQaa(oaParam.getQaaLevel()); + attributeRequest.setSpInstitution(spInstitution); + attributeRequest.setCountry(spCountryCode); + attributeRequest.setSpCountry(spCountryCode); + attributeRequest.setSpApplication(spApplication); + attributeRequest.setSpSector(spSector); + attributeRequest.setPersonalAttributeList(requestedAttributes); + + attributeRequest.setCitizenCountryCode("AT"); + attributeRequest.setQaa(oaParam.getQaaLevel()); + + if (attributeRequest.getQaa() == 0 ) { + attributeRequest.setQaa(4); // workaround + } + + + + Logger.info("STORK AttrRequest successfully assembled."); + + STORKSAMLEngine samlEngine = STORKSAMLEngine.getInstance("VIDP"); + try { + + attributeRequest = samlEngine.generateSTORKAttrQueryRequest(attributeRequest); + } catch (STORKSAMLEngineException e) { + Logger.error("Could not sign STORK SAML AttrRequest.", e); + throw new MOAIDException("stork.00", null); + } + + Logger.info("STORK AttrRequest successfully signed!"); + + try { + Logger.trace("Initialize VelocityEngine..."); + + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/saml2-post-binding-moa.vm"); + VelocityContext context = new VelocityContext(); + context.put("SAMLRequest", PEPSUtil.encodeSAMLToken(attributeRequest.getTokenSaml())); + context.put("action", destination); + + StringWriter writer = new StringWriter(); + template.merge(context, writer); + + resp.getOutputStream().write(writer.toString().getBytes("UTF-8")); + } catch (Exception e) { + Logger.error("Error sending STORK SAML AttrRequest.", e); + throw new MOAIDException("stork.11", null); + } + Logger.info("STORK AttrRequest successfully rendered!"); + + } + + public IPersonalAttributeList parse(HttpServletRequest httpReq) throws UnsupportedAttributeException, MOAIDException { + return null; // + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.attributeproviders.AttributeProvider#getPriority() + */ + @Override + public int getPriority() { + return 99; + } +} + diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/PVPAuthenticationProvider.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/PVPAuthenticationProvider.java new file mode 100644 index 000000000..7f06c604b --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/PVPAuthenticationProvider.java @@ -0,0 +1,238 @@ +/* + * 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.attributeproviders; + +import java.io.StringWriter; + +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 at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.protocols.stork2.ExternalAttributeRequestRequiredException; +import at.gv.egovernment.moa.id.protocols.stork2.MOASTORKRequest; +import at.gv.egovernment.moa.id.protocols.stork2.UnsupportedAttributeException; +import at.gv.egovernment.moa.id.util.HTTPUtils; +import at.gv.egovernment.moa.id.util.VelocityProvider; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.StringUtils; +import eu.stork.peps.auth.commons.IPersonalAttributeList; +import eu.stork.peps.auth.commons.PEPSUtil; +import eu.stork.peps.auth.commons.PersonalAttribute; +import eu.stork.peps.auth.commons.STORKAttrQueryRequest; +import eu.stork.peps.auth.commons.STORKAttrQueryResponse; +import eu.stork.peps.auth.commons.STORKAuthnRequest; +import eu.stork.peps.auth.commons.STORKAuthnResponse; +import eu.stork.peps.auth.engine.STORKSAMLEngine; +import eu.stork.peps.exceptions.STORKSAMLEngineException; + +/** + * @author tlenz + * + */ +public class PVPAuthenticationProvider extends AttributeProvider { + + private String destination = null; + private MOASTORKRequest moastorkRequest = null; + + /** + * @param attributes + * @param attributes2 + */ + public PVPAuthenticationProvider(String url, String attributes) { + super(attributes); + this.destination = url; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.attributeproviders.AttributeProvider#acquire(eu.stork.peps.auth.commons.PersonalAttribute, java.lang.String, at.gv.egovernment.moa.id.data.IAuthData) + */ + @Override + protected IPersonalAttributeList acquire(PersonalAttribute attribute, + MOASTORKRequest moastorkRequest, IAuthData authData) + throws UnsupportedAttributeException, + ExternalAttributeRequestRequiredException, MOAIDException { + + this.moastorkRequest = moastorkRequest; + // break if we cannot handle the requested attribute + if (!getSupportedAttributeNames().contains(attribute.getName())) { + Logger.info("Attribute " + attribute.getName() + " not supported by the provider: " + getAttrProviderName()); + throw new UnsupportedAttributeException(); + + } + + Logger.info("Thrown external request by: " + getAttrProviderName()); + throw new ExternalAttributeRequestRequiredException(this); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.attributeproviders.AttributeProvider#performRedirect(java.lang.String, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, at.gv.egovernment.moa.id.config.auth.OAAuthParameter) + */ + @Override + public void performRedirect(String url, HttpServletRequest req, + HttpServletResponse resp, OAAuthParameter oaParam) + throws MOAIDException { + + String spSector = "Business"; + String spInstitution = StringUtils.isEmpty(oaParam.getFriendlyName()) ? "UNKNOWN" : oaParam.getFriendlyName(); + String spApplication = spInstitution; + String spCountryCode = moastorkRequest.getSpCountry(); + + if ((spCountryCode == null) || (spCountryCode.length()<2)) { + spCountryCode = oaParam.getTarget(); + Logger.info("Setting spcountry target: " + oaParam.getTarget()); + Logger.info("idlink ident " + oaParam.getIdentityLinkDomainIdentifier()); + Logger.info("idlink type " + oaParam.getIdentityLinkDomainIdentifierType()); + Logger.info("Setting spcountry target friendly : " + oaParam.getTargetFriendlyName()); + Logger.info("Oatype : " + oaParam.getOaType()); + Logger.info("puburl : " + oaParam.getPublicURLPrefix()); + if ("STORK".equals(oaParam.getIdentityLinkDomainIdentifierType())) { + + spCountryCode = oaParam.getIdentityLinkDomainIdentifier().substring(oaParam.getIdentityLinkDomainIdentifier().length()-2); + Logger.info("Set to " +spCountryCode); + } + + } + + //generate AttrQueryRequest + STORKAuthnRequest authRequest = new STORKAuthnRequest(); + authRequest.setDestination(destination); + authRequest.setAssertionConsumerServiceURL(url); + authRequest.setIssuer(HTTPUtils.getBaseURL(req)); + authRequest.setQaa(oaParam.getQaaLevel()); + authRequest.setSpInstitution(spInstitution); + authRequest.setCountry(spCountryCode); + authRequest.setSpCountry(spCountryCode); + authRequest.setSpApplication(spApplication); + authRequest.setProviderName(spApplication); + authRequest.setSpSector(spSector); + authRequest.setPersonalAttributeList(moastorkRequest.getPersonalAttributeList()); + + authRequest.setCitizenCountryCode("AT"); + //authRequest.setQaa(oaParam.getQaaLevel()); + authRequest.setQaa(moastorkRequest.getStorkAuthnRequest().getQaa()); + + + + + Logger.info("STORK AttrRequest successfully assembled."); + + STORKSAMLEngine samlEngine = STORKSAMLEngine.getInstance("VIDP"); + try { + + authRequest = samlEngine.generateSTORKAuthnRequest(authRequest); + } catch (STORKSAMLEngineException e) { + Logger.error("Could not sign STORK SAML AttrRequest.", e); + throw new MOAIDException("stork.00", null); + } + + Logger.info("STORK AttrRequest successfully signed!"); + + //validate AuthnRequest + try { + samlEngine.validateSTORKAuthnRequest(authRequest.getTokenSaml()); + } catch (STORKSAMLEngineException e) { + Logger.error("STORK SAML AuthnRequest not valid.", e); + throw new MOAIDException("stork.01", null); + } + + Logger.debug("STORK AuthnRequest successfully internally validated."); + + try { + Logger.trace("Initialize VelocityEngine..."); + + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/saml2-post-binding-moa.vm"); + VelocityContext context = new VelocityContext(); + context.put("SAMLRequest", PEPSUtil.encodeSAMLToken(authRequest.getTokenSaml())); + context.put("action", destination); + + StringWriter writer = new StringWriter(); + template.merge(context, writer); + + resp.getOutputStream().write(writer.toString().getBytes("UTF-8")); + + } catch (Exception e) { + Logger.error("Error sending STORK SAML AttrRequest.", e); + throw new MOAIDException("stork.11", null); + + } + Logger.info("STORK AttrRequest successfully rendered!"); + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.attributeproviders.AttributeProvider#parse(javax.servlet.http.HttpServletRequest) + */ + @Override + public IPersonalAttributeList parse(HttpServletRequest httpReq) + throws UnsupportedAttributeException, MOAIDException { + + throw new UnsupportedAttributeException(); + +// Logger.info(this.getClass().getSimpleName() + " tries to extract SAMLResponse out of HTTP Request"); +// //extract STORK Response from HTTP Request +// //Decodes SAML Response +// byte[] decSamlToken; +// try { +// decSamlToken = PEPSUtil.decodeSAMLToken(httpReq.getParameter("SAMLResponse")); +// } catch(NullPointerException e) { +// throw new UnsupportedAttributeException(); +// } +// +// //Get SAMLEngine instance +// STORKSAMLEngine engine = STORKSAMLEngine.getInstance("VIDP"); +// +// STORKAuthnResponse authnResponse = null; +// try { +// //validate SAML Token +// Logger.debug("Starting validation of SAML response"); +// authnResponse = engine.validateSTORKAuthnResponse(decSamlToken, (String) httpReq.getRemoteHost()); +// Logger.info("SAML response successfully verified!"); +// +// }catch(STORKSAMLEngineException e){ +// Logger.error("Failed to verify STORK SAML Response", e); +// throw new MOAIDException("stork.05", null); +// } +// +// return authnResponse.getPersonalAttributeList(); + + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.attributeproviders.AttributeProvider#getPriority() + */ + @Override + public int getPriority() { + return 1; + } + + public String getAttrProviderName() { + return this.getClass().getName(); + } +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/SignedDocAttributeRequestProvider.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/SignedDocAttributeRequestProvider.java new file mode 100644 index 000000000..def89d0d9 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/SignedDocAttributeRequestProvider.java @@ -0,0 +1,688 @@ +/******************************************************************************* + * 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.attributeproviders; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.activation.DataSource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.namespace.QName; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; +import javax.xml.ws.Service; +import javax.xml.ws.soap.SOAPBinding; +import javax.xml.ws.BindingProvider; + +import eu.stork.peps.complex.attributes.eu.stork.names.tc.stork._1_0.assertion.AttributeStatusType; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.NotImplementedException; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; + +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.config.auth.AuthConfiguration; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProviderFactory; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.protocols.stork2.ExternalAttributeRequestRequiredException; +import at.gv.egovernment.moa.id.protocols.stork2.MOASTORKRequest; +import at.gv.egovernment.moa.id.protocols.stork2.UnsupportedAttributeException; +import at.gv.egovernment.moa.id.util.VelocityProvider; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Base64Utils; +import eu.stork.oasisdss.api.ApiUtils; +import eu.stork.oasisdss.api.LightweightSourceResolver; +import eu.stork.oasisdss.api.ResultMajor; +import eu.stork.oasisdss.api.exceptions.ApiUtilsException; +import eu.stork.oasisdss.profile.AnyType; +import eu.stork.oasisdss.profile.Base64Data; +import eu.stork.oasisdss.profile.DocumentType; +import eu.stork.oasisdss.profile.DocumentWithSignature; +import eu.stork.oasisdss.profile.IncludeObject; +import eu.stork.oasisdss.profile.SignRequest; +import eu.stork.oasisdss.profile.SignResponse; +import eu.stork.peps.auth.commons.IPersonalAttributeList; +import eu.stork.peps.auth.commons.PEPSUtil; +import eu.stork.peps.auth.commons.PersonalAttribute; +import eu.stork.peps.auth.commons.PersonalAttributeList; +import eu.stork.peps.auth.commons.STORKAttrQueryRequest; +import eu.stork.peps.auth.engine.STORKSAMLEngine; +import eu.stork.peps.exceptions.STORKSAMLEngineException; +import eu.stork.documentservice.DocumentService; +/** + * Forwards a signedDoc attribute request to the oasis-dss service instance + */ +public class SignedDocAttributeRequestProvider extends AttributeProvider { + + private String dtlUrl = null; + private PersonalAttribute requestedAttribute; + + /** + * The URL of the service listening for the oasis dss webform post request + */ + private String oasisDssWebFormURL; + + /** + * Instantiates a new signed doc attribute request provider. + * + * @param oasisDssWebFormURL + * the AP location + * @param attributes + */ + public SignedDocAttributeRequestProvider(String oasisDssWebFormURL, String attributes) { + super(attributes); + this.oasisDssWebFormURL = oasisDssWebFormURL; + + try { + AuthConfiguration authConfigurationProvider = AuthConfigurationProviderFactory.getInstance(); + dtlUrl = authConfigurationProvider.getDocumentServiceUrl(); + Logger.info ("SignedDocAttributeRequestProvider, using dtlUrl:"+dtlUrl); + } catch (Exception e) { + dtlUrl = "http://testvidp.buergerkarte.at/DocumentService/DocumentService"; + e.printStackTrace(); + Logger.error("Loading documentservice url failed, using default value:"+dtlUrl); + } + +// Properties props = new Properties(); +// try { +// props.load(DatabaseConnectorMySQLImpl.class.getResourceAsStream("docservice.properties")); +// dtlUrl = props.getProperty("docservice.url"); +// } catch (IOException e) { +// dtlUrl = "http://testvidp.buergerkarte.at/DocumentService/DocumentService"; +// Logger.error("Loading DTL config failed, using default value:"+dtlUrl); +// e.printStackTrace(); +// } + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#acquire(java + * .lang.String) + */ + @Override + protected IPersonalAttributeList acquire(PersonalAttribute attribute, MOASTORKRequest moastorkRequest, IAuthData authData) throws UnsupportedAttributeException, + ExternalAttributeRequestRequiredException { + if(!attributes.contains(attribute.getName())) { + throw new UnsupportedAttributeException(); + } + + requestedAttribute = attribute; + try + { + String tmp = requestedAttribute.getValue().get(0); + }catch(Exception e) + { + Logger.info("SignedDocAttributeProvide failed:"+e.toString()); + throw new UnsupportedAttributeException(); + } + + throw new ExternalAttributeRequestRequiredException(this); + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#parse(javax + * .servlet.http.HttpServletRequest) + */ + public IPersonalAttributeList parse(HttpServletRequest httpReq) throws MOAIDException, UnsupportedAttributeException { + Logger.debug("Beginning to extract OASIS-DSS response out of HTTP Request"); + + try { + String base64 = httpReq.getParameter("signresponse"); + Logger.debug("signresponse url: " + httpReq.getRequestURI().toString()); + Logger.debug("signresponse querystring: " + httpReq.getQueryString()); + Logger.debug("signresponse method: " + httpReq.getMethod()); + Logger.debug("signresponse content type: " + httpReq.getContentType()); + Logger.debug("signresponse parameter:"+base64); + String signResponseString = new String(Base64Utils.decode(base64, false), "UTF8"); + Logger.debug("RECEIVED signresponse:"+signResponseString); + //create SignResponse object + Source response = new StreamSource(new java.io.StringReader(signResponseString)); + SignResponse signResponse = ApiUtils.unmarshal(response, SignResponse.class); + //Check if Signing was successfully or not + + if(!signResponse.getResult().getResultMajor().equals(ResultMajor.RESULT_MAJOR_SUCCESS)) + { + //Pass unmodifed or unmarshal & marshal?? + InputStream istr = ApiUtils.marshalToInputStream(signResponse); + StringWriter writer = new StringWriter(); + IOUtils.copy(istr, writer, "UTF-8"); + signResponseString = writer.toString(); + Logger.info("SignResponse with error (unmodified):"+signResponseString); + istr.close(); + } + else + { + //extract doc from signresponse + DataSource dataSource = LightweightSourceResolver.getDataSource(signResponse); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + IOUtils.copy(dataSource.getInputStream(), baos); + byte[] data = baos.toByteArray(); + baos.close(); + + //update doc in DTL + String docId, dssId = ""; + docId = signResponse.getDocUI(); + //For reference dssId equals docId + dssId = docId; + if (dssId != null && data!=null) + { + boolean success = false; + try{ + success = updateDocumentInDtl(data, docId, signResponseString); + }catch(Exception e){//No document service used? + Logger.info("No document service used?"); + e.printStackTrace(); + success = false; + } + if(success) + { + // set the url in the SignResponse + DocumentWithSignature documentWithSignature = new DocumentWithSignature(); + DocumentType value = new DocumentType(); + if(dtlUrl.endsWith("?wsdl")) + { + String tmp = dtlUrl.replace("?wsdl", ""); + Logger.debug("DocumentUrl ends with ? wsdl, using "+tmp+" instead."); + value.setDocumentURL(tmp); + } + else + { + value.setDocumentURL(dtlUrl); + } + documentWithSignature.setDocument(value); + if(signResponse.getOptionalOutputs()!=null) + { + //signResponse.getOptionalOutputs().getAny().add(documentWithSignature); + for(Object o :signResponse.getOptionalOutputs().getAny()) + { + if(o instanceof DocumentWithSignature) + { + signResponse.getOptionalOutputs().getAny().remove(o); + signResponse.getOptionalOutputs().getAny().add(documentWithSignature); + break; + } + } + } + else + { + AnyType anytype = new AnyType(); + anytype.getAny().add(documentWithSignature); + signResponse.setOptionalOutputs(anytype ); + } + + // System.out.println("overwriting:"+signResponse.getResult().getResultMessage()+" with DTL url:"+dtlUrl); + InputStream istr = ApiUtils.marshalToInputStream(signResponse); + StringWriter writer = new StringWriter(); + IOUtils.copy(istr, writer, "UTF-8"); + signResponseString = writer.toString(); + Logger.info("SignResponse overwritten:"+signResponseString); + istr.close(); + } + else + { + //No document service used? + // do nothing.... + //TODO temporary fix because document is deleted after fetching => SP can't download Doc + //Add doc to Signresponse + + DocumentWithSignature documentWithSignature = new DocumentWithSignature(); + DocumentType value = new DocumentType(); + if(signResponse.getProfile().toLowerCase().contains("xades")) + { + value.setBase64XML(data); + } + else + { + Base64Data base64data = new Base64Data(); + base64data.setValue(data); + base64data.setMimeType(dataSource.getContentType()); + value.setBase64Data(base64data); + } + documentWithSignature.setDocument(value); + if(signResponse.getOptionalOutputs()!=null) + { + //signResponse.getOptionalOutputs().getAny().add(documentWithSignature); + for(Object o :signResponse.getOptionalOutputs().getAny()) + { + if(o instanceof DocumentWithSignature) + { + signResponse.getOptionalOutputs().getAny().remove(o); + signResponse.getOptionalOutputs().getAny().add(documentWithSignature); + break; + } + } + } + else + { + AnyType anytype = new AnyType(); + anytype.getAny().add(documentWithSignature); + signResponse.setOptionalOutputs(anytype ); + } + + // System.out.println("overwriting:"+signResponse.getResult().getResultMessage()+" with DTL url:"+dtlUrl); + InputStream istr = ApiUtils.marshalToInputStream(signResponse); + StringWriter writer = new StringWriter(); + IOUtils.copy(istr, writer, "UTF-8"); + signResponseString = writer.toString(); + Logger.info("SignResponse overwritten:"+signResponseString); + istr.close(); + } + } + else + throw new Exception("No DSS id found."); + } + + //alter signresponse + //done + List values = new ArrayList(); + values.add(signResponseString); + + Logger.debug("Assembling signedDoc attribute"); + PersonalAttribute signedDocAttribute = new PersonalAttribute("signedDoc", false, values, + AttributeStatusType.AVAILABLE.value()); + + // pack and return the result + PersonalAttributeList result = new PersonalAttributeList(); + result.add(signedDocAttribute); + return result; + } catch (UnsupportedEncodingException e) { + Logger.error("Failed to assemble signedDoc attribute"); + throw new MOAIDException("stork.05", null); + } catch (ApiUtilsException e) { + e.printStackTrace(); + Logger.error("Failed to assemble signedDoc attribute"); + throw new MOAIDException("stork.05", null); + } catch (IOException e) { + e.printStackTrace(); + Logger.error("Failed to assemble signedDoc attribute"); + throw new MOAIDException("stork.05", null); + } catch (Exception e) { + e.printStackTrace(); + Logger.error("Failed to assemble signedDoc attribute"); + //throw new MOAIDException("stork.05", null); + throw new UnsupportedAttributeException(); + } + } + + /* + * (non-Javadoc) + * + * @see + * at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#performRedirect + * (java.lang.String) + */ + public void performRedirect(String url, HttpServletRequest req, HttpServletResponse resp, OAAuthParameter oaParam) + throws MOAIDException { + + try { + Logger.trace("Initialize VelocityEngine..."); + Logger.info("performRedirect url:"+url); + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/oasis_dss_webform_binding.vm"); + VelocityContext context = new VelocityContext(); + + //Parse SignRequest + String signRequestString = requestedAttribute.getValue().get(0); + Logger.debug("performRedirect, signrequest:"+signRequestString); + Source signDoc = new StreamSource(new java.io.StringReader(signRequestString)); + SignRequest signRequest = ApiUtils.unmarshal(signDoc, SignRequest.class); + try{ + //search for DTL link + String dtlURL = getDtlUrlFromRequest(signRequest); + String docId = signRequest.getDocUI(); + + if(dtlURL!=null) + { + String docRequest = getDocTransferRequest(docId, dtlURL);//dtlUrl + + byte[] data = getDocumentFromDtl(docRequest, dtlURL);//dtlUrl + + //load doc from DTL + Logger.debug("data:"+data+" "+data.length); + try{ + Logger.trace("data:"+new String(data,"UTF-8")); + }catch(Exception e) + { + Logger.trace("data: creating String failed:"+e); + } + String mime = getDocumentMimeFromDtl(docId, dtlURL);//dtlUrl + Logger.debug("mime:"+mime); + + //add doc as base64* to signrequest => post doc to oasis + try{ + List includeObjects = ApiUtils.findNamedElement( + signRequest.getOptionalInputs(), "IncludeObject", + IncludeObject.class); + signRequest.getOptionalInputs().getAny().removeAll(includeObjects); + + String documentId = null; + Object objDoc = signRequest.getInputDocuments().getDocumentOrTransformedDataOrDocumentHash().get(0); + if (objDoc != null && objDoc instanceof DocumentType) + { + DocumentType document = (DocumentType)objDoc; + documentId = document.getID(); + } + DocumentType document = new DocumentType(); + if(documentId != null) + document.setID(documentId); + if(signRequest.getProfile().toLowerCase().contains("xades")) + { + document.setBase64XML(data); + } + else + { + Base64Data b64data = new Base64Data(); + b64data.setValue(data); + b64data.setMimeType(mime); + document.setBase64Data(b64data); + } + + signRequest.setInputDocuments(ApiUtils.createInputDocuments(document)); + //override old signRequestString + + InputStream istr = ApiUtils.marshalToInputStream(signRequest); + StringWriter writer = new StringWriter(); + IOUtils.copy(istr, writer, "UTF-8"); + signRequestString = writer.toString(); + Logger.info("Signrequest overwritten"); + Logger.debug("Signrequest overwritten:"+signRequestString); + istr.close(); + } catch (Exception e) { + e.printStackTrace(); + throw new Exception("Could not marshall sign request", e); + } + } + else//Do not modify signRequest, document is already included + { + + } + }catch(Exception e) + { + Logger.info("No documentservice used?"); + e.printStackTrace(); + } + + context.put("signrequest", Base64Utils.encode(signRequestString.getBytes("UTF8"))); + context.put("clienturl", url); + context.put("action", oasisDssWebFormURL); + + StringWriter writer = new StringWriter(); + template.merge(context, writer); + + resp.getOutputStream().write(writer.toString().getBytes("UTF-8")); + } catch (Exception e) { + Logger.error("Error sending DSS signrequest.", e); + throw new MOAIDException("stork.11", null); + } + } + + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#getSupportedAttributeNames() + */ + @Override + public List getSupportedAttributeNames() throws MOAIDException { + ArrayList supportedAttributeNames = new ArrayList(); + for (String attributeName : this.attributes.split(",")) { + supportedAttributeNames.add(attributeName); + } + return supportedAttributeNames; + } + + + //From DTLPEPSUTIL + + /** + * Get DTL uril from the oasis sign request + * @param signRequest The signature request + * @return The URL of DTL service + * @throws SimpleException + */ + private String getDtlUrlFromRequest(SignRequest signRequest) throws Exception + { + if (signRequest == null) + throw new Exception("Signature request is empty"); + else + { + try + { + Object objDoc = signRequest.getInputDocuments().getDocumentOrTransformedDataOrDocumentHash().get(0); + if (objDoc instanceof DocumentType) + { + DocumentType document = (DocumentType)objDoc; + if (document.getDocumentURL() != null) + return document.getDocumentURL(); + else + return null;//throw new Exception("No document url found"); + } + else + throw new Exception("No input document found"); + } + catch (Exception ex) + { + throw new Exception("Unable to parse xml.", ex); + } + } + } + + /** + * Get document from DTL + * @param transferRequest The transfer request (attribute query) + * @param eDtlUrl The DTL url of external DTL + * @return the document data + * @throws SimpleException + */ + private byte[] getDocumentFromDtl(String transferRequest, String eDtlUrl) throws Exception + { + URL url = null; + try + { + Logger.debug("getDocumentFromDtl:"+dtlUrl); + url = new URL(dtlUrl); + QName qname = new QName("http://stork.eu", + "DocumentService"); + + Service service = Service.create(url, qname); + DocumentService docservice = service.getPort(DocumentService.class); + + BindingProvider bp = (BindingProvider) docservice; + SOAPBinding binding = (SOAPBinding) bp.getBinding(); + binding.setMTOMEnabled(true); + + if (eDtlUrl.equalsIgnoreCase(dtlUrl)) + return docservice.getDocument(transferRequest, ""); + else + return docservice.getDocument(transferRequest, eDtlUrl); + } + catch (Exception e) + { + e.printStackTrace(); + throw new Exception("Error in getDocumentFromDtl", e); + } + } + + /** + * Get a document transfer request (attribute query) + * @param docId + * @return + * @throws SimpleException + */ + private String getDocTransferRequest(String docId, String destinationUrl) throws Exception + { + String spCountry = docId.substring(0, docId.indexOf("/")); + final STORKSAMLEngine engine = STORKSAMLEngine.getInstance("VIDP"); + STORKAttrQueryRequest req = new STORKAttrQueryRequest(); + req.setAssertionConsumerServiceURL(dtlUrl); + req.setDestination(destinationUrl); + req.setSpCountry(spCountry); + req.setQaa(3);//TODO + PersonalAttributeList pal = new PersonalAttributeList(); + PersonalAttribute attr = new PersonalAttribute(); + attr.setName("docRequest"); + attr.setIsRequired(true); + attr.setValue(Arrays.asList(docId)); + pal.add(attr); + req.setPersonalAttributeList(pal); + + STORKAttrQueryRequest req1; + try { + req1 = engine.generateSTORKAttrQueryRequest(req); + return PEPSUtil.encodeSAMLTokenUrlSafe(req1.getTokenSaml()); + } catch (STORKSAMLEngineException e) { + e.printStackTrace(); + throw new Exception("Error in doc request attribute query generation", e); + } + } + + /** + * Get mime type of document from DTL + * @param docId The document id + * @param dtlUrl The url of dtl + * @return The mime type + */ + private String getDocumentMimeFromDtl(String docId, String eDtlUrl) throws Exception + { + URL url = null; + try + { + url = new URL(dtlUrl); + QName qname = new QName("http://stork.eu", + "DocumentService"); + + Service service = Service.create(url, qname); + DocumentService docservice = service.getPort(DocumentService.class); + + BindingProvider bp = (BindingProvider) docservice; + SOAPBinding binding = (SOAPBinding) bp.getBinding(); + binding.setMTOMEnabled(true); + + if (eDtlUrl.equalsIgnoreCase(dtlUrl)) + return docservice.getDocumentMime(docId, ""); + else + return docservice.getDocumentMime(docId, eDtlUrl); + } + catch (Exception e) + { + e.printStackTrace(); + throw new Exception("Error in getDocumentFromDtl", e); + } + } + + /** + * Add document to DTL service + * @param docData the document data + * @param mime the mime type of data + * @param signRequest the sign request + * @return the document id + * @throws SimpleException + */ + private String addDocumentToDtl(byte[] docData, String mime, String signRequest, String destCountry, String spId) throws Exception + { + throw new NotImplementedException(); +// URL url = null; +// String docID = null; +// try +// { +// url = new URL(dtlUrl); +// QName qname = new QName("http://stork.eu", +// "DocumentService"); +// +// Service service = Service.create(url, qname); +// DocumentService docservice = service.getPort(DocumentService.class); +// +// BindingProvider bp = (BindingProvider) docservice; +// SOAPBinding binding = (SOAPBinding) bp.getBinding(); +// binding.setMTOMEnabled(true); +// +// docID = docservice.addDocument(docData, signRequest, destCountry, spId, mime, ""); +// } +// catch (Exception e) +// { +// e.printStackTrace(); +// throw new Exception("Error in addDocumentToDtl", e); +// } +// +// return docID; + } + + /** + * Update document in DTL + * @param docData The docment data + * @param docId The document ID + * @param signResponse The signature response + * @return True if successful + * @throws SimpleException + */ + private boolean updateDocumentInDtl(byte[] docData, String docId, String signResponse) throws Exception + { + boolean success = false; + URL url = null; + try + { + url = new URL(dtlUrl); + QName qname = new QName("http://stork.eu", + "DocumentService"); + + Service service = Service.create(url, qname); + DocumentService docservice = service.getPort(DocumentService.class); + + BindingProvider bp = (BindingProvider) docservice; + SOAPBinding binding = (SOAPBinding) bp.getBinding(); + binding.setMTOMEnabled(true); + + success = docservice.updateDocument(docId, signResponse, docData); + } + catch (Exception e) + { + e.printStackTrace(); + throw new Exception("Error in updateDocumentInDtl", e); + } + + return success; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.attributeproviders.AttributeProvider#getPriority() + */ + @Override + public int getPriority() { + return 99; + } +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/StorkAttributeRequestProvider.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/StorkAttributeRequestProvider.java new file mode 100644 index 000000000..5ee0e380e --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/attributeproviders/StorkAttributeRequestProvider.java @@ -0,0 +1,193 @@ +/******************************************************************************* + * 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.attributeproviders; + +import java.io.StringWriter; + +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 at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.data.IAuthData; +import at.gv.egovernment.moa.id.protocols.stork2.ExternalAttributeRequestRequiredException; +import at.gv.egovernment.moa.id.protocols.stork2.MOASTORKRequest; +import at.gv.egovernment.moa.id.protocols.stork2.UnsupportedAttributeException; +import at.gv.egovernment.moa.id.util.HTTPUtils; +import at.gv.egovernment.moa.id.util.VelocityProvider; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.StringUtils; +import eu.stork.peps.auth.commons.IPersonalAttributeList; +import eu.stork.peps.auth.commons.PEPSUtil; +import eu.stork.peps.auth.commons.PersonalAttribute; +import eu.stork.peps.auth.commons.PersonalAttributeList; +import eu.stork.peps.auth.commons.STORKAttrQueryRequest; +import eu.stork.peps.auth.commons.STORKAttrQueryResponse; +import eu.stork.peps.auth.engine.STORKSAMLEngine; +import eu.stork.peps.exceptions.STORKSAMLEngineException; + +/** + * creates a STORK attribute request for a configurable set of attributes + */ +public class StorkAttributeRequestProvider extends AttributeProvider { + + private PersonalAttributeList requestedAttributes; + + /** The destination. */ + private String destination; + + /** The sp country code. */ + private String spCountryCode; + + /** + * Instantiates a new stork attribute request provider. + * + * @param apUrl the AP location + * @param supportedAttributes the supported attributes as csv + */ + public StorkAttributeRequestProvider(String apUrl, String supportedAttributes) { + super(supportedAttributes); + destination = apUrl; + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#acquire(java.lang.String) + */ + @Override + protected IPersonalAttributeList acquire(PersonalAttribute attribute, MOASTORKRequest moastorkRequest, IAuthData authData) + throws UnsupportedAttributeException, ExternalAttributeRequestRequiredException { + + if (!attributes.contains(attribute.getName())) + throw new UnsupportedAttributeException(); + + this.spCountryCode = moastorkRequest.getSpCountry(); + + requestedAttributes = new PersonalAttributeList(1); + requestedAttributes.add(attribute); + throw new ExternalAttributeRequestRequiredException(this); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#parse(javax.servlet.http.HttpServletRequest) + */ + public IPersonalAttributeList parse(HttpServletRequest httpReq) throws MOAIDException, UnsupportedAttributeException { + + Logger.info(this.getClass().getSimpleName() + " tries to extract SAMLResponse out of HTTP Request"); + + //extract STORK Response from HTTP Request + //Decodes SAML Response + byte[] decSamlToken; + try { + decSamlToken = PEPSUtil.decodeSAMLToken(httpReq.getParameter("SAMLResponse")); + } catch(NullPointerException e) { + throw new UnsupportedAttributeException(); + } + + //Get SAMLEngine instance + STORKSAMLEngine engine = STORKSAMLEngine.getInstance("VIDP"); + + STORKAttrQueryResponse attrResponse = null; + try { + //validate SAML Token + Logger.debug("Starting validation of SAML response"); + attrResponse = engine.validateSTORKAttrQueryResponse(decSamlToken, (String) httpReq.getRemoteHost()); + Logger.info("SAML response successfully verified!"); + }catch(STORKSAMLEngineException e){ + Logger.error("Failed to verify STORK SAML Response", e); + throw new MOAIDException("stork.05", null); + } + + return attrResponse.getPersonalAttributeList(); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#performRedirect(java.lang.String) + */ + public void performRedirect(String url, HttpServletRequest req, HttpServletResponse resp, OAAuthParameter oaParam) throws MOAIDException { + + String spSector = "Business"; + String spInstitution = StringUtils.isEmpty(oaParam.getFriendlyName()) ? "UNKNOWN" : oaParam.getFriendlyName(); + String spApplication = spInstitution; + + //generate AuthnRquest + STORKAttrQueryRequest attributeRequest = new STORKAttrQueryRequest(); + attributeRequest.setDestination(destination); + attributeRequest.setAssertionConsumerServiceURL(url); + attributeRequest.setIssuer(HTTPUtils.getBaseURL(req)); + attributeRequest.setQaa(oaParam.getQaaLevel()); + attributeRequest.setSpInstitution(spInstitution); + attributeRequest.setCountry(spCountryCode); + attributeRequest.setSpCountry(spCountryCode); + attributeRequest.setSpApplication(spApplication); + attributeRequest.setSpSector(spSector); + attributeRequest.setPersonalAttributeList(requestedAttributes); + + attributeRequest.setCitizenCountryCode("AT"); + + + Logger.debug("STORK AttrRequest successfully assembled."); + + STORKSAMLEngine samlEngine = STORKSAMLEngine.getInstance("VIDP"); + try { + attributeRequest = samlEngine.generateSTORKAttrQueryRequest(attributeRequest); + } catch (STORKSAMLEngineException e) { + Logger.error("Could not sign STORK SAML AttrRequest.", e); + throw new MOAIDException("stork.00", null); + } + Logger.info("Using citizen country code: " + attributeRequest.getCitizenCountryCode()); + Logger.info("STORK AttrRequest successfully signed!"); + + try { + Logger.trace("Initialize VelocityEngine..."); + + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/saml2-post-binding-moa.vm"); + VelocityContext context = new VelocityContext(); + context.put("SAMLRequest", PEPSUtil.encodeSAMLToken(attributeRequest.getTokenSaml())); + context.put("action", destination); + + StringWriter writer = new StringWriter(); + template.merge(context, writer); + + resp.getOutputStream().write(writer.toString().getBytes("UTF-8")); + } catch (Exception e) { + Logger.error("Error sending STORK SAML AttrRequest.", e); + throw new MOAIDException("stork.11", null); + } + Logger.info("STORK AttrRequest successfully rendered!"); + } + + /* (non-Javadoc) + * @see at.gv.egovernment.moa.id.protocols.stork2.attributeproviders.AttributeProvider#getPriority() + */ + @Override + public int getPriority() { + return 99; + } + +} + -- cgit v1.2.3