diff options
| author | Thomas Lenz <tlenz@iaik.tugraz.at> | 2015-09-11 18:23:33 +0200 | 
|---|---|---|
| committer | Thomas Lenz <tlenz@iaik.tugraz.at> | 2015-09-11 18:23:33 +0200 | 
| commit | 3536b99c17250772f253ea5925da72a29e327c58 (patch) | |
| tree | 672cd61bd324e845e322c518223a14e0b1d82fbd /id/server/modules/module-stork/src | |
| parent | aa1dda4e14e7aebd3ec0df5e50493d273a65d999 (diff) | |
| download | moa-id-spss-3536b99c17250772f253ea5925da72a29e327c58.tar.gz moa-id-spss-3536b99c17250772f253ea5925da72a29e327c58.tar.bz2 moa-id-spss-3536b99c17250772f253ea5925da72a29e327c58.zip | |
move authentication protocol implementation to separate modules.
authentication protocol modules are loaded by SPI now.
Diffstat (limited to 'id/server/modules/module-stork/src')
25 files changed, 5434 insertions, 0 deletions
| 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<AttributeProvider> 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<PersonalAttribute> missingAttributes = new ArrayList<PersonalAttribute>(); +        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<AttributeProvider> 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<PersonalAttribute> currentProviderConfiguredAttributes = new ArrayList<PersonalAttribute>(); +                    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<String> 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<AttributeProvider> getConfiguredPlugins( +            Collection<StorkAttributeProviderPlugin> collection) { + +    	PriorityQueue<AttributeProvider> result = new PriorityQueue<AttributeProvider>(); +        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<String>()); +				current.setComplexValue(new HashMap<String, String>()); +			} +		} + +        //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 += "<tr><td><input type=\"checkbox\" checked=\"yes\" name=\"" + current.getName() + "\"></td><td>" + current.getName() + (current.isRequired() ? "" : " (optional)") + "</td></tr>\n"; + +			context.put("tablecontent", table); +			for(Entry<String, String> 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<String, String> storkAttributeSimpleMapping; +    private static final Map<String, String> storkAttributeFunctionMapping; +    private final MOASTORKRequest moastorkRequest; + +    // mappings for attribute population methods +    // based on mapping of moa authndata and executing functions to extract attributes +    static { +        Map<String, String> tempSimpleMap = new HashMap<String, String>(); +        tempSimpleMap.put("givenName", "getGivenName"); +        tempSimpleMap.put("surname", "getFamilyName");         +        tempSimpleMap.put("MSOrganization", "getPvpAttribute_OU"); +        storkAttributeSimpleMapping = Collections.unmodifiableMap(tempSimpleMap); +                 +        Map<String, String> tempFunctionMap = new HashMap<String, String>(); +        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<String> getECApplicationRole(PersonalAttribute personalAttribute) { +    	List<String> storkRoles = null; +    	    	 +    	if (authData.getAuthenticationRoles() != null  +    			&& authData.getAuthenticationRoles().size() > 0) { + +    		storkRoles = new ArrayList<String>(); +    		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<String>(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<String>) 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<String> 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<Attribute> 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<Attribute>(); +		 +	} +} 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<Attribute> 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<String, String> prefMap = new HashMap<String, String>() {{ +            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("<pd:Value>.*?==</pd:Value><pd:Type>urn:publicid:gv.at:baseid</pd:Type>","<pd:Value></pd:Value><pd:Type></pd:Type>");; +        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<MandateContentType>(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<MandateType>(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<RepresentationPersonType>(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<String>(), AttributeStatusType.NOT_AVAILABLE.value()); +        } +        ArrayList<String> value = new ArrayList<String>(); +        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<Pattern> gmbhPatterns = new ArrayList<Pattern>(); +        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<Pattern> agPatterns = new ArrayList<Pattern>(); +        agPatterns.add(Pattern.compile(".+ AG$")); +        agPatterns.add(Pattern.compile(".+ Aktiengesellschaft$")); + +        // og patterns +        ArrayList<Pattern> ogPatterns = new ArrayList<Pattern>(); +        ogPatterns.add(Pattern.compile(".+ OG$")); +        ogPatterns.add(Pattern.compile(".+ OHG$")); +        ogPatterns.add(Pattern.compile(".+ offene Gesellschaft$")); + +        // kg patterns +        ArrayList<Pattern> kgPatterns = new ArrayList<Pattern>(); +        kgPatterns.add(Pattern.compile(".+ KG$")); +        kgPatterns.add(Pattern.compile(".+ Kommanditgesellschaft$")); + +        // eu patterns +        ArrayList<Pattern> euPatterns = new ArrayList<Pattern>(); +        euPatterns.add(Pattern.compile(".+ eingetragene Unternehmerin$")); +        euPatterns.add(Pattern.compile(".+ eingetragener Unternehmer$")); +        euPatterns.add(Pattern.compile(".+ e\\.U\\.$")); + + +        // company patterns +        HashMap<String, ArrayList<Pattern>> companyPatterns = new HashMap<String, ArrayList<Pattern>>(); +        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<String> 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<String, IAction> actions = new HashMap<String, IAction>(); + +    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<String, String> prefMap = null;	 +	/** +	 * @param prefMap +	 */ +	 SimpleNamespaceContext(HashMap<String, String> 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<Entry<String, String>> set = prefMap.entrySet(); +			for (Entry<String, String> 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<AttributeProvider>{ + +	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<PersonalAttribute> 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<String> getSupportedAttributeNames() throws MOAIDException { +        ArrayList<String> supportedAttributeNames = new ArrayList<String>(); +        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: +			<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> +			  <soap:Body> +			    <IsHealthcareProfessional xmlns="http://gesundheit.gv.at/BAGDAD/DataAccessService"> +			      <bPK>string</bPK> +			    </IsHealthcareProfessional> +			  </soap:Body> +			</soap:Envelope> + +			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 + +            /* +			<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"> +			  <soap:Body> +			    <IsHealthcareProfessionalResponse xmlns="http://gesundheit.gv.at/BAGDAD/DataAccessService"> +			      <IsHealthcareProfessionalResult> +			        <RequestOK>boolean</RequestOK> +			        <Message>string</Message> +			        <IsHealthcareProfessional>boolean</IsHealthcareProfessional> +			        <NameOfOrganisation>string</NameOfOrganisation> +			        <Type>string</Type> +			        <Specialization>string</Specialization> +			      </IsHealthcareProfessionalResult> +			    </IsHealthcareProfessionalResponse> +			  </soap:Body> +			</soap:Envelope> + +			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<String, String> collection = new HashMap<String, String>(); +			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<String>(), 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<String> value = new ArrayList<String>(); +				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<String> value = new ArrayList<String>(); +			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<PersonalAttribute> 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<String> values = new ArrayList<String>(); +			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<IncludeObject> 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<String> getSupportedAttributeNames() throws MOAIDException { +        ArrayList<String> supportedAttributeNames = new ArrayList<String>(); +        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; +	} + +} + diff --git a/id/server/modules/module-stork/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.IModulInfo b/id/server/modules/module-stork/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.IModulInfo new file mode 100644 index 000000000..5d7af87d5 --- /dev/null +++ b/id/server/modules/module-stork/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.IModulInfo @@ -0,0 +1 @@ +at.gv.egovernment.moa.id.protocols.stork2.STORKProtocol
\ No newline at end of file | 
