aboutsummaryrefslogtreecommitdiff
path: root/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols
diff options
context:
space:
mode:
authorThomas Lenz <tlenz@iaik.tugraz.at>2014-03-21 14:45:05 +0100
committerThomas Lenz <tlenz@iaik.tugraz.at>2014-03-21 14:45:05 +0100
commitf3f35663f362ce6722eaa26598fb5aa8c4c6d962 (patch)
treebc9d66ebe1b5b840c6e3bf0087a8dd58040528a1 /id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols
parent05212e955f2c44bd3150b47d9d534c5a73eb71d1 (diff)
parent658cb68c445d5b73815c43b66dd717483a425ea5 (diff)
downloadmoa-id-spss-f3f35663f362ce6722eaa26598fb5aa8c4c6d962.tar.gz
moa-id-spss-f3f35663f362ce6722eaa26598fb5aa8c4c6d962.tar.bz2
moa-id-spss-f3f35663f362ce6722eaa26598fb5aa8c4c6d962.zip
Merge remote-tracking branch 'remotes/origin/vidp' into moa2_0_tlenz
Conflicts: id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/struts/action/EditGeneralConfigAction.java id/ConfigWebTool/src/main/java/at/gv/egovernment/moa/id/configuration/struts/action/EditOAAction.java id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/AuthenticationServer.java id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/PEPSConnectorServlet.java id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/config/stork/STORKConfig.java id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/entrypoints/DispatcherServlet.java id/server/idserverlib/src/main/resources/resources/properties/id_messages_de.properties id/server/moa-id-commons/pom.xml id/server/stork2-saml-engine/pom.xml pom.xml repository/iaik/iaik_tsl/1.0/iaik_tsl-1.0.jar repository/iaik/iaik_tsl/1.0/iaik_tsl-1.0.pom
Diffstat (limited to 'id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols')
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java15
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeCollector.java237
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeProvider.java56
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeProviderFactory.java73
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AuthenticationRequest.java201
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ConsentEvaluator.java208
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/DataContainer.java78
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/EHvdAttributeProviderPlugin.java222
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ExternalAttributeRequestRequiredException.java29
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOAAttributeProvider.java104
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKRequest.java213
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKResponse.java117
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateAttributeRequestProvider.java125
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateRetrievalRequest.java28
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/STORKProtocol.java126
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/SignedDocAttributeRequestProvider.java129
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/StorkAttributeRequestProvider.java162
-rw-r--r--id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/UnsupportedAttributeException.java7
18 files changed, 2117 insertions, 13 deletions
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java
index a609942f3..6517325b9 100644
--- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/pvp2x/binding/PostBinding.java
@@ -26,7 +26,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.velocity.app.VelocityEngine;
-import org.apache.velocity.runtime.RuntimeConstants;
import org.opensaml.common.SAMLObject;
import org.opensaml.common.binding.BasicSAMLMessageContext;
import org.opensaml.common.xml.SAMLConstants;
@@ -51,6 +50,7 @@ import org.opensaml.xml.security.x509.X509Credential;
import at.gv.egovernment.moa.id.protocols.pvp2x.metadata.MOAMetadataProvider;
import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialProvider;
import at.gv.egovernment.moa.id.protocols.pvp2x.signer.CredentialsNotAvailableException;
+import at.gv.egovernment.moa.id.util.VelocityProvider;
import at.gv.egovernment.moa.logging.Logger;
public class PostBinding implements IDecoder, IEncoder {
@@ -72,18 +72,7 @@ public class PostBinding implements IDecoder, IEncoder {
Logger.debug("create SAML POSTBinding response");
- // VelocityEngine engine =
- // VelocityProvider.getClassPathVelocityEngine();
- VelocityEngine engine = new VelocityEngine();
- engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8");
- engine.setProperty(RuntimeConstants.OUTPUT_ENCODING, "UTF-8");
- engine.setProperty(RuntimeConstants.ENCODING_DEFAULT, "UTF-8");
- engine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath");
- engine.setProperty("classpath.resource.loader.class",
- "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
- engine.setProperty(RuntimeConstants.RUNTIME_LOG_LOGSYSTEM_CLASS,
- "org.apache.velocity.runtime.log.SimpleLog4JLogSystem");
- engine.init();
+ VelocityEngine engine = VelocityProvider.getClassPathVelocityEngine();
HTTPPostEncoder encoder = new HTTPPostEncoder(engine,
"resources/templates/pvp_postbinding_template.html");
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeCollector.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeCollector.java
new file mode 100644
index 000000000..1d9e31674
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeCollector.java
@@ -0,0 +1,237 @@
+package at.gv.egovernment.moa.id.protocols.stork2;
+
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
+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.AuthConfigurationProvider;
+import at.gv.egovernment.moa.id.config.auth.OAAuthParameter;
+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.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.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.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 String processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp, AuthenticationSession moasession) 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);
+ }
+
+ // read configuration parameters of OA
+ OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(container.getRequest().getAssertionConsumerServiceURL());
+ if (oaParam == null)
+ throw new AuthenticationException("stork.12", new Object[]{moasession.getPublicOAURLPrefix()});
+
+ // find the attribute provider plugin that can handle the response
+ IPersonalAttributeList newAttributes = null;
+ for (AttributeProvider current : AttributeProviderFactory.getConfiguredPlugins(oaParam.getStorkAPs()))
+ try {
+ newAttributes = current.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
+ addOrUpdateAll(container.getResponse().getPersonalAttributeList(), newAttributes);
+
+ // see if we need some more attributes
+ return processRequest(container, httpReq, httpResp, moasession, oaParam);
+ }
+
+ /**
+ * 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 String processRequest(DataContainer container, HttpServletRequest request, HttpServletResponse response, AuthenticationSession moasession, 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>();
+ for (PersonalAttribute current : requestAttributeList)
+ if (!responseAttributeList.containsKey(current.getName()))
+ missingAttributes.add(current);
+
+ 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("notAvailable");
+ aquiredAttributes.add((PersonalAttribute) currentAttribute.clone());
+ addOrUpdateAll(container.getResponse().getPersonalAttributeList(), aquiredAttributes);
+
+ // - check if we can find a suitable AttributeProvider Plugin
+ for (AttributeProvider currentProvider : AttributeProviderFactory.getConfiguredPlugins(oaParam.getStorkAPs())) {
+ 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);
+ 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
+ addOrUpdateAll(container.getResponse().getPersonalAttributeList(), aquiredAttributes);
+ }
+ Logger.info("collecting attributes done");
+
+ // ask for consent if necessary
+ if(oaParam.isRequireConsentForStorkAttributes())
+ new ConsentEvaluator().requestConsent(container, response, oaParam);
+ else
+ new ConsentEvaluator().generateSTORKResponse(response, container);
+
+ return "12345"; // AssertionId
+
+ } 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(AuthConfigurationProvider.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);
+ }
+
+ return "12345"; // 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
+ * @throws MOAIDException
+ */
+ private void addOrUpdateAll(IPersonalAttributeList target, IPersonalAttributeList source) throws MOAIDException {
+ Logger.debug("Updating " + source.size() + " attributes...");
+ for (PersonalAttribute current : source) {
+ Logger.trace("treating " + current.getName());
+
+ // check if we need to update the current pa
+ if (target.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()});
+ }
+
+ target.get(current.getName()).setStatus(current.getStatus());
+ target.get(current.getName()).setValue(current.getValue());
+ target.get(current.getName()).setComplexValue(current.getComplexValue());
+ } else
+ target.add(current);
+
+ Logger.trace("...successfully treated " + current.getName());
+ }
+ }
+
+ /* (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/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeProvider.java
new file mode 100644
index 000000000..2914d8f7d
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeProvider.java
@@ -0,0 +1,56 @@
+package at.gv.egovernment.moa.id.protocols.stork2;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
+import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
+import at.gv.egovernment.moa.id.config.auth.OAAuthParameter;
+
+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 interface AttributeProvider {
+
+ /**
+ * 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 attributes the list of attributes to be acquired
+ * @param spCountyCode the sp county code
+ * @param moasession 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
+ */
+ public IPersonalAttributeList acquire(PersonalAttribute attributes, String spCountyCode, AuthenticationSession moasession) throws UnsupportedAttributeException, ExternalAttributeRequestRequiredException, MOAIDException;
+
+ /**
+ * 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 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 IPersonalAttributeList parse(HttpServletRequest httpReq) throws UnsupportedAttributeException, MOAIDException;
+
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeProviderFactory.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeProviderFactory.java
new file mode 100644
index 000000000..a339cff23
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AttributeProviderFactory.java
@@ -0,0 +1,73 @@
+package at.gv.egovernment.moa.id.protocols.stork2;
+
+import at.gv.egovernment.moa.id.commons.db.dao.config.AttributeProviderPlugin;
+import at.gv.egovernment.moa.logging.Logger;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A factory for creating AttributeProvider objects.
+ */
+public class AttributeProviderFactory {
+
+ /**
+ * Gets the available plugins.
+ *
+ * @return the available plugins
+ */
+ public static List<String> getAvailablePlugins() {
+ List<String> result = new ArrayList<String>();
+ result.add("StorkAttributeRequestProvider");
+ result.add("EHvdAttributeProvider");
+ result.add("SignedDocAttributeRequestProvider");
+ result.add("MandateAttributeRequestProvider");
+
+ return result;
+ }
+
+ /**
+ * 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 {
+ return null;
+ }
+ }
+
+ /**
+ * Gets fresh instances of the configured plugins.
+ *
+ * @param configuredAPs the configured a ps
+ * @return the configured plugins
+ */
+ public static List<AttributeProvider> getConfiguredPlugins(
+ List<AttributeProviderPlugin> configuredAPs) {
+
+ List<AttributeProvider> result = new ArrayList<AttributeProvider>();
+ for (AttributeProviderPlugin current : configuredAPs) {
+
+ 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;
+ }
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AuthenticationRequest.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AuthenticationRequest.java
new file mode 100644
index 000000000..5e49fe413
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/AuthenticationRequest.java
@@ -0,0 +1,201 @@
+package at.gv.egovernment.moa.id.protocols.stork2;
+
+import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
+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.AuthConfigurationProvider;
+import at.gv.egovernment.moa.id.config.auth.OAAuthParameter;
+import at.gv.egovernment.moa.id.moduls.IAction;
+import at.gv.egovernment.moa.id.moduls.IRequest;
+import at.gv.egovernment.moa.id.util.client.mis.simple.MISMandate;
+import at.gv.egovernment.moa.logging.Logger;
+import eu.stork.peps.auth.commons.*;
+import eu.stork.peps.auth.engine.STORKSAMLEngine;
+import eu.stork.peps.exceptions.STORKSAMLEngineException;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.runtime.RuntimeConstants;
+import org.joda.time.DateTime;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * 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 AuthenticationSession moaSession = null;
+ private MOASTORKRequest moaStorkRequest = null;
+
+
+ public String processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp, AuthenticationSession moasession) throws MOAIDException {
+
+ this.moaSession = moasession;
+
+ if (req instanceof MOASTORKRequest) {
+
+ this.moaStorkRequest = (MOASTORKRequest) req;
+
+ Logger.debug("Entering MOASTORKRequest");
+ httpResp.reset();
+
+ OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter(moasession.getPublicOAURLPrefix());
+ if (oaParam == null)
+ throw new AuthenticationException("stork.12", new Object[]{moasession.getPublicOAURLPrefix()});
+
+ 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) {
+ // TODO
+ }
+
+ // Get personal attributtes from MOA/IdentityLink
+ moaStorkResponse.setPersonalAttributeList(populateAttributes());
+
+
+ }
+
+ //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());
+
+
+ STORKAuthnResponse arep = moaStorkResponse.getStorkAuthnResponse();
+
+
+ arep.setCountry("XX");
+ arep.setInResponseTo("xxxx");
+ arep.setMessage("xxxx");
+ arep.setSamlId("xxxx");
+ arep.setStatusCode("xxxx");
+
+ // arep.setNotBefore(new DateTime().withTimeAtStartOfDay());
+ // arep.setNotOnOrAfter(new DateTime().withTimeAtStartOfDay());
+
+
+ Logger.debug("Data container prepared");
+
+ return (new AttributeCollector()).processRequest(container, httpReq, httpResp, moasession, oaParam);
+ } else {
+ Logger.error("Could not recognize request.");
+ throw new MOAIDException("stork.15", null);
+ }
+ }
+
+ public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) {
+ 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(AuthenticationSession moasession) {
+
+ if (moasession.getUseMandate()) {
+ try {
+ MISMandate mandate = moasession.getMISMandate();
+ String owbpk = mandate.getOWbPK();
+ byte[] mand = mandate.getMandate();
+ String profprep = mandate.getProfRep();
+ //String textdesc = mandate.getTextualDescriptionOfOID();
+ Element mndt = moasession.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() {
+
+ 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(moaSession.getIdentityLink(), moaStorkRequest);
+
+ try {
+ for (PersonalAttribute personalAttribute : attrLst) {
+ 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());
+ }
+
+ Logger.debug("AUTHBLOCK " + moaSession.getAuthBlock());
+ Logger.debug("TARGET " + moaSession.getTarget() + " " + moaSession.getTargetFriendlyName());
+ Logger.debug("SESSION IDENTIFIER " + moaSession.getCcc() + " " + moaSession.getDomainIdentifier());
+ Logger.debug("AUTHBLOCKTOKKEN" + moaSession.getAuthBlockTokken());
+
+ 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/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ConsentEvaluator.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ConsentEvaluator.java
new file mode 100644
index 000000000..9a3376e4c
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ConsentEvaluator.java
@@ -0,0 +1,208 @@
+package at.gv.egovernment.moa.id.protocols.stork2;
+
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
+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.AuthConfigurationProvider;
+import at.gv.egovernment.moa.id.config.auth.OAAuthParameter;
+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.commons.STORKAuthnResponse;
+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.joda.time.DateTime;
+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 String processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp, AuthenticationSession moasession) 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.17", null);
+ }
+
+ // evaluate response
+ for(PersonalAttribute current : container.getResponse().getPersonalAttributeList()) {
+ if(null == httpReq.getParameter(current.getName())) {
+ current.setStatus("notAvailable");
+ current.setValue(new ArrayList<String>());
+ current.setComplexValue(new HashMap<String, String>());
+ }
+ }
+
+ // build and send response
+ generateSTORKResponse(httpResp, container);
+
+ return "12345"; // AssertionId
+ }
+
+ /**
+ * Fills the given HttpResponse with the required web page.
+ *
+ * @param container the container
+ * @param response the response
+ * @param oaParam the oa param
+ * @return the string
+ * @throws MOAIDException the mOAID exception
+ */
+ public String requestConsent(DataContainer container, HttpServletResponse response, OAAuthParameter oaParam) throws MOAIDException {
+ // 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", AuthConfigurationProvider.getInstance().getPublicURLPrefix() + "/stork2/CompleteAuthentication?" + ARTIFACT_ID + "=" + newArtifactId);
+
+ // assemble table
+ String table = "";
+ for (PersonalAttribute current : container.getResponse().getPersonalAttributeList())
+ if ("Available".equals(current.getStatus()))
+ table += "<tr><td><input type=\"checkbox\" checked=\"yes\" name=\"" + current.getName() + "\"></td><td>" + current.getName() + "</td></tr>\n";
+
+ context.put("tablecontent", table);
+
+ StringWriter writer = new StringWriter();
+ template.merge(context, writer);
+ response.getOutputStream().write(writer.getBuffer().toString().getBytes());
+
+ } 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.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());
+
+ } 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/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/DataContainer.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/DataContainer.java
new file mode 100644
index 000000000..d13754aff
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/DataContainer.java
@@ -0,0 +1,78 @@
+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/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/EHvdAttributeProviderPlugin.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/EHvdAttributeProviderPlugin.java
new file mode 100644
index 000000000..5e9d9404c
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/EHvdAttributeProviderPlugin.java
@@ -0,0 +1,222 @@
+package at.gv.egovernment.moa.id.protocols.stork2;
+
+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.data.AuthenticationSession;
+import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
+import at.gv.egovernment.moa.id.config.auth.OAAuthParameter;
+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.IsHealthCareProfessionalType;
+import eu.stork.peps.complex.attributes.ObjectFactory;
+
+/**
+ * Fetches the attribute IsHealthcareProfessional from the BAGDAD SOAP service
+ */
+public class EHvdAttributeProviderPlugin implements AttributeProvider {
+
+ /** The destination. */
+ private Object destination;
+
+ /** The attributes. */
+ private String attributes;
+
+ /**
+ * Instantiates a new e hvd attribute provider plugin.
+ *
+ * @param url the service url
+ * @param attributes
+ */
+ public EHvdAttributeProviderPlugin(String url, String supportedAttributes) {
+ destination = url;
+ attributes = supportedAttributes;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#acquire(eu.stork.peps.auth.commons.PersonalAttribute)
+ */
+ public IPersonalAttributeList acquire(PersonalAttribute attribute, String spCountryCode, AuthenticationSession moasession)
+ 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");
+ requestBodyElem1.addTextNode(new BPKBuilder().buildBPK(moasession.getIdentityLink().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")) {
+ // the citizen is no HCP
+ acquiredAttribute = new PersonalAttribute("isHealthCareProfessional", false, new ArrayList<String>(), "NotAvailable");
+ } else {
+ // go on and parse the data
+ IsHealthCareProfessionalType result = new IsHealthCareProfessionalType();
+ result.setNameOfOrganisation(collection.get("NameOfOrganisation"));
+
+ if (collection.get("Type").equals("Medical doctor"))
+ result.setHCPType("D");
+ else
+ result.setHCPType("?");
+
+ if (collection.get("Specialization").contains("Arzt für Allgemeinmedizin"))
+ result.setSpecialisation("GP");
+ else
+ result.setSpecialisation("??");
+
+ 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, "Available");
+ }
+
+ // 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().buildStorkbPK(moasession.getIdentityLink().getIdentificationValue(), spCountryCode));
+ result.add(new PersonalAttribute("eIdentifier", false, value, "Available"));
+
+ 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();
+ }
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ExternalAttributeRequestRequiredException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ExternalAttributeRequestRequiredException.java
new file mode 100644
index 000000000..67fbd50f8
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/ExternalAttributeRequestRequiredException.java
@@ -0,0 +1,29 @@
+package at.gv.egovernment.moa.id.protocols.stork2;
+
+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/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOAAttributeProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOAAttributeProvider.java
new file mode 100644
index 000000000..873ec1e26
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOAAttributeProvider.java
@@ -0,0 +1,104 @@
+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.BuildException;
+import at.gv.egovernment.moa.logging.Logger;
+import eu.stork.peps.auth.commons.PersonalAttribute;
+import eu.stork.peps.auth.commons.PersonalAttributeList;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author bsuzic
+ * Date: 2/19/14, Time: 4:42 PM
+ */
+public class MOAAttributeProvider {
+ private final IdentityLink identityLink;
+ private static final Map<String, String> storkAttributeSimpleMapping;
+ private static final Map<String, String> storkAttributeFunctionMapping;
+ private final MOASTORKRequest moastorkRequest;
+
+ static {
+ Map<String, String> tempSimpleMap = new HashMap<String, String>();
+ tempSimpleMap.put("givenName", "getGivenName");
+ tempSimpleMap.put("surname", "getFamilyName");
+ tempSimpleMap.put("dateOfBirth", "getDateOfBirth");
+ storkAttributeSimpleMapping = Collections.unmodifiableMap(tempSimpleMap);
+ Map<String, String> tempFunctionMap = new HashMap<String, String>();
+ tempFunctionMap.put("eIdentifier", "geteIdentifier");
+ storkAttributeFunctionMapping = Collections.unmodifiableMap(tempFunctionMap);
+ }
+
+ public MOAAttributeProvider(IdentityLink identityLink, MOASTORKRequest moastorkRequest) {
+ this.identityLink = identityLink;
+ this.moastorkRequest = moastorkRequest;
+ Logger.debug("identity " + identityLink.getIdentificationType() + " " + identityLink.getIdentificationValue());
+ }
+
+ public void populateAttribute(PersonalAttributeList attributeList, PersonalAttribute requestedAttribute ) {
+ String storkAttribute = requestedAttribute.getName();
+ if (storkAttributeSimpleMapping.containsKey(storkAttribute)) {
+ Logger.debug("Trying to get value for attribute using simple mapping [" + storkAttribute + "]");
+ try {
+ Method method = identityLink.getClass().getDeclaredMethod(storkAttributeSimpleMapping.get(storkAttribute));
+ populateAttributeWithMethod(method, identityLink, attributeList, storkAttribute, requestedAttribute.isRequired());
+ } catch (NoSuchMethodException e) {
+ Logger.error("Could not found MOA extraction method while getting attribute: " + storkAttribute);
+ e.printStackTrace();
+ }
+
+ } 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));
+ populateAttributeWithMethod(method, this, attributeList, storkAttribute, requestedAttribute.isRequired());
+ } catch (NoSuchMethodException e) {
+ Logger.error("Could not found MOA extraction method while getting attribute: " + storkAttribute);
+ e.printStackTrace();
+ }
+ } else {
+ Logger.debug("MOA method for extraction of attribute " + storkAttribute + " not defined.");
+ }
+ }
+
+ private String geteIdentifier() {
+ Logger.debug("Using base urn for identification value: " + identityLink.getIdentificationType() + " and target country: " + moastorkRequest.getStorkAuthnRequest().getSpCountry());
+ try {
+ return new BPKBuilder().buildStorkbPK(identityLink.getIdentificationValue(), moastorkRequest.getStorkAuthnRequest().getSpCountry());
+ } catch (BuildException be) {
+ Logger.error("Stork eid could not be constructed; " + be.getMessage());
+ return null; // TODO error
+ }
+ }
+
+
+ private void populateAttributeWithMethod(Method method, Object object, PersonalAttributeList attributeList, String storkAttribute, Boolean isRequired) {
+ try {
+ String attributeValue = method.invoke(object, new Class[]{}).toString();
+ PersonalAttribute newAttribute = new PersonalAttribute();
+ newAttribute.setName(storkAttribute);
+
+ newAttribute.setStatus("Available");
+ newAttribute.setIsRequired(isRequired);
+ Logger.info("Got attribute value: " + attributeValue);
+ newAttribute.setValue(new ArrayList<String>(edu.emory.mathcs.backport.java.util.Collections.singletonList(attributeValue)));
+ attributeList.add(newAttribute);
+ } catch (InvocationTargetException e) {
+ Logger.error("Invocation target exception while getting attribute: " + storkAttribute);
+ e.printStackTrace();
+ } catch (IllegalAccessException e) {
+ Logger.error("Illegal access exception while getting attribute: " + storkAttribute);
+ e.printStackTrace();
+ }
+ }
+
+
+}
+
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKRequest.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKRequest.java
new file mode 100644
index 000000000..9ea33c8ef
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKRequest.java
@@ -0,0 +1,213 @@
+package at.gv.egovernment.moa.id.protocols.stork2;
+
+import java.io.Serializable;
+
+import at.gv.egovernment.moa.id.moduls.IRequest;
+import at.gv.egovernment.moa.logging.Logger;
+import eu.stork.peps.auth.commons.IPersonalAttributeList;
+import eu.stork.peps.auth.commons.STORKAttrQueryRequest;
+import eu.stork.peps.auth.commons.STORKAuthnRequest;
+
+/**
+ * Implements MOA request and stores StorkAuthn/Attr-Request related data.
+ *
+ * @author bsuzic
+ */
+public class MOASTORKRequest implements IRequest, Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = 4581953368724501376L;
+
+ /** The request id. */
+ private String requestID;
+
+ /** The target. */
+ private String target = null;
+
+ /** The module. */
+ String module = null;
+
+ /** The action. */
+ String action = null;
+
+ /** 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#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#setModule(java.lang.String)
+ */
+ public void setModule(String module) {
+ this.module = module;
+ }
+
+ /* (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.IRequest#getTarget()
+ */
+ public String getTarget() {
+ return this.target;
+ }
+
+ /* (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();
+ }
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKResponse.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKResponse.java
new file mode 100644
index 000000000..4e0f57779
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MOASTORKResponse.java
@@ -0,0 +1,117 @@
+package at.gv.egovernment.moa.id.protocols.stork2;
+
+import java.io.Serializable;
+
+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;
+
+/**
+ * Implements MOA request and stores StorkAuthn/Attr-Request related data.
+ *
+ * @author bsuzic
+ */
+public class MOASTORKResponse implements Serializable {
+
+ /** The Constant serialVersionUID. */
+ private static final long serialVersionUID = -5798803155055518747L;
+
+ /** The stork authn request. */
+ private STORKAuthnResponse storkAuthnResponse;
+
+ /** The stork attr query request. */
+ private STORKAttrQueryResponse storkAttrQueryResponse;
+
+ /**
+ * Sets the sTORK authn response.
+ *
+ * @param request the new sTORK authn response
+ */
+ public void setSTORKAuthnResponse(STORKAuthnResponse request) {
+ this.storkAuthnResponse = request;
+ }
+
+ /**
+ * 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);
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateAttributeRequestProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateAttributeRequestProvider.java
new file mode 100644
index 000000000..0e94600db
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateAttributeRequestProvider.java
@@ -0,0 +1,125 @@
+package at.gv.egovernment.moa.id.protocols.stork2;
+
+import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
+import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
+import at.gv.egovernment.moa.id.config.auth.OAAuthParameter;
+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.*;
+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 javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.StringWriter;
+
+/**
+ * Provides mandate attribute from MIS
+ */
+public class MandateAttributeRequestProvider implements AttributeProvider {
+ /**
+ * The destination.
+ */
+ private String destination;
+
+ /**
+ * The attributes.
+ */
+ private String attributes;
+
+ private String spCountryCode;
+
+ private PersonalAttributeList requestedAttributes;
+
+ public MandateAttributeRequestProvider(String aPurl, String supportedAttributes) throws MOAIDException {
+ destination = aPurl;
+ attributes = supportedAttributes;
+ }
+
+ public String getAttrProviderName() {
+ return "MandateAttributeRequestProvider";
+ }
+
+ public IPersonalAttributeList acquire(PersonalAttribute attribute, String spCountryCode, AuthenticationSession moasession) throws UnsupportedAttributeException, ExternalAttributeRequestRequiredException, MOAIDException {
+ Logger.info("Acquiring attribute: " + attribute.getName() + ", by: " + getAttrProviderName());
+ this.spCountryCode = spCountryCode;
+ 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();
+ }
+ PersonalAttributeList result = new PersonalAttributeList();
+ //return result;
+ 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;
+
+ //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.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());
+ } 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; //
+ }
+
+}
+
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateRetrievalRequest.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateRetrievalRequest.java
new file mode 100644
index 000000000..3bd1686b4
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/MandateRetrievalRequest.java
@@ -0,0 +1,28 @@
+package at.gv.egovernment.moa.id.protocols.stork2;
+
+import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
+import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
+import at.gv.egovernment.moa.id.moduls.IAction;
+import at.gv.egovernment.moa.id.moduls.IRequest;
+import at.gv.egovernment.moa.logging.Logger;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ *
+ */
+public class MandateRetrievalRequest implements IAction {
+ public String processRequest(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp, AuthenticationSession moasession) throws MOAIDException {
+ Logger.info("Entering mandateretrievalrequest");
+ return null; //
+ }
+
+ public boolean needAuthentication(IRequest req, HttpServletRequest httpReq, HttpServletResponse httpResp) {
+ return true; //
+ }
+
+ public String getDefaultActionName() {
+ return STORKProtocol.MANDATERETRIEVALREQUEST;
+ }
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/STORKProtocol.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/STORKProtocol.java
new file mode 100644
index 000000000..5b844580d
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/STORKProtocol.java
@@ -0,0 +1,126 @@
+package at.gv.egovernment.moa.id.protocols.stork2;
+
+import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants;
+import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
+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 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 implements IModulInfo, MOAIDAuthConstants {
+
+ 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) 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();
+
+ if (AttributeCollector.class.getSimpleName().equals(action) || ConsentEvaluator.class.getSimpleName().equals(action))
+ return STORK2Request;
+
+ //extract STORK Response from HTTP Request
+ byte[] decSamlToken;
+ try {
+ decSamlToken = PEPSUtil.decodeSAMLToken(request.getParameter("SAMLRequest"));
+ } catch (NullPointerException e) {
+ Logger.error("Unable to retrieve STORK Request", 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);
+ }
+
+ STORK2Request.setSTORKAuthnRequest(authnRequest);
+ STORK2Request.setSTORKAttrRequest(attrRequest);
+
+ return STORK2Request;
+ }
+
+ 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/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/SignedDocAttributeRequestProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/SignedDocAttributeRequestProvider.java
new file mode 100644
index 000000000..89eb07815
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/SignedDocAttributeRequestProvider.java
@@ -0,0 +1,129 @@
+package at.gv.egovernment.moa.id.protocols.stork2;
+
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+
+import at.gv.egovernment.moa.id.auth.data.AuthenticationSession;
+import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
+import at.gv.egovernment.moa.id.config.auth.OAAuthParameter;
+import at.gv.egovernment.moa.id.util.VelocityProvider;
+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;
+
+/**
+ * Forwards a signedDoc attribute request to the oasis-dss service instance
+ */
+public class SignedDocAttributeRequestProvider implements AttributeProvider {
+
+ private PersonalAttribute requestedAttribute;
+
+ /**
+ * The URL of the service listening for the oasis dss webform post request
+ */
+ private String oasisDssWebFormURL;
+
+ /** The attributes. */
+ private String attributes;
+
+ /**
+ * Instantiates a new signed doc attribute request provider.
+ *
+ * @param oasisDssWebFormURL
+ * the AP location
+ * @param attributes
+ */
+ public SignedDocAttributeRequestProvider(String oasisDssWebFormURL, String attributes) {
+ this.oasisDssWebFormURL = oasisDssWebFormURL;
+ this.attributes = attributes;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#acquire(java
+ * .lang.String)
+ */
+ public IPersonalAttributeList acquire(PersonalAttribute attribute, String spCountyCode, AuthenticationSession moasession) throws UnsupportedAttributeException,
+ ExternalAttributeRequestRequiredException {
+ if(!attributes.contains(attribute.getName())) {
+ throw new UnsupportedAttributeException();
+ }
+
+ requestedAttribute = 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.debug("Beginning to extract OASIS-DSS response out of HTTP Request");
+
+ try {
+ String signResponse = new String(Base64.decodeBase64(httpReq.getParameter("signresponse")), "UTF8");
+ List<String> values = new ArrayList<String>();
+ values.add(signResponse);
+
+ Logger.debug("Assembling signedDoc attribute");
+ PersonalAttribute signedDocAttribute = new PersonalAttribute("signedDoc", false, values,
+ "Available");
+
+ // 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);
+ }
+ }
+
+ /*
+ * (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...");
+
+ VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine();
+ Template template = velocityEngine.getTemplate("/resources/templates/oasis_dss_webform_binding.vm");
+ VelocityContext context = new VelocityContext();
+ context.put("signrequest", Base64.encodeBase64String(requestedAttribute.getValue().get(0).getBytes("UTF8")));
+ context.put("clienturl", url);
+ context.put("action", oasisDssWebFormURL);
+
+ StringWriter writer = new StringWriter();
+ template.merge(context, writer);
+
+ resp.getOutputStream().write(writer.toString().getBytes());
+ } catch (Exception e) {
+ Logger.error("Error sending DSS signrequest.", e);
+ throw new MOAIDException("stork.11", null);
+ }
+ }
+
+}
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/StorkAttributeRequestProvider.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/StorkAttributeRequestProvider.java
new file mode 100644
index 000000000..c0e613b82
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/StorkAttributeRequestProvider.java
@@ -0,0 +1,162 @@
+package at.gv.egovernment.moa.id.protocols.stork2;
+
+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.data.AuthenticationSession;
+import at.gv.egovernment.moa.id.auth.exception.MOAIDException;
+import at.gv.egovernment.moa.id.config.auth.OAAuthParameter;
+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 implements AttributeProvider {
+
+ private PersonalAttributeList requestedAttributes;
+
+ /** The destination. */
+ private String destination;
+
+ /** The attributes. */
+ private String attributes;
+
+ /** 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) {
+ destination = apUrl;
+ attributes = supportedAttributes;
+ }
+
+ /* (non-Javadoc)
+ * @see at.gv.egovernment.moa.id.protocols.stork2.AttributeProvider#acquire(java.lang.String)
+ */
+ public IPersonalAttributeList acquire(PersonalAttribute attribute, String spCountyCode, AuthenticationSession moasession)
+ throws UnsupportedAttributeException, ExternalAttributeRequestRequiredException {
+
+ if (!attributes.contains(attribute.getName()))
+ throw new UnsupportedAttributeException();
+
+ this.spCountryCode = spCountyCode;
+
+ 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("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());
+ } catch (Exception e) {
+ Logger.error("Error sending STORK SAML AttrRequest.", e);
+ throw new MOAIDException("stork.11", null);
+ }
+ Logger.info("STORK AttrRequest successfully rendered!");
+ }
+
+}
+
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/UnsupportedAttributeException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/UnsupportedAttributeException.java
new file mode 100644
index 000000000..9447c079f
--- /dev/null
+++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/protocols/stork2/UnsupportedAttributeException.java
@@ -0,0 +1,7 @@
+package at.gv.egovernment.moa.id.protocols.stork2;
+
+public class UnsupportedAttributeException extends Exception {
+
+ private static final long serialVersionUID = -7720066381435378111L;
+
+}