From 4b6fd327b29ff84f61914f33b6361fa31441c92e Mon Sep 17 00:00:00 2001 From: Thomas Knall Date: Wed, 4 Feb 2015 11:31:43 +0100 Subject: Create separate module STORK (MOAID-67) - Add new maven module moa-id-modules and sub module moa-id-module-stork. - Move stork relates processes and task to module moa-id-module-stork. - Move module registration to modules package. --- id/server/auth/pom.xml | 4 + .../src/main/webapp/WEB-INF/applicationContext.xml | 4 +- .../id/auth/modules/AbstractAuthServletTask.java | 378 ++++++++++++++ .../moa/id/auth/modules/AuthModule.java | 41 ++ .../modules/internal/DefaultAuthModuleImpl.java | 2 +- .../internal/tasks/AbstractAuthServletTask.java | 378 -------------- .../internal/tasks/CertificateReadRequestTask.java | 4 +- .../internal/tasks/CreateIdentityLinkFormTask.java | 1 + .../modules/internal/tasks/GetForeignIDTask.java | 1 + .../internal/tasks/GetMISSessionIDTask.java | 1 + .../tasks/PrepareAuthBlockSignatureTask.java | 1 + .../tasks/VerifyAuthenticationBlockTask.java | 1 + .../internal/tasks/VerifyCertificateTask.java | 1 + .../internal/tasks/VerifyIdentityLinkTask.java | 1 + .../modules/registration/ModuleRegistration.java | 149 ++++++ .../id/auth/modules/stork/STORKAuthModuleImpl.java | 39 -- .../stork/STORKWebApplicationInitializer.java | 37 -- .../AbstractPepsConnectorWithLocalSigningTask.java | 223 -------- .../tasks/CreateStorkAuthRequestFormTask.java | 112 ---- .../PepsConnectorHandleLocalSignResponseTask.java | 216 -------- ...onnectorHandleResponseWithoutSignatureTask.java | 439 ---------------- .../modules/stork/tasks/PepsConnectorTask.java | 566 --------------------- .../servlet/GenerateIFrameTemplateServlet.java | 2 +- .../moa/id/moduls/AuthenticationManager.java | 2 +- .../id/moduls/moduleregistration/AuthModule.java | 41 -- .../moduleregistration/ModuleRegistration.java | 149 ------ .../egovernment/moa/id/process/ProcessEngine.java | 3 +- .../moa/id/process/ProcessEngineImpl.java | 6 +- ...t.gv.egovernment.moa.id.auth.modules.AuthModule | 2 + ...ent.moa.id.moduls.moduleregistration.AuthModule | 2 - .../auth/modules/stork/STORK.authmodule.beans.xml | 14 - .../modules/stork/STORKAuthentication.process.xml | 29 -- id/server/modules/module-stork/pom.xml | 22 + .../id/auth/modules/stork/STORKAuthModuleImpl.java | 39 ++ .../stork/STORKWebApplicationInitializer.java | 37 ++ .../AbstractPepsConnectorWithLocalSigningTask.java | 223 ++++++++ .../tasks/CreateStorkAuthRequestFormTask.java | 112 ++++ .../PepsConnectorHandleLocalSignResponseTask.java | 216 ++++++++ ...onnectorHandleResponseWithoutSignatureTask.java | 439 ++++++++++++++++ .../modules/stork/tasks/PepsConnectorTask.java | 566 +++++++++++++++++++++ .../auth/modules/stork/STORK.authmodule.beans.xml | 14 + .../modules/stork/STORKAuthentication.process.xml | 29 ++ id/server/modules/pom.xml | 48 ++ id/server/pom.xml | 1 + 44 files changed, 2340 insertions(+), 2255 deletions(-) create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/AbstractAuthServletTask.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/AuthModule.java delete mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/AbstractAuthServletTask.java create mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/registration/ModuleRegistration.java delete mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java delete mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java delete mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java delete mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java delete mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java delete mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java delete mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java delete mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/AuthModule.java delete mode 100644 id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/ModuleRegistration.java create mode 100644 id/server/idserverlib/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.auth.modules.AuthModule delete mode 100644 id/server/idserverlib/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.moduleregistration.AuthModule delete mode 100644 id/server/idserverlib/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORK.authmodule.beans.xml delete mode 100644 id/server/idserverlib/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthentication.process.xml create mode 100644 id/server/modules/module-stork/pom.xml create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java create mode 100644 id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java create mode 100644 id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORK.authmodule.beans.xml create mode 100644 id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthentication.process.xml create mode 100644 id/server/modules/pom.xml (limited to 'id') diff --git a/id/server/auth/pom.xml b/id/server/auth/pom.xml index 529737820..df45568dc 100644 --- a/id/server/auth/pom.xml +++ b/id/server/auth/pom.xml @@ -137,6 +137,10 @@ oasis-dss-api 1.0.0-RELEASE + + MOA.id.server.modules + moa-id-module-stork + diff --git a/id/server/auth/src/main/webapp/WEB-INF/applicationContext.xml b/id/server/auth/src/main/webapp/WEB-INF/applicationContext.xml index 1fe3b4254..fabe6cd9c 100644 --- a/id/server/auth/src/main/webapp/WEB-INF/applicationContext.xml +++ b/id/server/auth/src/main/webapp/WEB-INF/applicationContext.xml @@ -15,9 +15,9 @@ - - + + diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/AbstractAuthServletTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/AbstractAuthServletTask.java new file mode 100644 index 000000000..3b20e85d7 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/AbstractAuthServletTask.java @@ -0,0 +1,378 @@ +package at.gv.egovernment.moa.id.auth.modules; + +import static at.gv.egovernment.moa.id.auth.MOAIDAuthConstants.*; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.FileItemFactory; +import org.apache.commons.fileupload.FileUploadException; +import org.apache.commons.fileupload.disk.DiskFileItemFactory; +import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.lang3.ArrayUtils; + +import at.gv.egovernment.moa.id.advancedlogging.StatisticLogger; +import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; +import at.gv.egovernment.moa.id.auth.servlet.AuthServlet; +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.entrypoints.DispatcherServlet; +import at.gv.egovernment.moa.id.process.springweb.AbstractSpringWebSupportedTask; +import at.gv.egovernment.moa.id.storage.DBExceptionStoreImpl; +import at.gv.egovernment.moa.id.storage.IExceptionStore; +import at.gv.egovernment.moa.id.util.ServletUtils; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.MiscUtil; + +/** + * Task based counterpart to {@link AuthServlet}, providing the same utility methods (error handling, parameter parsing + * etc.).

The code has been taken from {@link AuthServlet}. + */ +public abstract class AbstractAuthServletTask extends AbstractSpringWebSupportedTask { + + protected static final String ERROR_CODE_PARAM = "errorid"; + + protected void handleErrorNoRedirect(String errorMessage, Throwable exceptionThrown, + HttpServletRequest req, HttpServletResponse resp) { + + if (null != errorMessage) { + Logger.error(errorMessage); + req.setAttribute("ErrorMessage", errorMessage); + } + + if (null != exceptionThrown) { + if (null == errorMessage) + errorMessage = exceptionThrown.getMessage(); + Logger.error(errorMessage, exceptionThrown); + req.setAttribute("ExceptionThrown", exceptionThrown); + } + + if (Logger.isDebugEnabled()) { + req.setAttribute("LogLevel", "debug"); + } + + + StatisticLogger logger = StatisticLogger.getInstance(); + logger.logErrorOperation(exceptionThrown); + + + // forward this to errorpage-auth.jsp where the HTML error page is + // generated + ServletContext context = req.getServletContext(); + RequestDispatcher dispatcher = context + .getRequestDispatcher("/errorpage-auth.jsp"); + try { + + resp.setHeader(HEADER_EXPIRES, HEADER_VALUE_EXPIRES); + resp.setHeader(HEADER_PRAGMA, HEADER_VALUE_PRAGMA); + resp.setHeader(HEADER_CACHE_CONTROL, HEADER_VALUE_CACHE_CONTROL); + resp.addHeader(HEADER_CACHE_CONTROL, HEADER_VALUE_CACHE_CONTROL_IE); + + dispatcher.forward(req, resp); + } catch (ServletException e) { + Logger.error(e); + } catch (IOException e) { + Logger.error(e); + } + } + + /** + * Handles an error.
> + *
    + *
  • Logs the error
  • + *
  • Places error message and exception thrown into the request as request + * attributes (to be used by "/errorpage-auth.jsp")
  • + *
  • Sets HTTP status 500 (internal server error)
  • + *
+ * + * @param errorMessage + * error message + * @param exceptionThrown + * exception thrown + * @param req + * servlet request + * @param resp + * servlet response + */ + protected void handleError(String errorMessage, Throwable exceptionThrown, + HttpServletRequest req, HttpServletResponse resp, String pendingRequestID) { + + if (null != errorMessage) { + Logger.error(errorMessage); + req.setAttribute("ErrorMessage", errorMessage); + } + + if (null != exceptionThrown) { + if (null == errorMessage) + errorMessage = exceptionThrown.getMessage(); + Logger.error(errorMessage, exceptionThrown); + req.setAttribute("ExceptionThrown", exceptionThrown); + } + + if (Logger.isDebugEnabled()) { + req.setAttribute("LogLevel", "debug"); + } + + if (!(exceptionThrown instanceof MOAIDException)) { + Logger.error("Receive an internal error: Message=" + exceptionThrown.getMessage(), exceptionThrown); + + } + + IExceptionStore store = DBExceptionStoreImpl.getStore(); + String id = store.storeException(exceptionThrown); + + if (id != null && MiscUtil.isNotEmpty(pendingRequestID)) { + + String redirectURL = null; + + redirectURL = ServletUtils.getBaseUrl(req); + redirectURL += "/dispatcher?" + ERROR_CODE_PARAM + "=" + id + + "&" + DispatcherServlet.PARAM_TARGET_PENDINGREQUESTID + "=" + pendingRequestID; + + resp.setContentType("text/html"); + resp.setStatus(302); + + resp.addHeader("Location", redirectURL); + Logger.debug("REDIRECT TO: " + redirectURL); + + return; + + } else { + + //Exception can not be stored in database + handleErrorNoRedirect(errorMessage, exceptionThrown, req, resp); + } + } + + /** + * Handles a WrongParametersException. + * + * @param req + * servlet request + * @param resp + * servlet response + */ + protected void handleWrongParameters(WrongParametersException ex, + HttpServletRequest req, HttpServletResponse resp) { + Logger.error(ex.toString()); + req.setAttribute("WrongParameters", ex.getMessage()); + + // forward this to errorpage-auth.jsp where the HTML error page is + // generated + ServletContext context = req.getServletContext(); + RequestDispatcher dispatcher = context + .getRequestDispatcher("/errorpage-auth.jsp"); + try { + setNoCachingHeaders(resp); + dispatcher.forward(req, resp); + } catch (ServletException e) { + Logger.error(e); + } catch (IOException e) { + Logger.error(e); + } + } + + /** + * Logs all servlet parameters for debugging purposes. + */ + protected void logParameters(HttpServletRequest req) { + for (Enumeration params = req.getParameterNames(); params + .hasMoreElements();) { + String parname = (String) params.nextElement(); + Logger.debug("Parameter " + parname + req.getParameter(parname)); + } + } + + /** + * Parses the request input stream for parameters, assuming parameters are + * encoded UTF-8 (no standard exists how browsers should encode them). + * + * @param req + * servlet request + * + * @return mapping parameter name -> value + * + * @throws IOException + * if parsing request parameters fails. + * + * @throws FileUploadException + * if parsing request parameters fails. + */ + protected Map getParameters(HttpServletRequest req) throws IOException, + FileUploadException { + + Map parameters = new HashMap(); + + if (ServletFileUpload.isMultipartContent(req)) { + // request is encoded as mulitpart/form-data + FileItemFactory factory = new DiskFileItemFactory(); + ServletFileUpload upload = null; + upload = new ServletFileUpload(factory); + List items = null; + items = upload.parseRequest(req); + for (int i = 0; i < items.size(); i++) { + FileItem item = (FileItem) items.get(i); + if (item.isFormField()) { + // Process only form fields - no file upload items + String logString = item.getString("UTF-8"); + + // TODO use RegExp + String startS = ""; + String endS = "urn:publicid:gv.at:baseid"; + String logWithMaskedBaseid = logString; + int start = logString.indexOf(startS); + if (start > -1) { + int end = logString.indexOf(endS); + if (end > -1) { + logWithMaskedBaseid = logString.substring(0, start); + logWithMaskedBaseid += startS; + logWithMaskedBaseid += "xxxxxxxxxxxxxxxxxxxxxxxx"; + logWithMaskedBaseid += logString.substring(end, + logString.length()); + } + } + parameters + .put(item.getFieldName(), item.getString("UTF-8")); + Logger.debug("Processed multipart/form-data request parameter: \nName: " + + item.getFieldName() + + "\nValue: " + + logWithMaskedBaseid); + } + } + } + + else { + // request is encoded as application/x-www-urlencoded + // [tknall]: we must not consume request body input stream once servlet-api request parameters have been accessed + + /* + InputStream in = req.getInputStream(); + + String paramName; + String paramValueURLEncoded; + do { + paramName = new String(readBytesUpTo(in, '=')); + if (paramName.length() > 0) { + paramValueURLEncoded = readBytesUpTo(in, '&'); + String paramValue = URLDecoder.decode(paramValueURLEncoded, + "UTF-8"); + parameters.put(paramName, paramValue); + } + } while (paramName.length() > 0); + in.close(); + */ + + Iterator> requestParamIt = req.getParameterMap().entrySet().iterator(); + while (requestParamIt.hasNext()) { + Entry entry = requestParamIt.next(); + String key = entry.getKey(); + String[] values = entry.getValue(); + // take the last value from the value array since the legacy code above also does it this way + parameters.put(key, ArrayUtils.isEmpty(values) ? null : values[values.length-1]); + } + + } + + return parameters; + } + + /** + * Reads bytes up to a delimiter, consuming the delimiter. + * + * @param in + * input stream + * @param delimiter + * delimiter character + * @return String constructed from the read bytes + * @throws IOException + */ + protected String readBytesUpTo(InputStream in, char delimiter) + throws IOException { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + boolean done = false; + int b; + while (!done && (b = in.read()) >= 0) { + if (b == delimiter) + done = true; + else + bout.write(b); + } + return bout.toString(); + } + + /** + * Sets response headers that prevent caching (code taken from {@link AuthServlet}). + * + * @param resp + * The HttpServletResponse. + */ + public void setNoCachingHeaders(HttpServletResponse resp) { + resp.setHeader(HEADER_EXPIRES, HEADER_VALUE_EXPIRES); + resp.setHeader(HEADER_PRAGMA, HEADER_VALUE_PRAGMA); + resp.setHeader(HEADER_CACHE_CONTROL, HEADER_VALUE_CACHE_CONTROL); + resp.addHeader(HEADER_CACHE_CONTROL, HEADER_VALUE_CACHE_CONTROL_IE); + } + + /** + * Adds a parameter to a URL. + * + * @param url + * the URL + * @param paramname + * parameter name + * @param paramvalue + * parameter value + * @return the URL with parameter added + */ + protected static String addURLParameter(String url, String paramname, + String paramvalue) { + String param = paramname + "=" + paramvalue; + if (url.indexOf("?") < 0) + return url + "?" + param; + else + return url + "&" + param; + } + + /** + * Checks if HTTP requests are allowed + * + * @param authURL + * requestURL + * @throws AuthenticationException + * if HTTP requests are not allowed + * @throws ConfigurationException + */ + protected void checkIfHTTPisAllowed(String authURL) + throws AuthenticationException, ConfigurationException { + // check if HTTP Connection may be allowed (through + // FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY) + + //Removed from MOA-ID 2.0 config +// String boolStr = AuthConfigurationProvider +// .getInstance() +// .getGenericConfigurationParameter( +// AuthConfigurationProvider.FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY); + if ((!authURL.startsWith("https:")) + //&& (false == BoolUtils.valueOf(boolStr)) + ) + throw new AuthenticationException("auth.07", new Object[] { authURL + + "*" }); + + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/AuthModule.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/AuthModule.java new file mode 100644 index 000000000..a31f3ceb0 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/AuthModule.java @@ -0,0 +1,41 @@ +package at.gv.egovernment.moa.id.auth.modules; + +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.process.model.ProcessDefinition; + +/** + * Provides metadata of a certain module. Uses for module discovery and process selection. + */ +public interface AuthModule { + + /** + * Returns the priority of the module. The priority defines the order of the respective module within the chain of + * discovered modules. Higher priorized modules are asked before lower priorized modules for a process that they can + * handle. + *

+ * Internal default modules are priorized neutral ({@code 0}. Use a higher priority ({@code 1...Integer.MAX_VALUE}) + * in order to have your module(s) priorized or a lower priority ({@code Integer.MIN_VALUE...-1}) in order to put + * your modules behind default modules. + * + * @return the priority of the module. + */ + int getPriority(); + + /** + * Checks if the module has a process, which is able to perform an authentication with the given + * {@link ExecutionContext}. + * + * @param context + * an ExecutionContext for a process. + * @return the process-ID of a process which is able to work with the given ExecutionContext, or {@code null}. + */ + String selectProcess(ExecutionContext context); + + /** + * Returns the an Array of {@link ProcessDefinition}s of the processes included in this module. + * + * @return an array of resource uris of the processes included in this module. + */ + String[] getProcessDefinitions(); + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/DefaultAuthModuleImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/DefaultAuthModuleImpl.java index a3b105cfd..8ae4a9999 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/DefaultAuthModuleImpl.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/DefaultAuthModuleImpl.java @@ -2,7 +2,7 @@ package at.gv.egovernment.moa.id.auth.modules.internal; import org.apache.commons.lang3.StringUtils; -import at.gv.egovernment.moa.id.moduls.moduleregistration.AuthModule; +import at.gv.egovernment.moa.id.auth.modules.AuthModule; import at.gv.egovernment.moa.id.process.api.ExecutionContext; /** diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/AbstractAuthServletTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/AbstractAuthServletTask.java deleted file mode 100644 index 088ec59d4..000000000 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/AbstractAuthServletTask.java +++ /dev/null @@ -1,378 +0,0 @@ -package at.gv.egovernment.moa.id.auth.modules.internal.tasks; - -import static at.gv.egovernment.moa.id.auth.MOAIDAuthConstants.*; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; - -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.fileupload.FileItem; -import org.apache.commons.fileupload.FileItemFactory; -import org.apache.commons.fileupload.FileUploadException; -import org.apache.commons.fileupload.disk.DiskFileItemFactory; -import org.apache.commons.fileupload.servlet.ServletFileUpload; -import org.apache.commons.lang3.ArrayUtils; - -import at.gv.egovernment.moa.id.advancedlogging.StatisticLogger; -import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; -import at.gv.egovernment.moa.id.auth.exception.MOAIDException; -import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; -import at.gv.egovernment.moa.id.auth.servlet.AuthServlet; -import at.gv.egovernment.moa.id.config.ConfigurationException; -import at.gv.egovernment.moa.id.entrypoints.DispatcherServlet; -import at.gv.egovernment.moa.id.process.springweb.AbstractSpringWebSupportedTask; -import at.gv.egovernment.moa.id.storage.DBExceptionStoreImpl; -import at.gv.egovernment.moa.id.storage.IExceptionStore; -import at.gv.egovernment.moa.id.util.ServletUtils; -import at.gv.egovernment.moa.logging.Logger; -import at.gv.egovernment.moa.util.MiscUtil; - -/** - * Task based counterpart to {@link AuthServlet}, providing the same utility methods (error handling, parameter parsing - * etc.).

The code has been taken from {@link AuthServlet}. - */ -public abstract class AbstractAuthServletTask extends AbstractSpringWebSupportedTask { - - protected static final String ERROR_CODE_PARAM = "errorid"; - - protected void handleErrorNoRedirect(String errorMessage, Throwable exceptionThrown, - HttpServletRequest req, HttpServletResponse resp) { - - if (null != errorMessage) { - Logger.error(errorMessage); - req.setAttribute("ErrorMessage", errorMessage); - } - - if (null != exceptionThrown) { - if (null == errorMessage) - errorMessage = exceptionThrown.getMessage(); - Logger.error(errorMessage, exceptionThrown); - req.setAttribute("ExceptionThrown", exceptionThrown); - } - - if (Logger.isDebugEnabled()) { - req.setAttribute("LogLevel", "debug"); - } - - - StatisticLogger logger = StatisticLogger.getInstance(); - logger.logErrorOperation(exceptionThrown); - - - // forward this to errorpage-auth.jsp where the HTML error page is - // generated - ServletContext context = req.getServletContext(); - RequestDispatcher dispatcher = context - .getRequestDispatcher("/errorpage-auth.jsp"); - try { - - resp.setHeader(HEADER_EXPIRES, HEADER_VALUE_EXPIRES); - resp.setHeader(HEADER_PRAGMA, HEADER_VALUE_PRAGMA); - resp.setHeader(HEADER_CACHE_CONTROL, HEADER_VALUE_CACHE_CONTROL); - resp.addHeader(HEADER_CACHE_CONTROL, HEADER_VALUE_CACHE_CONTROL_IE); - - dispatcher.forward(req, resp); - } catch (ServletException e) { - Logger.error(e); - } catch (IOException e) { - Logger.error(e); - } - } - - /** - * Handles an error.
> - *
    - *
  • Logs the error
  • - *
  • Places error message and exception thrown into the request as request - * attributes (to be used by "/errorpage-auth.jsp")
  • - *
  • Sets HTTP status 500 (internal server error)
  • - *
- * - * @param errorMessage - * error message - * @param exceptionThrown - * exception thrown - * @param req - * servlet request - * @param resp - * servlet response - */ - protected void handleError(String errorMessage, Throwable exceptionThrown, - HttpServletRequest req, HttpServletResponse resp, String pendingRequestID) { - - if (null != errorMessage) { - Logger.error(errorMessage); - req.setAttribute("ErrorMessage", errorMessage); - } - - if (null != exceptionThrown) { - if (null == errorMessage) - errorMessage = exceptionThrown.getMessage(); - Logger.error(errorMessage, exceptionThrown); - req.setAttribute("ExceptionThrown", exceptionThrown); - } - - if (Logger.isDebugEnabled()) { - req.setAttribute("LogLevel", "debug"); - } - - if (!(exceptionThrown instanceof MOAIDException)) { - Logger.error("Receive an internal error: Message=" + exceptionThrown.getMessage(), exceptionThrown); - - } - - IExceptionStore store = DBExceptionStoreImpl.getStore(); - String id = store.storeException(exceptionThrown); - - if (id != null && MiscUtil.isNotEmpty(pendingRequestID)) { - - String redirectURL = null; - - redirectURL = ServletUtils.getBaseUrl(req); - redirectURL += "/dispatcher?" + ERROR_CODE_PARAM + "=" + id - + "&" + DispatcherServlet.PARAM_TARGET_PENDINGREQUESTID + "=" + pendingRequestID; - - resp.setContentType("text/html"); - resp.setStatus(302); - - resp.addHeader("Location", redirectURL); - Logger.debug("REDIRECT TO: " + redirectURL); - - return; - - } else { - - //Exception can not be stored in database - handleErrorNoRedirect(errorMessage, exceptionThrown, req, resp); - } - } - - /** - * Handles a WrongParametersException. - * - * @param req - * servlet request - * @param resp - * servlet response - */ - protected void handleWrongParameters(WrongParametersException ex, - HttpServletRequest req, HttpServletResponse resp) { - Logger.error(ex.toString()); - req.setAttribute("WrongParameters", ex.getMessage()); - - // forward this to errorpage-auth.jsp where the HTML error page is - // generated - ServletContext context = req.getServletContext(); - RequestDispatcher dispatcher = context - .getRequestDispatcher("/errorpage-auth.jsp"); - try { - setNoCachingHeaders(resp); - dispatcher.forward(req, resp); - } catch (ServletException e) { - Logger.error(e); - } catch (IOException e) { - Logger.error(e); - } - } - - /** - * Logs all servlet parameters for debugging purposes. - */ - protected void logParameters(HttpServletRequest req) { - for (Enumeration params = req.getParameterNames(); params - .hasMoreElements();) { - String parname = (String) params.nextElement(); - Logger.debug("Parameter " + parname + req.getParameter(parname)); - } - } - - /** - * Parses the request input stream for parameters, assuming parameters are - * encoded UTF-8 (no standard exists how browsers should encode them). - * - * @param req - * servlet request - * - * @return mapping parameter name -> value - * - * @throws IOException - * if parsing request parameters fails. - * - * @throws FileUploadException - * if parsing request parameters fails. - */ - protected Map getParameters(HttpServletRequest req) throws IOException, - FileUploadException { - - Map parameters = new HashMap(); - - if (ServletFileUpload.isMultipartContent(req)) { - // request is encoded as mulitpart/form-data - FileItemFactory factory = new DiskFileItemFactory(); - ServletFileUpload upload = null; - upload = new ServletFileUpload(factory); - List items = null; - items = upload.parseRequest(req); - for (int i = 0; i < items.size(); i++) { - FileItem item = (FileItem) items.get(i); - if (item.isFormField()) { - // Process only form fields - no file upload items - String logString = item.getString("UTF-8"); - - // TODO use RegExp - String startS = ""; - String endS = "urn:publicid:gv.at:baseid"; - String logWithMaskedBaseid = logString; - int start = logString.indexOf(startS); - if (start > -1) { - int end = logString.indexOf(endS); - if (end > -1) { - logWithMaskedBaseid = logString.substring(0, start); - logWithMaskedBaseid += startS; - logWithMaskedBaseid += "xxxxxxxxxxxxxxxxxxxxxxxx"; - logWithMaskedBaseid += logString.substring(end, - logString.length()); - } - } - parameters - .put(item.getFieldName(), item.getString("UTF-8")); - Logger.debug("Processed multipart/form-data request parameter: \nName: " - + item.getFieldName() - + "\nValue: " - + logWithMaskedBaseid); - } - } - } - - else { - // request is encoded as application/x-www-urlencoded - // [tknall]: we must not consume request body input stream once servlet-api request parameters have been accessed - - /* - InputStream in = req.getInputStream(); - - String paramName; - String paramValueURLEncoded; - do { - paramName = new String(readBytesUpTo(in, '=')); - if (paramName.length() > 0) { - paramValueURLEncoded = readBytesUpTo(in, '&'); - String paramValue = URLDecoder.decode(paramValueURLEncoded, - "UTF-8"); - parameters.put(paramName, paramValue); - } - } while (paramName.length() > 0); - in.close(); - */ - - Iterator> requestParamIt = req.getParameterMap().entrySet().iterator(); - while (requestParamIt.hasNext()) { - Entry entry = requestParamIt.next(); - String key = entry.getKey(); - String[] values = entry.getValue(); - // take the last value from the value array since the legacy code above also does it this way - parameters.put(key, ArrayUtils.isEmpty(values) ? null : values[values.length-1]); - } - - } - - return parameters; - } - - /** - * Reads bytes up to a delimiter, consuming the delimiter. - * - * @param in - * input stream - * @param delimiter - * delimiter character - * @return String constructed from the read bytes - * @throws IOException - */ - protected String readBytesUpTo(InputStream in, char delimiter) - throws IOException { - ByteArrayOutputStream bout = new ByteArrayOutputStream(); - boolean done = false; - int b; - while (!done && (b = in.read()) >= 0) { - if (b == delimiter) - done = true; - else - bout.write(b); - } - return bout.toString(); - } - - /** - * Sets response headers that prevent caching (code taken from {@link AuthServlet}). - * - * @param resp - * The HttpServletResponse. - */ - public void setNoCachingHeaders(HttpServletResponse resp) { - resp.setHeader(HEADER_EXPIRES, HEADER_VALUE_EXPIRES); - resp.setHeader(HEADER_PRAGMA, HEADER_VALUE_PRAGMA); - resp.setHeader(HEADER_CACHE_CONTROL, HEADER_VALUE_CACHE_CONTROL); - resp.addHeader(HEADER_CACHE_CONTROL, HEADER_VALUE_CACHE_CONTROL_IE); - } - - /** - * Adds a parameter to a URL. - * - * @param url - * the URL - * @param paramname - * parameter name - * @param paramvalue - * parameter value - * @return the URL with parameter added - */ - protected static String addURLParameter(String url, String paramname, - String paramvalue) { - String param = paramname + "=" + paramvalue; - if (url.indexOf("?") < 0) - return url + "?" + param; - else - return url + "&" + param; - } - - /** - * Checks if HTTP requests are allowed - * - * @param authURL - * requestURL - * @throws AuthenticationException - * if HTTP requests are not allowed - * @throws ConfigurationException - */ - protected void checkIfHTTPisAllowed(String authURL) - throws AuthenticationException, ConfigurationException { - // check if HTTP Connection may be allowed (through - // FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY) - - //Removed from MOA-ID 2.0 config -// String boolStr = AuthConfigurationProvider -// .getInstance() -// .getGenericConfigurationParameter( -// AuthConfigurationProvider.FRONTEND_SERVLETS_ENABLE_HTTP_CONNECTION_PROPERTY); - if ((!authURL.startsWith("https:")) - //&& (false == BoolUtils.valueOf(boolStr)) - ) - throw new AuthenticationException("auth.07", new Object[] { authURL - + "*" }); - - } - -} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CertificateReadRequestTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CertificateReadRequestTask.java index 4bcf717c5..bc73a9f2f 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CertificateReadRequestTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CertificateReadRequestTask.java @@ -9,13 +9,13 @@ import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang3.BooleanUtils; import at.gv.egovernment.moa.id.auth.AuthenticationServer; -import at.gv.egovernment.moa.id.auth.MOAIDAuthConstants; import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; import at.gv.egovernment.moa.id.auth.builder.InfoboxReadRequestBuilderCertificate; 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.auth.exception.WrongParametersException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; import at.gv.egovernment.moa.id.process.api.ExecutionContext; import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; @@ -37,7 +37,7 @@ import at.gv.egovernment.moa.logging.Logger; * * Result: *
    - *
  • Responds with {@code InfoBoxReadRequest} (for CCE), {@code DataURL} is {@code {/VerifyCertificate}
  • + *
  • Responds with {@code InfoBoxReadRequest} (for CCE), {@code DataURL} is {@code /VerifyCertificate}
  • *
* Code taken from {@link at.gv.egovernment.moa.id.auth.servlet.VerifyIdentityLinkServlet}. * @see #execute(ExecutionContext, HttpServletRequest, HttpServletResponse) diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CreateIdentityLinkFormTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CreateIdentityLinkFormTask.java index 08030e623..4cd1ea94e 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CreateIdentityLinkFormTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/CreateIdentityLinkFormTask.java @@ -14,6 +14,7 @@ import at.gv.egovernment.moa.id.auth.builder.StartAuthenticationBuilder; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; import at.gv.egovernment.moa.id.auth.servlet.GenerateIFrameTemplateServlet; import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetForeignIDTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetForeignIDTask.java index 4e535b83d..4771628a3 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetForeignIDTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetForeignIDTask.java @@ -23,6 +23,7 @@ import at.gv.egovernment.moa.id.auth.data.IdentityLink; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.auth.exception.ParseException; import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; import at.gv.egovernment.moa.id.auth.parser.CreateXMLSignatureResponseParser; import at.gv.egovernment.moa.id.auth.parser.IdentityLinkAssertionParser; import at.gv.egovernment.moa.id.client.SZRGWClientException; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetMISSessionIDTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetMISSessionIDTask.java index 6714dfb53..f08f96782 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetMISSessionIDTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/GetMISSessionIDTask.java @@ -20,6 +20,7 @@ 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.auth.exception.WrongParametersException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; import at.gv.egovernment.moa.id.config.ConnectionParameter; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/PrepareAuthBlockSignatureTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/PrepareAuthBlockSignatureTask.java index d7b35236e..36d6ea555 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/PrepareAuthBlockSignatureTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/PrepareAuthBlockSignatureTask.java @@ -11,6 +11,7 @@ import at.gv.egovernment.moa.id.auth.AuthenticationServer; import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyAuthenticationBlockTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyAuthenticationBlockTask.java index 060bdf72c..1e1a4df89 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyAuthenticationBlockTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyAuthenticationBlockTask.java @@ -24,6 +24,7 @@ import at.gv.egovernment.moa.id.auth.exception.AuthenticationException; import at.gv.egovernment.moa.id.auth.exception.MISSimpleClientException; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; import at.gv.egovernment.moa.id.config.ConnectionParameter; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyCertificateTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyCertificateTask.java index af0c4c897..32ea7fe3a 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyCertificateTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyCertificateTask.java @@ -18,6 +18,7 @@ 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.auth.exception.WrongParametersException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; import at.gv.egovernment.moa.id.commons.db.ex.MOADatabaseException; import at.gv.egovernment.moa.id.process.api.ExecutionContext; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyIdentityLinkTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyIdentityLinkTask.java index 75fdd19aa..bf10b3681 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyIdentityLinkTask.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/internal/tasks/VerifyIdentityLinkTask.java @@ -15,6 +15,7 @@ import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; import at.gv.egovernment.moa.id.auth.exception.ParseException; import at.gv.egovernment.moa.id.auth.exception.WrongParametersException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; import at.gv.egovernment.moa.id.process.api.ExecutionContext; import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/registration/ModuleRegistration.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/registration/ModuleRegistration.java new file mode 100644 index 000000000..c2a34ff21 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/registration/ModuleRegistration.java @@ -0,0 +1,149 @@ +package at.gv.egovernment.moa.id.auth.modules.registration; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.ServiceLoader; + +import javax.annotation.PostConstruct; + +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.core.io.Resource; + +import at.gv.egovernment.moa.id.auth.modules.AuthModule; +import at.gv.egovernment.moa.id.process.ProcessDefinitionParserException; +import at.gv.egovernment.moa.id.process.ProcessEngine; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; + +/** + * This class handles registering modules. The modules are detected either with + * the ServiceLoader mechanism or via Spring. All detected modules are ranked + * according to their priority. + */ +public class ModuleRegistration { + + private static ModuleRegistration instance = new ModuleRegistration(); + + private List priorizedModules = new ArrayList<>(); + + @Autowired + private ApplicationContext ctx; + + @Autowired + private ProcessEngine processEngine; + + private Logger log = LoggerFactory.getLogger(getClass()); + + public static ModuleRegistration getInstance() { + return instance; + } + + private ModuleRegistration() { + } + + @PostConstruct + private void init() { + // load modules via the ServiceLoader + initServiceLoaderModules(); + + // load modules via Spring + initSpringModules(); + + // order modules according to their priority + sortModules(); + } + + /** + * Discovers modules which use the ServiceLoader mechanism. + */ + private void initServiceLoaderModules() { + log.info("Looking for auth modules."); + ServiceLoader loader = ServiceLoader.load(AuthModule.class); + Iterator modules = loader.iterator(); + while (modules.hasNext()) { + AuthModule module = modules.next(); + log.info("Detected module {}", module.getClass().getName()); + registerModuleProcessDefinitions(module); + priorizedModules.add(module); + } + } + + /** + * Discovers modules which use Spring. + */ + private void initSpringModules() { + log.debug("Discovering Spring modules."); + Map modules = ctx.getBeansOfType(AuthModule.class); + for (AuthModule module : modules.values()) { + registerModuleProcessDefinitions(module); + priorizedModules.add(module); + } + } + + /** + * Registers the resource uris for the module. + * + * @param module + * the module. + */ + private void registerModuleProcessDefinitions(AuthModule module) { + for (String uri : module.getProcessDefinitions()) { + Resource resource = ctx.getResource(uri); + if (resource.isReadable()) { + log.info("Registering process definition '{}'.", uri); + try (InputStream processDefinitionInputStream = resource.getInputStream()) { + processEngine.registerProcessDefinition(processDefinitionInputStream); + } catch (IOException e) { + log.error("Process definition '{}' could NOT be read.", uri, e); + } catch (ProcessDefinitionParserException e) { + log.error("Error while parsing process definition '{}'", uri, e); + } + } else { + log.error("Process definition '{}' cannot be read.", uri); + } + } + } + + /** + * Order the modules in descending order according to their priority. + */ + private void sortModules() { + Collections.sort(priorizedModules, new Comparator() { + @Override + public int compare(AuthModule thisAuthModule, AuthModule otherAuthModule) { + int thisOrder = thisAuthModule.getPriority(); + int otherOrder = otherAuthModule.getPriority(); + return (thisOrder < otherOrder ? -1 : (thisOrder == otherOrder ? 0 : 1)); + } + }); + } + + /** + * Returns the process id of the first process, in the highest ranked + * module, which is able to work with the given execution context. + * + * @param context + * the {@link ExecutionContext}. + * @return the process id or {@code null} + */ + public String selectProcess(ExecutionContext context) { + for (AuthModule module : priorizedModules) { + String id = module.selectProcess(context); + if (StringUtils.isNotEmpty(id)) { + log.debug("Process with id '{}' selected, for context '{}'.", id, context); + return id; + } + } + log.info("No process is able to handle context '{}'.", context); + return null; + } +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java deleted file mode 100644 index 55a7907ed..000000000 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java +++ /dev/null @@ -1,39 +0,0 @@ -package at.gv.egovernment.moa.id.auth.modules.stork; - -import org.apache.commons.lang3.StringUtils; - -import at.gv.egovernment.moa.id.moduls.moduleregistration.AuthModule; -import at.gv.egovernment.moa.id.process.api.ExecutionContext; - -/** - * Module descriptor for an auth module providing stork authentication related processes. - * @author tknall - */ -public class STORKAuthModuleImpl implements AuthModule { - - private int priority = 0; - - @Override - public int getPriority() { - return priority; - } - - /** - * Sets the priority of this module. Default value is {@code 0}. - * @param priority The priority. - */ - public void setPriority(int priority) { - this.priority = priority; - } - - @Override - public String selectProcess(ExecutionContext context) { - return StringUtils.isNotBlank((String) context.get("ccc")) ? "STORKAuthentication" : null; - } - - @Override - public String[] getProcessDefinitions() { - return new String[] { "classpath:at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthentication.process.xml" }; - } - -} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java deleted file mode 100644 index 7478a57c3..000000000 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java +++ /dev/null @@ -1,37 +0,0 @@ -package at.gv.egovernment.moa.id.auth.modules.stork; - -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRegistration; - -import org.springframework.web.WebApplicationInitializer; - -import at.gv.egovernment.moa.id.auth.servlet.ProcessEngineSignalServlet; - -/** - * Spring automatically discovers {@link WebApplicationInitializer} implementations at startup.
- * This STORK webapp initializer adds the required servlet mappings: - *
    - *
  • {@code /PEPSConnector}
  • - *
  • {@code /PEPSConnectorWithLocalSigning}
  • - *
- * for the {@linkplain ProcessEngineSignalServlet process engine servlet} (named {@code ProcessEngineSignal}) that wakes - * up a process in order to execute asynchronous tasks. Therefore the servlet mappings mentioned above do not need to be - * declared in {@code web.xml}. - * - * @author tknall - * @see ProcessEngineSignalServlet - */ -public class STORKWebApplicationInitializer implements WebApplicationInitializer { - - @Override - public void onStartup(ServletContext servletContext) throws ServletException { - ServletRegistration servletRegistration = servletContext.getServletRegistration("ProcessEngineSignal"); - if (servletRegistration == null) { - throw new IllegalStateException("Servlet 'ProcessEngineSignal' expected to be registered."); - } - servletRegistration.addMapping("/PEPSConnectorWithLocalSigning"); - servletRegistration.addMapping("/PEPSConnector"); - } - -} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java deleted file mode 100644 index 202e405ef..000000000 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java +++ /dev/null @@ -1,223 +0,0 @@ -package at.gv.egovernment.moa.id.auth.modules.stork.tasks; - -import iaik.x509.X509Certificate; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.security.cert.CertificateException; -import java.util.HashMap; - -import javax.activation.DataSource; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBElement; -import javax.xml.bind.JAXBException; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.TransformerConfigurationException; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactoryConfigurationError; - -import org.apache.commons.io.IOUtils; -import org.xml.sax.SAXException; - -import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; -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.BKUException; -import at.gv.egovernment.moa.id.auth.exception.BuildException; -import at.gv.egovernment.moa.id.auth.exception.MOAIDException; -import at.gv.egovernment.moa.id.auth.exception.ParseException; -import at.gv.egovernment.moa.id.auth.exception.ServiceException; -import at.gv.egovernment.moa.id.auth.modules.internal.tasks.AbstractAuthServletTask; -import at.gv.egovernment.moa.id.auth.stork.STORKException; -import at.gv.egovernment.moa.id.auth.stork.STORKResponseProcessor; -import at.gv.egovernment.moa.id.config.ConfigurationException; -import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; -import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; -import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; -import at.gv.egovernment.moa.logging.Logger; -import at.gv.egovernment.moa.spss.MOAException; -import at.gv.egovernment.moa.spss.api.SPSSFactory; -import at.gv.egovernment.moa.spss.api.SignatureVerificationService; -import at.gv.egovernment.moa.spss.api.common.Content; -import at.gv.egovernment.moa.spss.api.xmlverify.VerifySignatureInfo; -import at.gv.egovernment.moa.spss.api.xmlverify.VerifySignatureLocation; -import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureRequest; -import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureResponse; -import at.gv.util.xsd.xmldsig.SignatureType; -import at.gv.util.xsd.xmldsig.X509DataType; -import eu.stork.oasisdss.api.LightweightSourceResolver; -import eu.stork.oasisdss.api.exceptions.ApiUtilsException; -import eu.stork.oasisdss.api.exceptions.UtilsException; -import eu.stork.oasisdss.profile.SignResponse; -import eu.stork.peps.auth.commons.IPersonalAttributeList; - -public abstract class AbstractPepsConnectorWithLocalSigningTask extends AbstractAuthServletTask { - - String getCitizienSignatureFromSignResponse(SignResponse dssSignResponse) throws IllegalArgumentException, - TransformerConfigurationException, UtilsException, TransformerException, - TransformerFactoryConfigurationError, IOException, ApiUtilsException { - // fetch signed doc - DataSource ds = LightweightSourceResolver.getDataSource(dssSignResponse); - if (ds == null) { - throw new ApiUtilsException("No datasource found in response"); - } - - InputStream incoming = ds.getInputStream(); - String citizenSignature = IOUtils.toString(incoming); - incoming.close(); - - return citizenSignature; - } - - void SZRGInsertion(AuthenticationSession moaSession, IPersonalAttributeList personalAttributeList, - String authnContextClassRef, String citizenSignature) throws STORKException, MOAIDException { - Logger.debug("Foregin Citizen signature successfully extracted from STORK Assertion (signedDoc)"); - Logger.debug("Citizen signature will be verified by SZR Gateway!"); - - Logger.debug("fetching OAParameters from database"); - - OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter( - moaSession.getPublicOAURLPrefix()); - if (oaParam == null) - throw new AuthenticationException("auth.00", new Object[] { moaSession.getPublicOAURLPrefix() }); - - // retrieve target - // TODO: check in case of SSO!!! - String targetType = null; - if (oaParam.getBusinessService()) { - String id = oaParam.getIdentityLinkDomainIdentifier(); - if (id.startsWith(AuthenticationSession.REGISTERANDORDNR_PREFIX_)) - targetType = id; - else - targetType = AuthenticationSession.REGISTERANDORDNR_PREFIX_ + moaSession.getDomainIdentifier(); - } else { - targetType = AuthenticationSession.TARGET_PREFIX_ + oaParam.getTarget(); - } - - Logger.debug("Starting connecting SZR Gateway"); - // contact SZR Gateway - IdentityLink identityLink = null; - - identityLink = STORKResponseProcessor.connectToSZRGateway(personalAttributeList, oaParam.getFriendlyName(), - targetType, null, oaParam.getMandateProfiles(), citizenSignature); - Logger.debug("SZR communication was successfull"); - - if (identityLink == null) { - Logger.error("SZR Gateway did not return an identity link."); - throw new MOAIDException("stork.10", null); - } - Logger.info("Received Identity Link from SZR Gateway"); - moaSession.setIdentityLink(identityLink); - - Logger.debug("Adding addtional STORK attributes to MOA session"); - moaSession.setStorkAttributes(personalAttributeList); - - // We don't have BKUURL, setting from null to "Not applicable" - moaSession.setBkuURL("Not applicable (STORK Authentication)"); - - // free for single use - moaSession.setAuthenticatedUsed(false); - - // stork did the authentication step - moaSession.setAuthenticated(true); - - // TODO: found better solution, but QAA Level in response could be not supported yet - try { - if (authnContextClassRef == null) - authnContextClassRef = PVPConstants.STORK_QAA_PREFIX + oaParam.getQaaLevel(); - moaSession.setQAALevel(authnContextClassRef); - - } catch (Throwable e) { - Logger.warn("STORK QAA-Level is not found in AuthnResponse. Set QAA Level to requested level"); - moaSession.setQAALevel(PVPConstants.STORK_QAA_PREFIX + oaParam.getQaaLevel()); - - } - - } - - X509Certificate getSignerCertificate(String citizenSignature) throws CertificateException, JAXBException, - UnsupportedEncodingException { - JAXBContext ctx = JAXBContext.newInstance(SignatureType.class.getPackage().getName()); - SignatureType root = ((JAXBElement) ctx.createUnmarshaller().unmarshal( - IOUtils.toInputStream(citizenSignature))).getValue(); - - // extract certificate - for (Object current : root.getKeyInfo().getContent()) - if (((JAXBElement) current).getValue() instanceof X509DataType) { - for (Object currentX509Data : ((JAXBElement) current).getValue() - .getX509IssuerSerialOrX509SKIOrX509SubjectName()) { - JAXBElement casted = ((JAXBElement) currentX509Data); - if (casted.getName().getLocalPart().equals("X509Certificate")) { - return new X509Certificate(((String) casted.getValue()).getBytes("UTF-8")); - } - } - } - return null; - } - - VerifyXMLSignatureResponse verifyXMLSignature(String signature) throws AuthenticationException, ParseException, - BKUException, BuildException, ConfigurationException, ServiceException, UnsupportedEncodingException, - SAXException, IOException, ParserConfigurationException, MOAException { - // Based on MOA demo client - // Factory und Service instanzieren - SPSSFactory spssFac = SPSSFactory.getInstance(); - SignatureVerificationService sigVerifyService = SignatureVerificationService.getInstance(); - - Content sigDocContent1 = spssFac.createContent(IOUtils.toInputStream(signature, "UTF-8"), null); - - // Position der zu prüfenden Signatur im Dokument angeben - // (Nachdem im XPath-Ausdruck ein NS-Präfix verwendet wird, muss in einer Lookup-Tabelle - // der damit bezeichnete Namenraum mitgegeben werden) - HashMap nSMap = new HashMap(); - nSMap.put("dsig", "http://www.w3.org/2000/09/xmldsig#"); - VerifySignatureLocation sigLocation = spssFac.createVerifySignatureLocation("//dsig:Signature", nSMap); - - // Zu prüfendes Dokument und Signaturposition zusammenfassen - - VerifySignatureInfo sigInfo = spssFac.createVerifySignatureInfo(sigDocContent1, sigLocation); - - // Prüfrequest zusammenstellen - VerifyXMLSignatureRequest verifyRequest = spssFac.createVerifyXMLSignatureRequest(null, // Wird Prüfzeit nicht - // angegeben, wird - // aktuelle Zeit - // verwendet - sigInfo, null, // Keine Ergänzungsobjekte notwendig - null, // Signaturmanifest-Prüfung soll nicht durchgeführt werden - false, // Hash-Inputdaten, d.h. tatsächlich signierte Daten werden nicht zurückgeliefert - "MOAIDBuergerkartePersonenbindungMitTestkarten");// TODO load from config - // "Test-Signaturdienste"); // ID des verwendeten Vertrauensprofils - - VerifyXMLSignatureResponse verifyResponse = null; - try { - // Aufruf der Signaturprüfung - verifyResponse = sigVerifyService.verifyXMLSignature(verifyRequest); - } catch (MOAException e) { - // Service liefert Fehler - System.err.println("Die Signaturprüfung hat folgenden Fehler geliefert:"); - System.err.println("Fehlercode: " + e.getMessageId()); - System.err.println("Fehlernachricht: " + e.getMessage()); - throw e; - } - - return verifyResponse; - } - - at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse convert( - VerifyXMLSignatureResponse xMLVerifySignatureResponse) { - at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse response = new at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse(); - response.setCertificateCheckCode(xMLVerifySignatureResponse.getCertificateCheck().getCode()); - response.setPublicAuthority(xMLVerifySignatureResponse.getSignerInfo().isPublicAuthority()); - // response.setPublicAuthorityCode(publicAuthorityCode) - response.setQualifiedCertificate(xMLVerifySignatureResponse.getSignerInfo().isQualifiedCertificate()); - response.setSignatureCheckCode(xMLVerifySignatureResponse.getSignatureCheck().getCode()); - response.setSignatureManifestCheckCode(xMLVerifySignatureResponse.getSignatureManifestCheck().getCode()); - // response.setSigningDateTime() - // response.setX509certificate(x509certificate) - response.setXmlDSIGManifestCheckCode(xMLVerifySignatureResponse.getSignatureManifestCheck().getCode()); - // response.setXmlDSIGManigest(xMLVerifySignatureResponse.getSignatureManifestCheck()) - // response.setXmlDsigSubjectName(xmlDsigSubjectName) - return response; - } - -} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java deleted file mode 100644 index ec7ee04a6..000000000 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java +++ /dev/null @@ -1,112 +0,0 @@ -package at.gv.egovernment.moa.id.auth.modules.stork.tasks; - -import static at.gv.egovernment.moa.id.auth.MOAIDAuthConstants.*; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.lang.StringEscapeUtils; -import org.apache.commons.lang3.StringUtils; - -import at.gv.egovernment.moa.id.auth.AuthenticationServer; -import at.gv.egovernment.moa.id.auth.builder.StartAuthenticationBuilder; -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.auth.exception.WrongParametersException; -import at.gv.egovernment.moa.id.auth.modules.internal.tasks.AbstractAuthServletTask; -import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; -import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; -import at.gv.egovernment.moa.id.config.stork.CPEPS; -import at.gv.egovernment.moa.id.config.stork.STORKConfig; -import at.gv.egovernment.moa.id.process.api.ExecutionContext; -import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; -import at.gv.egovernment.moa.id.util.ParamValidatorUtils; -import at.gv.egovernment.moa.logging.Logger; - -/** - * Creates a SAML2 STORK authentication request, embeds it in a form (in order to satisfy saml post binging) and returns the form withing the HttpServletResponse.

- * In detail: - *

    - *
  • Validates the stork configuration in order to make sure the selected country is supported.
  • - *
  • Puts a flag ({@link #PROCESS_CTX_KEY_CPEPS_ISXMLSIGSUPPORTED}) into the ExecutionContext reflecting the capability of the C-PEPS to create xml signatures.
  • - *
  • Invokes {@link AuthenticationServer#startSTORKAuthentication(HttpServletRequest, HttpServletResponse, AuthenticationSession)} which
  • - *
      - *
    • Creates and signs a SAML2 stork authentication request.
    • - *
    • Creates a signature request for auth block signature (either to be performed by the C-PEPS or locally).
    • - *
    • Using the velocity template engine in order to create a form with the embedded stork request.
    • - *
    • Writes the form to the response output stream.
    • - *
    - *
- * Expects: - *
    - *
  • HttpServletRequest parameter {@linkplain at.gv.egovernment.moa.id.auth.MOAIDAuthConstants#PARAM_SESSIONID PARAM_SESSIONID}
  • - *
  • Property {@code ccc} set within the moa session.
  • - *
- * Result: - *
    - *
  • Form containing a SAML2 Stork authentication request and an action url pointing to the selected C-PEPS.
  • - *
  • Assertion consumer URL for C-PEPS set either to {@code /PEPSConnector} in case of a C-PEPS supporting xml signatures or {@code /PEPSConnectorWithLocalSigning} if the selected C-PEPS does not support xml signatures.
  • - *
  • In case of a C-PEPS not supporting xml signature: moasession with set signedDoc property (containing the signature request for local signing).
  • - *
  • ExecutionContext contains the boolean flag {@link #PROCESS_CTX_KEY_CPEPS_ISXMLSIGSUPPORTED}. - *
- * Code taken from {@link StartAuthenticationBuilder#build(AuthenticationSession, HttpServletRequest, HttpServletResponse)}.
- * Using {@link AuthenticationServer#startSTORKAuthentication(HttpServletRequest, HttpServletResponse, AuthenticationSession)} - * @see #execute(ExecutionContext, HttpServletRequest, HttpServletResponse) - */ -public class CreateStorkAuthRequestFormTask extends AbstractAuthServletTask { - - /** - * Boolean value reflecting the capability of the selected c-peps of creating xml signatures. - */ - public static final String PROCESS_CTX_KEY_CPEPS_ISXMLSIGSUPPORTED = "C-PEPS:XMLSignatureSupported"; - - @Override - public void execute(ExecutionContext executionContext, HttpServletRequest req, HttpServletResponse resp) - throws Exception { - - String pendingRequestID = null; - String sessionID = null; - try { - setNoCachingHeaders(resp); - - sessionID = StringEscapeUtils.escapeHtml(req.getParameter(PARAM_SESSIONID)); - // check parameter - if (!ParamValidatorUtils.isValidSessionID(sessionID)) { - throw new WrongParametersException("CreateStorkAuthRequestFormTask", PARAM_SESSIONID, "auth.12"); - } - AuthenticationSession moasession = AuthenticationServer.getSession(sessionID); - pendingRequestID = AuthenticationSessionStoreage.getPendingRequestID(sessionID); - - if (StringUtils.isEmpty(moasession.getCcc())) { - // illegal state; task should not have been executed without a selected country - throw new AuthenticationException("stork.22", new Object[] { sessionID }); - } - STORKConfig storkConfig = AuthConfigurationProvider.getInstance().getStorkConfig(); - if (!storkConfig.isSTORKAuthentication(moasession.getCcc())) { - throw new AuthenticationException("stork.23", new Object[] { moasession.getCcc(), sessionID }); - } - - // STORK authentication - // cpeps cannot be null - CPEPS cpeps = storkConfig.getCPEPS(moasession.getCcc()); - Logger.debug("Found C-PEPS configuration for citizen of country: " + moasession.getCcc()); - executionContext.put(PROCESS_CTX_KEY_CPEPS_ISXMLSIGSUPPORTED, cpeps.isXMLSignatureSupported()); - - Logger.info("Starting STORK authentication for a citizen of country: " + moasession.getCcc()); - AuthenticationServer.startSTORKAuthentication(req, resp, moasession); - - } catch (MOAIDException ex) { - handleError(null, ex, req, resp, pendingRequestID); - - } catch (Exception e) { - Logger.error("CreateStorkAuthRequestFormTask has an interal Error.", e); - throw new MOAIDException("Internal error.", new Object[] { sessionID }, e); - } - - finally { - ConfigurationDBUtils.closeSession(); - } - } - -} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java deleted file mode 100644 index 077bb2dee..000000000 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java +++ /dev/null @@ -1,216 +0,0 @@ -package at.gv.egovernment.moa.id.auth.modules.stork.tasks; - -import iaik.x509.X509Certificate; - -import java.io.IOException; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.List; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - -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.AuthenticationServer; -import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; -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.auth.stork.STORKException; -import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; -import at.gv.egovernment.moa.id.moduls.ModulUtils; -import at.gv.egovernment.moa.id.process.api.ExecutionContext; -import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; -import at.gv.egovernment.moa.id.util.VelocityProvider; -import at.gv.egovernment.moa.logging.Logger; -import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureResponse; -import eu.stork.oasisdss.api.ApiUtils; -import eu.stork.oasisdss.profile.SignResponse; -import eu.stork.peps.auth.commons.IPersonalAttributeList; -import eu.stork.peps.auth.commons.PersonalAttribute; - -/** - * Processes the citizen's signature, creates identity link using szr gateway and finalizes authentication. - *

- * In detail: - *

    - *
  • Changes moa session id.
  • - *
  • Decodes and validates the sign response, extracting the citizen's signature.
  • - *
  • Verifies the citizen's signature.
  • - *
  • Create {@code signedDoc} attribute.
  • - *
  • Retrieve identity link from SZR gateway using the citizen's signature.
  • - *
  • If the S-PEPS did not provide any gender information, the szr gateway will not be able to issue an identity link. - * Therefore a form is presented asking for the subject's gender. The form finally submits the user back to the - * {@code /PepsConnectorWithLocalSigning} servlet (this task).
  • - *
  • The moa session is updated with authentication information.
  • - *
  • Change moa session id.
  • - *
  • Redirects back to {@code /dispatcher} in order to finalize the authentication.
  • - *
- * Expects: - *
    - *
  • HttpServletRequest parameter {@code moaSessionID}
  • - *
  • HttpServletRequest parameter {@code signresponse}
  • - *
- * Result: - *
    - *
  • Updated moa id session (signed auth block, signer certificate etc.)
  • - *
  • Redirect to {@code /dispatcher}.
  • - *
  • {@link ExecutionContext} contains boolean flag {@code identityLinkAvailable} indicating if an identitylink has been successfully creates or not.
  • - *
- * Possible branches: - *
    - *
  • In case the szr gateway throws exception due to missing gender information: - *
      - *
    • Returns a form for gender selection with action url back to this servlet/task.
    • - *
    - *
  • - *
- * Code taken from {@link at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorWithLocalSigningServlet}.
- * - * @see #execute(ExecutionContext, HttpServletRequest, HttpServletResponse) - */ -public class PepsConnectorHandleLocalSignResponseTask extends AbstractPepsConnectorWithLocalSigningTask { - - @Override - public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) - throws Exception { - String moaSessionID = request.getParameter("moaSessionID"); - String signResponse = request.getParameter("signresponse"); - Logger.info("moaSessionID:" + moaSessionID); - Logger.info("signResponse:" + signResponse); - - if (moaSessionID != null && signResponse != null) { - // redirect from oasis with signresponse - handleSignResponse(executionContext, request, response); - } else { - // should not occur - throw new IOException("should not occur"); - } - return; - } - - private void handleSignResponse(ExecutionContext executionContext, HttpServletRequest request, - HttpServletResponse response) { - Logger.info("handleSignResponse started"); - String moaSessionID = request.getParameter("moaSessionID"); - String signResponse = request.getParameter("signresponse"); - Logger.info("moaSessionID:" + moaSessionID); - Logger.info("signResponse:" + signResponse); - String pendingRequestID = null; - try { - - // load MOASession from database - AuthenticationSession moaSession = AuthenticationServer.getSession(moaSessionID); - // change MOASessionID - moaSessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); - - pendingRequestID = AuthenticationSessionStoreage.getPendingRequestID(moaSessionID); - Logger.info("pendingRequestID:" + pendingRequestID); - String signResponseString = new String(Base64.decodeBase64(signResponse), "UTF8"); - Logger.info("RECEIVED signresponse:" + signResponseString); - // create SignResponse object - Source response1 = new StreamSource(new java.io.StringReader(signResponseString)); - SignResponse dssSignResponse = ApiUtils.unmarshal(response1, SignResponse.class); - - // SignResponse dssSignResponse = (SignResponse) ApiUtils.unmarshal(new StreamSource(new - // java.io.StringReader(Base64.signResponse))); - - String citizenSignature = getCitizienSignatureFromSignResponse(dssSignResponse); - - // memorize signature into authblock - moaSession.setAuthBlock(citizenSignature); - - X509Certificate cert = getSignerCertificate(citizenSignature); - moaSession.setSignerCertificate(cert); - VerifyXMLSignatureResponse xMLVerifySignatureResponse = verifyXMLSignature(citizenSignature); - at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse tmp = convert(xMLVerifySignatureResponse); - - moaSession.setXMLVerifySignatureResponse(tmp); - executionContext.put("identityLinkAvailable", false); - try { - IPersonalAttributeList personalAttributeList = moaSession.getAuthnResponseGetPersonalAttributeList(); - // Add SignResponse TODO Add signature (extracted from signResponse)? - List values = new ArrayList(); - values.add(signResponseString); - // values.add(citizenSignature); - Logger.debug("Assembling signedDoc attribute"); - PersonalAttribute signedDocAttribute = new PersonalAttribute("signedDoc", false, values, "Available"); - personalAttributeList.add(signedDocAttribute); - - String authnContextClassRef = moaSession.getAuthnContextClassRef(); - SZRGInsertion(moaSession, personalAttributeList, authnContextClassRef, citizenSignature); - executionContext.put("identityLinkAvailable", true); - } catch (STORKException e) { - // this is really nasty but we work against the system here. We are supposed to get the gender attribute - // from - // stork. If we do not, we cannot register the person in the ERnP - we have to have the - // gender for the represented person. So here comes the dirty hack. - if (e.getCause() instanceof STORKException - && e.getCause().getMessage().equals("gender not found in response")) { - try { - Logger.trace("Initialize VelocityEngine..."); - - VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); - Template template = velocityEngine.getTemplate("/resources/templates/fetchGender.html"); - VelocityContext context = new VelocityContext(); - context.put("SAMLResponse", request.getParameter("SAMLResponse")); - context.put("action", request.getRequestURL()); - - StringWriter writer = new StringWriter(); - template.merge(context, writer); - response.getOutputStream().write(writer.toString().getBytes("UTF-8")); - } catch (Exception e1) { - Logger.error("Error sending gender retrival form.", e1); - // httpSession.invalidate(); - throw new MOAIDException("stork.10", null); - } - - return; - } - - Logger.error("Error connecting SZR Gateway", e); - throw new MOAIDException("stork.10", null); - } - - Logger.debug("Add full STORK AuthnResponse to MOA session"); - moaSession.setStorkAuthnResponse(request.getParameter("SAMLResponse"));// TODO ask Florian/Thomas - // authnResponse? - moaSession.setForeigner(true); - - // session is implicit stored in changeSessionID!!!! - String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); - - Logger.info("Changed MOASession " + moaSessionID + " to Session " + newMOASessionID); - - // redirect - String redirectURL = null; - redirectURL = new DataURLBuilder().buildDataURL(moaSession.getAuthURL(), - ModulUtils.buildAuthURL(moaSession.getModul(), moaSession.getAction(), pendingRequestID), - newMOASessionID); - redirectURL = response.encodeRedirectURL(redirectURL); - - response.sendRedirect(redirectURL); - Logger.info("REDIRECT TO: " + redirectURL); - - } catch (AuthenticationException e) { - handleError(null, e, request, response, pendingRequestID); - - } catch (MOAIDException e) { - handleError(null, e, request, response, pendingRequestID); - - } catch (Exception e) { - Logger.error("PEPSConnector has an interal Error.", e); - } - - finally { - ConfigurationDBUtils.closeSession(); - } - } - -} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java deleted file mode 100644 index 3338804b4..000000000 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java +++ /dev/null @@ -1,439 +0,0 @@ -package at.gv.egovernment.moa.id.auth.modules.stork.tasks; - -import iaik.x509.X509Certificate; - -import java.io.IOException; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.List; - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.xml.transform.Source; -import javax.xml.transform.stream.StreamSource; - -import org.apache.commons.codec.binary.Base64; -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringEscapeUtils; -import org.apache.velocity.Template; -import org.apache.velocity.VelocityContext; -import org.apache.velocity.app.VelocityEngine; -import org.opensaml.saml2.core.StatusCode; - -import at.gv.egovernment.moa.id.auth.AuthenticationServer; -import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; -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.auth.servlet.PEPSConnectorWithLocalSigningServlet; -import at.gv.egovernment.moa.id.auth.stork.STORKException; -import at.gv.egovernment.moa.id.auth.stork.STORKResponseProcessor; -import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; -import at.gv.egovernment.moa.id.commons.db.dao.config.AttributeProviderPlugin; -import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; -import at.gv.egovernment.moa.id.moduls.ModulUtils; -import at.gv.egovernment.moa.id.process.api.ExecutionContext; -import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; -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.oasisdss.api.ApiUtils; -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.STORKAuthnRequest; -import eu.stork.peps.auth.commons.STORKAuthnResponse; -import eu.stork.peps.auth.engine.STORKSAMLEngine; -import eu.stork.peps.exceptions.STORKSAMLEngineException; - -/** - * Validates the SAML response from C-PEPS. - *

- * In detail: - *

    - *
  • Decodes and validates SAML response from C-PEPS.
  • - *
  • Retrieves the moa session using the session id provided by HttpServletRequest parameter {@code RelayState} or by {@code inResponseTo} attribute of the saml response.
  • - *
  • Store saml response in moa session.
  • - *
  • Change moa session id.
  • - *
  • Redirect to {@code /PEPSConnectorWithLocalSigning}, with providing the moa session id as request parameter.
  • - *
- * Expects: - *
    - *
  • HttpServletRequest parameter {@code moaSessionID} to be {@code null}
  • - *
  • HttpServletRequest parameter {@code signresponse} to be {@code null}
  • - *
  • HttpServletRequest parameter {@code SAMLResponse}
  • - *
  • Either HttpServletRequest parameter {@code RelayState} or {@code inResponseTo} attribute within the saml response, both reflecting the moa session id.
  • - *
- * Result: - *
    - *
  • Updated moa session (with saml response).
  • - *
  • Redirect to {@code /PEPSConnectorWithLocalSigning}, with providing the moa session id as request parameter.
  • - *
- * Code taken from {@link at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorWithLocalSigningServlet}.
- * - * @see #execute(ExecutionContext, HttpServletRequest, HttpServletResponse) - */ -public class PepsConnectorHandleResponseWithoutSignatureTask extends AbstractPepsConnectorWithLocalSigningTask { - - private String oasisDssWebFormURL = "https://testvidp.buergerkarte.at/oasis-dss/DSSWebFormServlet"; - // load from config below - - @Override - public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) - throws Exception { - String moaSessionID = request.getParameter("moaSessionID"); - String signResponse = request.getParameter("signresponse"); - Logger.info("moaSessionID:" + moaSessionID); - Logger.info("signResponse:" + signResponse); - - if (moaSessionID == null && signResponse == null) { - // normal saml response - handleSAMLResponse(executionContext, request, response); - - } else { - // should not occur - throw new IOException("should not occur"); - } - return; - } - - private void handleSAMLResponse(ExecutionContext executionContext, HttpServletRequest request, - HttpServletResponse response) { - Logger.info("handleSAMLResponse started"); - String pendingRequestID = null; - - setNoCachingHeaders(response); - try { - Logger.info("PEPSConnector Servlet invoked, expecting C-PEPS message."); - Logger.debug("This ACS endpoint is: " + HTTPUtils.getBaseURL(request)); - - Logger.trace("No Caching headers set for HTTP response"); - - // check if https or only http - super.checkIfHTTPisAllowed(request.getRequestURL().toString()); - - Logger.debug("Beginning to extract SAMLResponse out of HTTP Request"); - - // extract STORK Response from HTTP Request - // Decodes SAML Response - byte[] decSamlToken; - try { - decSamlToken = PEPSUtil.decodeSAMLToken(request.getParameter("SAMLResponse")); - Logger.debug("SAMLResponse: " + new String(decSamlToken)); - - } catch (NullPointerException e) { - Logger.error("Unable to retrieve STORK Response", e); - throw new MOAIDException("stork.04", null); - } - - // Get SAMLEngine instance - STORKSAMLEngine engine = STORKSAMLEngine.getInstance("outgoing"); - - STORKAuthnResponse authnResponse = null; - try { - // validate SAML Token - Logger.debug("Starting validation of SAML response"); - authnResponse = engine.validateSTORKAuthnResponse(decSamlToken, (String) request.getRemoteHost()); - Logger.info("SAML response succesfully verified!"); - } catch (STORKSAMLEngineException e) { - Logger.error("Failed to verify STORK SAML Response", e); - throw new MOAIDException("stork.05", null); - } - - Logger.info("STORK SAML Response message succesfully extracted"); - Logger.debug("STORK response: "); - Logger.debug(authnResponse.toString()); - - Logger.debug("Trying to find MOA Session-ID ..."); - // String moaSessionID = request.getParameter(PARAM_SESSIONID); - // first use SAML2 relayState - String moaSessionID = request.getParameter("RelayState"); - - // escape parameter strings - moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID); - - // check if SAML2 relaystate includes a MOA sessionID - if (StringUtils.isEmpty(moaSessionID)) { - // if relaystate is emtpty, use SAML response -> inResponseTo element as session identifier - - moaSessionID = authnResponse.getInResponseTo(); - moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID); - - if (StringUtils.isEmpty(moaSessionID)) { - // No authentication session has been started before - Logger.error("MOA-SessionID was not found, no previous AuthnRequest had been started"); - Logger.debug("PEPSConnectorURL was: " + request.getRequestURL()); - throw new AuthenticationException("auth.02", new Object[] { moaSessionID }); - - } else - Logger.trace("Use MOA SessionID " + moaSessionID + " from AuthnResponse->inResponseTo attribute."); - - } else - // Logger.trace("MOA SessionID " + moaSessionID + " is found in http GET parameter."); - Logger.trace("MOA SessionID " + moaSessionID + " is found in SAML2 relayState."); - - /* - * INFO!!!! SAML message IDs has an different format then MOASessionIDs This is only a workaround because - * many PEPS does not support SAML2 relayState or MOASessionID as AttributConsumerServiceURL GET parameter - */ - // if (!ParamValidatorUtils.isValidSessionID(moaSessionID)) - // throw new WrongParametersException("VerifyAuthenticationBlock", PARAM_SESSIONID, "auth.12"); - - pendingRequestID = AuthenticationSessionStoreage.getPendingRequestID(moaSessionID); - - // load MOASession from database - AuthenticationSession moaSession = AuthenticationServer.getSession(moaSessionID); - // change MOASessionID - moaSessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); - - Logger.info("Found MOA sessionID: " + moaSessionID); - - String statusCodeValue = authnResponse.getStatusCode(); - - if (!statusCodeValue.equals(StatusCode.SUCCESS_URI)) { - Logger.error("Received ErrorResponse from PEPS: " + statusCodeValue); - throw new MOAIDException("stork.06", new Object[] { statusCodeValue }); - } - - Logger.info("Got SAML response with authentication success message."); - - Logger.debug("MOA session is still valid"); - - STORKAuthnRequest storkAuthnRequest = moaSession.getStorkAuthnRequest(); - - if (storkAuthnRequest == null) { - Logger.error("Could not find any preceeding STORK AuthnRequest to this MOA session: " + moaSessionID); - throw new MOAIDException("stork.07", null); - } - - Logger.debug("Found a preceeding STORK AuthnRequest to this MOA session: " + moaSessionID); - - // //////////// incorporate gender from parameters if not in stork response - - IPersonalAttributeList attributeList = authnResponse.getPersonalAttributeList(); - - // but first, check if we have a representation case - if (STORKResponseProcessor.hasAttribute("mandateContent", attributeList) - || STORKResponseProcessor.hasAttribute("representative", attributeList) - || STORKResponseProcessor.hasAttribute("represented", attributeList)) { - // in a representation case... - moaSession.setUseMandate("true"); - - // and check if we have the gender value - PersonalAttribute gender = attributeList.get("gender"); - if (null == gender) { - String gendervalue = (String) request.getParameter("gender"); - if (null != gendervalue) { - gender = new PersonalAttribute(); - gender.setName("gender"); - ArrayList tmp = new ArrayList(); - tmp.add(gendervalue); - gender.setValue(tmp); - - authnResponse.getPersonalAttributeList().add(gender); - } - } - } - - - - // //////////////////////////////////////////////////////////////////////// - - Logger.debug("Starting extraction of signedDoc attribute"); - // extract signed doc element and citizen signature - String citizenSignature = null; - try { - PersonalAttribute signedDoc = authnResponse.getPersonalAttributeList().get("signedDoc"); - String signatureInfo = null; - // FIXME: Remove nonsense code (signedDoc attribute... (throw Exception for "should not occur" situations)), adjust error messages in order to reflect the true problem... - if (signedDoc != null) { - signatureInfo = signedDoc.getValue().get(0); - // should not occur - } else { - - // store SAMLResponse - moaSession.setSAMLResponse(request.getParameter("SAMLResponse")); - // store authnResponse - - // moaSession.setAuthnResponse(authnResponse);//not serializable - moaSession.setAuthnResponseGetPersonalAttributeList(authnResponse.getPersonalAttributeList()); - - String authnContextClassRef = null; - try { - authnContextClassRef = authnResponse.getAssertions().get(0).getAuthnStatements().get(0) - .getAuthnContext().getAuthnContextClassRef().getAuthnContextClassRef(); - } catch (Throwable e) { - Logger.warn("STORK QAA-Level is not found in AuthnResponse. Set QAA Level to requested level"); - } - - moaSession.setAuthnContextClassRef(authnContextClassRef); - moaSession.setReturnURL(request.getRequestURL()); - - // load signedDoc - String signRequest = moaSession.getSignedDoc(); - - // session is implicit stored in changeSessionID!!!! - String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); - - // set return url to PEPSConnectorWithLocalSigningServlet and add newMOASessionID - // signRequest - - String issuerValue = AuthConfigurationProvider.getInstance().getPublicURLPrefix(); - String acsURL = issuerValue - + PEPSConnectorWithLocalSigningServlet.PEPSCONNECTOR_SERVLET_URL_PATTERN; - - String url = acsURL + "?moaSessionID=" + newMOASessionID; - // redirect to OASIS module and sign there - - boolean found = false; - try { - List aps = AuthConfigurationProvider.getInstance() - .getOnlineApplicationParameter(moaSession.getPublicOAURLPrefix()).getStorkAPs(); - Logger.info("Found AttributeProviderPlugins:" + aps.size()); - for (AttributeProviderPlugin ap : aps) { - Logger.info("Found AttributeProviderPlugin attribute:" + ap.getAttributes()); - if (ap.getAttributes().equalsIgnoreCase("signedDoc")) { - // FIXME: A servlet's class field is not thread safe!!! - oasisDssWebFormURL = ap.getUrl(); - found = true; - Logger.info("Loaded signedDoc attribute provider url from config:" + oasisDssWebFormURL); - break; - } - } - } catch (Exception e) { - e.printStackTrace(); - Logger.error("Loading the signedDoc attribute provider url from config failed"); - } - if (!found) { - Logger.error("Failed to load the signedDoc attribute provider url from config"); - } - performRedirect(url, request, response, signRequest); - - return; - } - - // FIXME: This servlet/task is intended to handle peps responses without signature, so why do we try to process that signature here? - SignResponse dssSignResponse = (SignResponse) ApiUtils.unmarshal(new StreamSource( - new java.io.StringReader(signatureInfo))); - - citizenSignature = getCitizienSignatureFromSignResponse(dssSignResponse); - - // memorize signature into authblock - moaSession.setAuthBlock(citizenSignature); - - X509Certificate cert = getSignerCertificate(citizenSignature); - moaSession.setSignerCertificate(cert); - moaSession.setForeigner(true); - - } catch (Throwable e) { - Logger.error("Could not extract citizen signature from C-PEPS", e); - throw new MOAIDException("stork.09", null); - } - - // FIXME: Same here; we do not have the citizen's signature, so this code might be regarded as dead code. - try { - SZRGInsertion(moaSession, authnResponse.getPersonalAttributeList(), authnResponse.getAssertions() - .get(0).getAuthnStatements().get(0).getAuthnContext().getAuthnContextClassRef() - .getAuthnContextClassRef(), citizenSignature); - } catch (STORKException e) { - // this is really nasty but we work against the system here. We are supposed to get the gender attribute - // from - // stork. If we do not, we cannot register the person in the ERnP - we have to have the - // gender for the represented person. So here comes the dirty hack. - if (e.getCause() instanceof STORKException - && e.getCause().getMessage().equals("gender not found in response")) { - try { - Logger.trace("Initialize VelocityEngine..."); - - VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); - Template template = velocityEngine.getTemplate("/resources/templates/fetchGender.html"); - VelocityContext context = new VelocityContext(); - context.put("SAMLResponse", request.getParameter("SAMLResponse")); - context.put("action", request.getRequestURL()); - - StringWriter writer = new StringWriter(); - template.merge(context, writer); - - response.getOutputStream().write(writer.toString().getBytes("UTF-8")); - } catch (Exception e1) { - Logger.error("Error sending gender retrival form.", e1); - // httpSession.invalidate(); - throw new MOAIDException("stork.10", null); - } - - return; - } - - Logger.error("Error connecting SZR Gateway", e); - throw new MOAIDException("stork.10", null); - } - - Logger.debug("Add full STORK AuthnResponse to MOA session"); - moaSession.setStorkAuthnResponse(request.getParameter("SAMLResponse"));// TODO ask Florian/Thomas - // authnResponse? - - // session is implicit stored in changeSessionID!!!! - String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); - - Logger.info("Changed MOASession " + moaSessionID + " to Session " + newMOASessionID); - - // redirect - String redirectURL = null; - redirectURL = new DataURLBuilder().buildDataURL(moaSession.getAuthURL(), - ModulUtils.buildAuthURL(moaSession.getModul(), moaSession.getAction(), pendingRequestID), - newMOASessionID); - redirectURL = response.encodeRedirectURL(redirectURL); - - response.setContentType("text/html"); - response.setStatus(302); - response.addHeader("Location", redirectURL); - Logger.info("REDIRECT TO: " + redirectURL); - - } catch (AuthenticationException e) { - handleError(null, e, request, response, pendingRequestID); - - } catch (MOAIDException e) { - handleError(null, e, request, response, pendingRequestID); - - } catch (Exception e) { - Logger.error("PEPSConnector has an interal Error.", e); - } - - finally { - ConfigurationDBUtils.closeSession(); - } - - } - - private void performRedirect(String url, HttpServletRequest req, HttpServletResponse resp, String signRequestString) - 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(); - - Logger.debug("performRedirect, signrequest:" + signRequestString); - Source signDoc = new StreamSource(new java.io.StringReader(signRequestString)); - SignRequest signRequest = ApiUtils.unmarshal(signDoc, SignRequest.class); - signRequest.setReturnURL("TODO"); - signRequestString = IOUtils.toString(ApiUtils.marshalToInputStream(signRequest)); - context.put("signrequest", Base64.encodeBase64String(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); - } - } -} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java deleted file mode 100644 index 3fb4fb0a9..000000000 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java +++ /dev/null @@ -1,566 +0,0 @@ -package at.gv.egovernment.moa.id.auth.modules.stork.tasks; - -import iaik.x509.X509Certificate; - -import java.io.IOException; -import java.io.InputStream; -import java.io.StringWriter; -import java.net.URL; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Properties; - -import javax.activation.DataSource; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBElement; -import javax.xml.namespace.QName; -import javax.xml.transform.stream.StreamSource; -import javax.xml.ws.BindingProvider; -import javax.xml.ws.Service; -import javax.xml.ws.soap.SOAPBinding; - -import org.apache.commons.io.IOUtils; -import org.apache.commons.lang.StringEscapeUtils; -import org.apache.velocity.Template; -import org.apache.velocity.VelocityContext; -import org.apache.velocity.app.VelocityEngine; -import org.opensaml.saml2.core.StatusCode; - -import at.gv.egovernment.moa.id.auth.AuthenticationServer; -import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; -import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; -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.MOAIDException; -import at.gv.egovernment.moa.id.auth.modules.internal.tasks.AbstractAuthServletTask; -import at.gv.egovernment.moa.id.auth.stork.STORKException; -import at.gv.egovernment.moa.id.auth.stork.STORKResponseProcessor; -import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; -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.ModulUtils; -import at.gv.egovernment.moa.id.process.api.ExecutionContext; -import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; -import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; -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 at.gv.util.xsd.xmldsig.SignatureType; -import at.gv.util.xsd.xmldsig.X509DataType; -import eu.stork.documentservice.DocumentService; -import eu.stork.documentservice.data.DatabaseConnectorMySQLImpl; -import eu.stork.oasisdss.api.ApiUtils; -import eu.stork.oasisdss.api.LightweightSourceResolver; -import eu.stork.oasisdss.api.exceptions.ApiUtilsException; -import eu.stork.oasisdss.profile.DocumentType; -import eu.stork.oasisdss.profile.DocumentWithSignature; -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.commons.STORKAuthnRequest; -import eu.stork.peps.auth.commons.STORKAuthnResponse; -import eu.stork.peps.auth.engine.STORKSAMLEngine; -import eu.stork.peps.exceptions.STORKSAMLEngineException; - -/** - * Evaluates the SAML response from the C-PEPS and authenticates the user. - *

- * In detail: - *

    - *
  • Decodes and validates the SAML response from the C-PEPS.
  • - *
  • Change moa session id.
  • - *
  • Extracts the subject's gender from request parameter {@code gender} if not available from the saml response.
  • - *
  • Extracts the {@code signedDoc} attribute from the response, get signed doc payload using stork attribute query request.
  • - *
  • Request SZR gateway for verification of the citizen's signature and for creating of an identity link.
  • - *
  • In case of mandate mode: If the S-PEPS did not provide any gender information, the szr gateway will not be able to issue an identity link. Therefore a form is presented asking for the subject's gender. The form submits the user back to the {@code /PepsConnector} servlet (this task).
  • - *
  • The moa session is updated with authentication information.
  • - *
  • Change moa session id.
  • - *
  • Redirects back to {@code /dispatcher} in order to finalize the authentication.
  • - *
- * Expects: - *
    - *
  • HttpServletRequest parameter {@code SAMLResponse}
  • - *
  • Either HttpServletRequest parameter {@code RelayState} or {@code inResponseTo} attribute from the SAML response (both depicting the moa session id)
  • - *
  • HttpServletRequest parameter {@code gender} in case the request comes from the gender selection form
  • - *
  • {@code signedDoc} attribute within the SAML response.
  • - *
- * Result: - *
    - *
  • Updated moa id session (identity link, stork attributes...)
  • - *
  • {@link ExecutionContext} contains boolean flag {@code identityLinkAvailable} indicating if an identitylink has been successfully creates or not.
  • - *
  • Redirect to {@code /dispatcher}.
  • - *
- * Possible branches: - *
    - *
  • In case the szr gateway throws exception due to missing gender information: - *
      - *
    • Returns a form for gender selection with action url back to this servlet/task.
    • - *
    - *
  • - *
- * Code taken from {@link at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorServlet}.
- * - * @see #execute(ExecutionContext, HttpServletRequest, HttpServletResponse) - */ -public class PepsConnectorTask extends AbstractAuthServletTask { - - private String dtlUrl = null; - - public PepsConnectorTask() { - super(); - 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(); - } - } - - @Override - public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) - throws Exception { - String pendingRequestID = null; - - setNoCachingHeaders(response); - - try { - - Logger.info("PEPSConnector Servlet invoked, expecting C-PEPS message."); - Logger.debug("This ACS endpoint is: " + HTTPUtils.getBaseURL(request)); - - // check if https or only http - super.checkIfHTTPisAllowed(request.getRequestURL().toString()); - - Logger.debug("Beginning to extract SAMLResponse out of HTTP Request"); - - // extract STORK Response from HTTP Request - // Decodes SAML Response - byte[] decSamlToken; - try { - decSamlToken = PEPSUtil.decodeSAMLToken(request.getParameter("SAMLResponse")); - Logger.debug("SAMLResponse: " + new String(decSamlToken)); - - } catch (NullPointerException e) { - Logger.error("Unable to retrieve STORK Response", e); - throw new MOAIDException("stork.04", null); - } - - // Get SAMLEngine instance - STORKSAMLEngine engine = STORKSAMLEngine.getInstance("outgoing"); - - STORKAuthnResponse authnResponse = null; - try { - // validate SAML Token - Logger.debug("Starting validation of SAML response"); - authnResponse = engine.validateSTORKAuthnResponse(decSamlToken, (String) request.getRemoteHost()); - Logger.info("SAML response succesfully verified!"); - } catch (STORKSAMLEngineException e) { - Logger.error("Failed to verify STORK SAML Response", e); - throw new MOAIDException("stork.05", null); - } - - Logger.info("STORK SAML Response message succesfully extracted"); - Logger.debug("STORK response: "); - Logger.debug(authnResponse.toString()); - - Logger.debug("Trying to find MOA Session-ID ..."); - // String moaSessionID = request.getParameter(PARAM_SESSIONID); - // first use SAML2 relayState - String moaSessionID = request.getParameter("RelayState"); - - // escape parameter strings - moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID); - - // check if SAML2 relaystate includes a MOA sessionID - if (StringUtils.isEmpty(moaSessionID)) { - // if relaystate is emtpty, use SAML response -> inResponseTo element as session identifier - - moaSessionID = authnResponse.getInResponseTo(); - moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID); - - if (StringUtils.isEmpty(moaSessionID)) { - // No authentication session has been started before - Logger.error("MOA-SessionID was not found, no previous AuthnRequest had been started"); - Logger.debug("PEPSConnectorURL was: " + request.getRequestURL()); - throw new AuthenticationException("auth.02", new Object[] { moaSessionID }); - - } else - Logger.trace("Use MOA SessionID " + moaSessionID + " from AuthnResponse->inResponseTo attribute."); - - } else - // Logger.trace("MOA SessionID " + moaSessionID + " is found in http GET parameter."); - Logger.trace("MOA SessionID " + moaSessionID + " is found in SAML2 relayState."); - - /* - * INFO!!!! SAML message IDs has an different format then MOASessionIDs This is only a workaround because - * many PEPS does not support SAML2 relayState or MOASessionID as AttributConsumerServiceURL GET parameter - */ - // if (!ParamValidatorUtils.isValidSessionID(moaSessionID)) - // throw new WrongParametersException("VerifyAuthenticationBlock", PARAM_SESSIONID, "auth.12"); - - pendingRequestID = AuthenticationSessionStoreage.getPendingRequestID(moaSessionID); - - // load MOASession from database - AuthenticationSession moaSession = AuthenticationServer.getSession(moaSessionID); - // change MOASessionID - moaSessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); - - Logger.info("Found MOA sessionID: " + moaSessionID); - - String statusCodeValue = authnResponse.getStatusCode(); - - if (!statusCodeValue.equals(StatusCode.SUCCESS_URI)) { - Logger.error("Received ErrorResponse from PEPS: " + statusCodeValue); - throw new MOAIDException("stork.06", new Object[] { statusCodeValue }); - } - - Logger.info("Got SAML response with authentication success message."); - - Logger.debug("MOA session is still valid"); - - STORKAuthnRequest storkAuthnRequest = moaSession.getStorkAuthnRequest(); - - if (storkAuthnRequest == null) { - Logger.error("Could not find any preceeding STORK AuthnRequest to this MOA session: " + moaSessionID); - throw new MOAIDException("stork.07", null); - } - - Logger.debug("Found a preceeding STORK AuthnRequest to this MOA session: " + moaSessionID); - - // //////////// incorporate gender from parameters if not in stork response - - IPersonalAttributeList attributeList = authnResponse.getPersonalAttributeList(); - - // but first, check if we have a representation case - if (STORKResponseProcessor.hasAttribute("mandateContent", attributeList) - || STORKResponseProcessor.hasAttribute("representative", attributeList) - || STORKResponseProcessor.hasAttribute("represented", attributeList)) { - // in a representation case... - moaSession.setUseMandate("true"); - - // and check if we have the gender value - PersonalAttribute gender = attributeList.get("gender"); // TODO Do we need to check gender value if - // there is no representation case? - if (null == gender) { - String gendervalue = (String) request.getParameter("gender"); - if (null != gendervalue) { - gender = new PersonalAttribute(); - gender.setName("gender"); - ArrayList tmp = new ArrayList(); - tmp.add(gendervalue); - gender.setValue(tmp); - - authnResponse.getPersonalAttributeList().add(gender); - } - } - } - - // //////////////////////////////////////////////////////////////////////// - - Logger.debug("Starting extraction of signedDoc attribute"); - // extract signed doc element and citizen signature - String citizenSignature = null; - try { - String signatureInfo = authnResponse.getPersonalAttributeList().get("signedDoc").getValue().get(0); // TODO ERROR HANDLING - - Logger.debug("signatureInfo:" + signatureInfo); - - SignResponse dssSignResponse = (SignResponse) ApiUtils.unmarshal(new StreamSource( - new java.io.StringReader(signatureInfo))); - - // fetch signed doc - DataSource ds = LightweightSourceResolver.getDataSource(dssSignResponse); - if (ds == null) { - throw new ApiUtilsException("No datasource found in response"); - } - - InputStream incoming = ds.getInputStream(); - citizenSignature = IOUtils.toString(incoming); - incoming.close(); - - Logger.debug("citizenSignature:" + citizenSignature); - if (isDocumentServiceUsed(citizenSignature) == true) { - Logger.debug("Loading document from DocumentService."); - String url = getDtlUrlFromResponse(dssSignResponse); - // get Transferrequest - String transferRequest = getDocTransferRequest(dssSignResponse.getDocUI(), url); - // Load document from DocujmentService - byte[] data = getDocumentFromDtl(transferRequest, url); - citizenSignature = new String(data, "UTF-8"); - Logger.debug("Overridung citizenSignature with:" + citizenSignature); - } - - JAXBContext ctx = JAXBContext.newInstance(SignatureType.class.getPackage().getName()); - SignatureType root = ((JAXBElement) ctx.createUnmarshaller().unmarshal( - IOUtils.toInputStream(citizenSignature))).getValue(); - - // memorize signature into authblock - moaSession.setAuthBlock(citizenSignature); - - // extract certificate - for (Object current : root.getKeyInfo().getContent()) - if (((JAXBElement) current).getValue() instanceof X509DataType) { - for (Object currentX509Data : ((JAXBElement) current).getValue() - .getX509IssuerSerialOrX509SKIOrX509SubjectName()) { - JAXBElement casted = ((JAXBElement) currentX509Data); - if (casted.getName().getLocalPart().equals("X509Certificate")) { - moaSession.setSignerCertificate(new X509Certificate(((String) casted.getValue()) - .getBytes("UTF-8"))); - break; - } - } - } - - } catch (Throwable e) { - Logger.error("Could not extract citizen signature from C-PEPS", e); - throw new MOAIDException("stork.09", null); - } - Logger.debug("Foregin Citizen signature successfully extracted from STORK Assertion (signedDoc)"); - Logger.debug("Citizen signature will be verified by SZR Gateway!"); - - Logger.debug("fetching OAParameters from database"); - - // //read configuration paramters of OA - // AuthenticationSession moasession; - // try { - // moasession = AuthenticationSessionStoreage.getSession(moaSessionID); - // } catch (MOADatabaseException e2) { - // Logger.error("could not retrieve moa session"); - // throw new AuthenticationException("auth.01", null); - // } - OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter( - moaSession.getPublicOAURLPrefix()); - if (oaParam == null) - throw new AuthenticationException("auth.00", new Object[] { moaSession.getPublicOAURLPrefix() }); - - // retrieve target - // TODO: check in case of SSO!!! - String targetType = null; - if (oaParam.getBusinessService()) { - String id = oaParam.getIdentityLinkDomainIdentifier(); - if (id.startsWith(AuthenticationSession.REGISTERANDORDNR_PREFIX_)) - targetType = id; - else - targetType = AuthenticationSession.REGISTERANDORDNR_PREFIX_ + moaSession.getDomainIdentifier(); - } else { - targetType = AuthenticationSession.TARGET_PREFIX_ + oaParam.getTarget(); - } - - Logger.debug("Starting connecting SZR Gateway"); - // contact SZR Gateway - IdentityLink identityLink = null; - executionContext.put("identityLinkAvailable", false); - try { - identityLink = STORKResponseProcessor.connectToSZRGateway(authnResponse.getPersonalAttributeList(), - oaParam.getFriendlyName(), targetType, null, oaParam.getMandateProfiles(), citizenSignature); - } catch (STORKException e) { - // this is really nasty but we work against the system here. We are supposed to get the gender attribute - // from - // stork. If we do not, we cannot register the person in the ERnP - we have to have the - // gender for the represented person. So here comes the dirty hack. - if (e.getCause() instanceof STORKException - && e.getCause().getMessage().equals("gender not found in response")) { - try { - Logger.trace("Initialize VelocityEngine..."); - - VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); - Template template = velocityEngine.getTemplate("/resources/templates/fetchGender.html"); - VelocityContext context = new VelocityContext(); - context.put("SAMLResponse", request.getParameter("SAMLResponse")); - context.put("action", request.getRequestURL()); - - StringWriter writer = new StringWriter(); - template.merge(context, writer); - - response.getOutputStream().write(writer.toString().getBytes("UTF-8")); - } catch (Exception e1) { - Logger.error("Error sending gender retrival form.", e1); - // httpSession.invalidate(); - throw new MOAIDException("stork.10", null); - } - - return; - } - - Logger.error("Error connecting SZR Gateway", e); - throw new MOAIDException("stork.10", null); - } - Logger.debug("SZR communication was successfull"); - - if (identityLink == null) { - Logger.error("SZR Gateway did not return an identity link."); - throw new MOAIDException("stork.10", null); - } - moaSession.setForeigner(true); - - Logger.info("Received Identity Link from SZR Gateway"); - executionContext.put("identityLinkAvailable", true); - moaSession.setIdentityLink(identityLink); - - Logger.debug("Adding addtional STORK attributes to MOA session"); - moaSession.setStorkAttributes(authnResponse.getPersonalAttributeList()); - - Logger.debug("Add full STORK AuthnResponse to MOA session"); - moaSession.setStorkAuthnResponse(request.getParameter("SAMLResponse")); - - // We don't have BKUURL, setting from null to "Not applicable" - moaSession.setBkuURL("Not applicable (STORK Authentication)"); - - // free for single use - moaSession.setAuthenticatedUsed(false); - - // stork did the authentication step - moaSession.setAuthenticated(true); - - // TODO: found better solution, but QAA Level in response could be not supported yet - try { - - moaSession.setQAALevel(authnResponse.getAssertions().get(0).getAuthnStatements().get(0) - .getAuthnContext().getAuthnContextClassRef().getAuthnContextClassRef()); - - } catch (Throwable e) { - Logger.warn("STORK QAA-Level is not found in AuthnResponse. Set QAA Level to requested level"); - moaSession.setQAALevel(PVPConstants.STORK_QAA_PREFIX + oaParam.getQaaLevel()); - - } - - // session is implicit stored in changeSessionID!!!! - String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); - - Logger.info("Changed MOASession " + moaSessionID + " to Session " + newMOASessionID); - - // redirect - String redirectURL = null; - redirectURL = new DataURLBuilder().buildDataURL(moaSession.getAuthURL(), - ModulUtils.buildAuthURL(moaSession.getModul(), moaSession.getAction(), pendingRequestID), - newMOASessionID); - redirectURL = response.encodeRedirectURL(redirectURL); - - // response.setContentType("text/html"); - // response.setStatus(302); - // response.addHeader("Location", redirectURL); - response.sendRedirect(redirectURL); - Logger.info("REDIRECT TO: " + redirectURL); - - } catch (AuthenticationException e) { - handleError(null, e, request, response, pendingRequestID); - - } catch (MOAIDException e) { - handleError(null, e, request, response, pendingRequestID); - - } catch (Exception e) { - Logger.error("PEPSConnector has an interal Error.", e); - } - - finally { - ConfigurationDBUtils.closeSession(); - } - - } - - private boolean isDocumentServiceUsed(String citizenSignature) // TODo add better check - { - if (citizenSignature - .contains("
Service Name:{http://stork.eu}DocumentService
Port Name:{http://stork.eu}DocumentServicePort
")) - return true; - return false; - } - - /** - * Get DTL uril from the oasis sign response - * - * @param signRequest - * The signature response - * @return The URL of DTL service - * @throws SimpleException - */ - private String getDtlUrlFromResponse(SignResponse dssSignResponse) { - List documents = ApiUtils.findNamedElement(dssSignResponse.getOptionalOutputs(), - ApiUtils.OPTIONAL_OUTPUT_DOCUMENTWITHSIGNATURE, DocumentWithSignature.class); - DocumentType sourceDocument = documents.get(0).getDocument(); - - if (sourceDocument.getDocumentURL() != null) - return sourceDocument.getDocumentURL(); - else - return null;// throw new Exception("No document url found"); - } - - // From DTLPEPSUTIL - - /** - * 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 { - 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); - } - } - -} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GenerateIFrameTemplateServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GenerateIFrameTemplateServlet.java index d6c15c658..bc8a01e41 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GenerateIFrameTemplateServlet.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/auth/servlet/GenerateIFrameTemplateServlet.java @@ -35,13 +35,13 @@ 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.auth.exception.WrongParametersException; +import at.gv.egovernment.moa.id.auth.modules.registration.ModuleRegistration; import at.gv.egovernment.moa.id.auth.parser.StartAuthentificationParameterParser; import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; import at.gv.egovernment.moa.id.commons.db.dao.config.TemplateType; 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.moduleregistration.ModuleRegistration; import at.gv.egovernment.moa.id.process.ExecutionContextImpl; import at.gv.egovernment.moa.id.process.ProcessInstance; import at.gv.egovernment.moa.id.process.api.ExecutionContext; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java index 0a7f71713..b239fbb1d 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/AuthenticationManager.java @@ -68,6 +68,7 @@ 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.BuildException; import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.auth.modules.registration.ModuleRegistration; import at.gv.egovernment.moa.id.auth.parser.StartAuthentificationParameterParser; import at.gv.egovernment.moa.id.commons.db.dao.session.InterfederationSessionStore; import at.gv.egovernment.moa.id.commons.db.dao.session.OASessionStore; @@ -76,7 +77,6 @@ import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; import at.gv.egovernment.moa.id.data.SLOInformationContainer; import at.gv.egovernment.moa.id.data.SLOInformationImpl; -import at.gv.egovernment.moa.id.moduls.moduleregistration.ModuleRegistration; import at.gv.egovernment.moa.id.process.ExecutionContextImpl; import at.gv.egovernment.moa.id.process.ProcessEngine; import at.gv.egovernment.moa.id.process.ProcessExecutionException; diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/AuthModule.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/AuthModule.java deleted file mode 100644 index 295a51a24..000000000 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/AuthModule.java +++ /dev/null @@ -1,41 +0,0 @@ -package at.gv.egovernment.moa.id.moduls.moduleregistration; - -import at.gv.egovernment.moa.id.process.api.ExecutionContext; -import at.gv.egovernment.moa.id.process.model.ProcessDefinition; - -/** - * Defines the module capabilities. - */ -public interface AuthModule { - - /** - * Returns the priority of the module. The priority defines the order of the respective module within the chain of - * discovered modules. Higher priorized modules are asked before lower priorized modules for a process that they can - * handle. - *

- * Internal default modules are priorized neutral ({@code 0}. Use a higher priority ({@code 1...Integer.MAX_VALUE}) - * in order to have your module(s) priorized or a lower priority ({@code Integer.MIN_VALUE...-1}) in order to put - * your modules behind default modules. - * - * @return the priority of the module. - */ - int getPriority(); - - /** - * Checks if the module has a process, which is able to perform an authentication with the given - * {@link ExecutionContext}. - * - * @param context - * an ExecutionContext for a process. - * @return the process-ID of a process which is able to work with the given ExecutionContext, or {@code null}. - */ - String selectProcess(ExecutionContext context); - - /** - * Returns the an Array of {@link ProcessDefinition}s of the processes included in this module. - * - * @return an array of resource uris of the processes included in this module. - */ - String[] getProcessDefinitions(); - -} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/ModuleRegistration.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/ModuleRegistration.java deleted file mode 100644 index 9e06a9ec8..000000000 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/moduls/moduleregistration/ModuleRegistration.java +++ /dev/null @@ -1,149 +0,0 @@ -package at.gv.egovernment.moa.id.moduls.moduleregistration; - -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.ServiceLoader; - -import javax.annotation.PostConstruct; - -import org.apache.commons.lang3.StringUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.core.io.Resource; - -import at.gv.egovernment.moa.id.process.ProcessDefinitionParserException; -import at.gv.egovernment.moa.id.process.ProcessEngine; -import at.gv.egovernment.moa.id.process.api.ExecutionContext; - -/** - * This class handles registering modules. The modules are detected either with - * the ServiceLoader mechanism or via Spring. All detected modules are ranked - * according to their priority. - */ -public class ModuleRegistration { - - private static ModuleRegistration instance = new ModuleRegistration(); - - private List priorizedModules = new ArrayList<>(); - - @Autowired - private ApplicationContext ctx; - - @Autowired - private ProcessEngine processEngine; - - private Logger log = LoggerFactory.getLogger(getClass()); - - public static ModuleRegistration getInstance() { - return instance; - } - - private ModuleRegistration() { - } - - @PostConstruct - private void init() { - // load modules via the ServiceLoader - initServiceLoaderModules(); - - // load modules via Spring - initSpringModules(); - - // order modules according to their priority - priorizeModules(); - } - - /** - * Discovers modules which use the ServiceLoader mechanism. - */ - private void initServiceLoaderModules() { - log.info("Looking for auth modules."); - ServiceLoader loader = ServiceLoader.load(AuthModule.class); - Iterator modules = loader.iterator(); - while (modules.hasNext()) { - AuthModule module = modules.next(); - log.info("Detected module {}", module.getClass().getName()); - registerResourceUris(module); - priorizedModules.add(module); - } - } - - /** - * Discovers modules which use Spring. - */ - private void initSpringModules() { - log.debug("Discovering Spring modules."); - Map modules = ctx.getBeansOfType(AuthModule.class); - for (AuthModule module : modules.values()) { - registerResourceUris(module); - priorizedModules.add(module); - } - } - - /** - * Registers the resource uris for the module. - * - * @param module - * the module. - */ - private void registerResourceUris(AuthModule module) { - for (String uri : module.getProcessDefinitions()) { - Resource resource = ctx.getResource(uri); - if (resource.isReadable()) { - log.info("Registering process definition resource: '{}'.", uri); - try (InputStream processDefinitionInputStream = resource.getInputStream()) { - processEngine.registerProcessDefinition(processDefinitionInputStream); - } catch (IOException e) { - log.error("Resource uri: '{}' could NOT be read.", uri, e); - } catch (ProcessDefinitionParserException e) { - log.error("Error while parsing process definition in '{}'", uri, e); - } - } else { - log.error("Resource uri: '{}' cannot be read.", uri); - } - } - } - - /** - * Order the modules in descending order according to their priority. - */ - private void priorizeModules() { - Collections.sort(priorizedModules, new Comparator() { - @Override - public int compare(AuthModule thisAuthModule, AuthModule otherAuthModule) { - int thisOrder = thisAuthModule.getPriority(); - int otherOrder = otherAuthModule.getPriority(); - return (thisOrder < otherOrder ? -1 : (thisOrder == otherOrder ? 0 : 1)); - } - }); - log.debug("Modules are ordered in descending order, according to their priority."); - } - - /** - * Returns the process id of the first process, in the highest ranked - * module, which is able to work with the given execution context. - * - * @param context - * the {@link ExecutionContext}. - * @return the process id or {@code null} - */ - public String selectProcess(ExecutionContext context) { - for (AuthModule module : priorizedModules) { - String id = module.selectProcess(context); - if (StringUtils.isNotEmpty(id)) { - log.debug("Process with id '{}' selected, for context '{}'.", id, context); - return id; - } - } - log.info("No process is able to handle context '{}'.", context); - return null; - } -} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngine.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngine.java index 2f1487564..ff6ec969e 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngine.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngine.java @@ -27,8 +27,9 @@ public interface ProcessEngine { * * @param processDefinitionInputStream The input stream to the definition to be registered. * @throws ProcessDefinitionParserException Thrown in case of an error parsing the process definition. + * @return The process definition's identifier. */ - void registerProcessDefinition(InputStream processDefinitionInputStream) throws ProcessDefinitionParserException; + String registerProcessDefinition(InputStream processDefinitionInputStream) throws ProcessDefinitionParserException; /** * Creates a process instance according to the referenced process definition, persists it into the database and returns it identifier. diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngineImpl.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngineImpl.java index ea5a2684e..eb6a29ad9 100644 --- a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngineImpl.java +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/process/ProcessEngineImpl.java @@ -55,8 +55,10 @@ public class ProcessEngineImpl implements ProcessEngine { } @Override - public void registerProcessDefinition(InputStream processDefinitionInputStream) throws ProcessDefinitionParserException{ - registerProcessDefinition(pdp.parse(processDefinitionInputStream)); + public String registerProcessDefinition(InputStream processDefinitionInputStream) throws ProcessDefinitionParserException{ + ProcessDefinition pd = pdp.parse(processDefinitionInputStream); + registerProcessDefinition(pd); + return pd.getId(); } /** diff --git a/id/server/idserverlib/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.auth.modules.AuthModule b/id/server/idserverlib/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.auth.modules.AuthModule new file mode 100644 index 000000000..865096055 --- /dev/null +++ b/id/server/idserverlib/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.auth.modules.AuthModule @@ -0,0 +1,2 @@ +# The default moaid process +at.gv.egovernment.moa.id.auth.modules.internal.DefaultAuthModuleImpl diff --git a/id/server/idserverlib/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.moduleregistration.AuthModule b/id/server/idserverlib/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.moduleregistration.AuthModule deleted file mode 100644 index 865096055..000000000 --- a/id/server/idserverlib/src/main/resources/META-INF/services/at.gv.egovernment.moa.id.moduls.moduleregistration.AuthModule +++ /dev/null @@ -1,2 +0,0 @@ -# The default moaid process -at.gv.egovernment.moa.id.auth.modules.internal.DefaultAuthModuleImpl diff --git a/id/server/idserverlib/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORK.authmodule.beans.xml b/id/server/idserverlib/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORK.authmodule.beans.xml deleted file mode 100644 index 2e924bdd0..000000000 --- a/id/server/idserverlib/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORK.authmodule.beans.xml +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - diff --git a/id/server/idserverlib/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthentication.process.xml b/id/server/idserverlib/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthentication.process.xml deleted file mode 100644 index 60989e638..000000000 --- a/id/server/idserverlib/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthentication.process.xml +++ /dev/null @@ -1,29 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/id/server/modules/module-stork/pom.xml b/id/server/modules/module-stork/pom.xml new file mode 100644 index 000000000..8761e17ee --- /dev/null +++ b/id/server/modules/module-stork/pom.xml @@ -0,0 +1,22 @@ + + 4.0.0 + + + MOA.id.server.modules + moa-id-modules + ${moa-id-version} + + + MOA.id.server.modules + moa-id-module-stork + ${moa-id-version} + jar + + MOA ID-Module STORK + + + ${basedir}/../../../../repository + + + diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java new file mode 100644 index 000000000..41384690e --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthModuleImpl.java @@ -0,0 +1,39 @@ +package at.gv.egovernment.moa.id.auth.modules.stork; + +import org.apache.commons.lang3.StringUtils; + +import at.gv.egovernment.moa.id.auth.modules.AuthModule; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; + +/** + * Module descriptor for an auth module providing stork authentication related processes. + * @author tknall + */ +public class STORKAuthModuleImpl implements AuthModule { + + private int priority = 0; + + @Override + public int getPriority() { + return priority; + } + + /** + * Sets the priority of this module. Default value is {@code 0}. + * @param priority The priority. + */ + public void setPriority(int priority) { + this.priority = priority; + } + + @Override + public String selectProcess(ExecutionContext context) { + return StringUtils.isNotBlank((String) context.get("ccc")) ? "STORKAuthentication" : null; + } + + @Override + public String[] getProcessDefinitions() { + return new String[] { "classpath:at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthentication.process.xml" }; + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java new file mode 100644 index 000000000..7478a57c3 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/STORKWebApplicationInitializer.java @@ -0,0 +1,37 @@ +package at.gv.egovernment.moa.id.auth.modules.stork; + +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; + +import org.springframework.web.WebApplicationInitializer; + +import at.gv.egovernment.moa.id.auth.servlet.ProcessEngineSignalServlet; + +/** + * Spring automatically discovers {@link WebApplicationInitializer} implementations at startup.
+ * This STORK webapp initializer adds the required servlet mappings: + *

    + *
  • {@code /PEPSConnector}
  • + *
  • {@code /PEPSConnectorWithLocalSigning}
  • + *
+ * for the {@linkplain ProcessEngineSignalServlet process engine servlet} (named {@code ProcessEngineSignal}) that wakes + * up a process in order to execute asynchronous tasks. Therefore the servlet mappings mentioned above do not need to be + * declared in {@code web.xml}. + * + * @author tknall + * @see ProcessEngineSignalServlet + */ +public class STORKWebApplicationInitializer implements WebApplicationInitializer { + + @Override + public void onStartup(ServletContext servletContext) throws ServletException { + ServletRegistration servletRegistration = servletContext.getServletRegistration("ProcessEngineSignal"); + if (servletRegistration == null) { + throw new IllegalStateException("Servlet 'ProcessEngineSignal' expected to be registered."); + } + servletRegistration.addMapping("/PEPSConnectorWithLocalSigning"); + servletRegistration.addMapping("/PEPSConnector"); + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java new file mode 100644 index 000000000..702e62fa0 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/AbstractPepsConnectorWithLocalSigningTask.java @@ -0,0 +1,223 @@ +package at.gv.egovernment.moa.id.auth.modules.stork.tasks; + +import iaik.x509.X509Certificate; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.security.cert.CertificateException; +import java.util.HashMap; + +import javax.activation.DataSource; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.JAXBException; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactoryConfigurationError; + +import org.apache.commons.io.IOUtils; +import org.xml.sax.SAXException; + +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +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.BKUException; +import at.gv.egovernment.moa.id.auth.exception.BuildException; +import at.gv.egovernment.moa.id.auth.exception.MOAIDException; +import at.gv.egovernment.moa.id.auth.exception.ParseException; +import at.gv.egovernment.moa.id.auth.exception.ServiceException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; +import at.gv.egovernment.moa.id.auth.stork.STORKException; +import at.gv.egovernment.moa.id.auth.stork.STORKResponseProcessor; +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.id.config.auth.OAAuthParameter; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.spss.MOAException; +import at.gv.egovernment.moa.spss.api.SPSSFactory; +import at.gv.egovernment.moa.spss.api.SignatureVerificationService; +import at.gv.egovernment.moa.spss.api.common.Content; +import at.gv.egovernment.moa.spss.api.xmlverify.VerifySignatureInfo; +import at.gv.egovernment.moa.spss.api.xmlverify.VerifySignatureLocation; +import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureRequest; +import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureResponse; +import at.gv.util.xsd.xmldsig.SignatureType; +import at.gv.util.xsd.xmldsig.X509DataType; +import eu.stork.oasisdss.api.LightweightSourceResolver; +import eu.stork.oasisdss.api.exceptions.ApiUtilsException; +import eu.stork.oasisdss.api.exceptions.UtilsException; +import eu.stork.oasisdss.profile.SignResponse; +import eu.stork.peps.auth.commons.IPersonalAttributeList; + +public abstract class AbstractPepsConnectorWithLocalSigningTask extends AbstractAuthServletTask { + + String getCitizienSignatureFromSignResponse(SignResponse dssSignResponse) throws IllegalArgumentException, + TransformerConfigurationException, UtilsException, TransformerException, + TransformerFactoryConfigurationError, IOException, ApiUtilsException { + // fetch signed doc + DataSource ds = LightweightSourceResolver.getDataSource(dssSignResponse); + if (ds == null) { + throw new ApiUtilsException("No datasource found in response"); + } + + InputStream incoming = ds.getInputStream(); + String citizenSignature = IOUtils.toString(incoming); + incoming.close(); + + return citizenSignature; + } + + void SZRGInsertion(AuthenticationSession moaSession, IPersonalAttributeList personalAttributeList, + String authnContextClassRef, String citizenSignature) throws STORKException, MOAIDException { + Logger.debug("Foregin Citizen signature successfully extracted from STORK Assertion (signedDoc)"); + Logger.debug("Citizen signature will be verified by SZR Gateway!"); + + Logger.debug("fetching OAParameters from database"); + + OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter( + moaSession.getPublicOAURLPrefix()); + if (oaParam == null) + throw new AuthenticationException("auth.00", new Object[] { moaSession.getPublicOAURLPrefix() }); + + // retrieve target + // TODO: check in case of SSO!!! + String targetType = null; + if (oaParam.getBusinessService()) { + String id = oaParam.getIdentityLinkDomainIdentifier(); + if (id.startsWith(AuthenticationSession.REGISTERANDORDNR_PREFIX_)) + targetType = id; + else + targetType = AuthenticationSession.REGISTERANDORDNR_PREFIX_ + moaSession.getDomainIdentifier(); + } else { + targetType = AuthenticationSession.TARGET_PREFIX_ + oaParam.getTarget(); + } + + Logger.debug("Starting connecting SZR Gateway"); + // contact SZR Gateway + IdentityLink identityLink = null; + + identityLink = STORKResponseProcessor.connectToSZRGateway(personalAttributeList, oaParam.getFriendlyName(), + targetType, null, oaParam.getMandateProfiles(), citizenSignature); + Logger.debug("SZR communication was successfull"); + + if (identityLink == null) { + Logger.error("SZR Gateway did not return an identity link."); + throw new MOAIDException("stork.10", null); + } + Logger.info("Received Identity Link from SZR Gateway"); + moaSession.setIdentityLink(identityLink); + + Logger.debug("Adding addtional STORK attributes to MOA session"); + moaSession.setStorkAttributes(personalAttributeList); + + // We don't have BKUURL, setting from null to "Not applicable" + moaSession.setBkuURL("Not applicable (STORK Authentication)"); + + // free for single use + moaSession.setAuthenticatedUsed(false); + + // stork did the authentication step + moaSession.setAuthenticated(true); + + // TODO: found better solution, but QAA Level in response could be not supported yet + try { + if (authnContextClassRef == null) + authnContextClassRef = PVPConstants.STORK_QAA_PREFIX + oaParam.getQaaLevel(); + moaSession.setQAALevel(authnContextClassRef); + + } catch (Throwable e) { + Logger.warn("STORK QAA-Level is not found in AuthnResponse. Set QAA Level to requested level"); + moaSession.setQAALevel(PVPConstants.STORK_QAA_PREFIX + oaParam.getQaaLevel()); + + } + + } + + X509Certificate getSignerCertificate(String citizenSignature) throws CertificateException, JAXBException, + UnsupportedEncodingException { + JAXBContext ctx = JAXBContext.newInstance(SignatureType.class.getPackage().getName()); + SignatureType root = ((JAXBElement) ctx.createUnmarshaller().unmarshal( + IOUtils.toInputStream(citizenSignature))).getValue(); + + // extract certificate + for (Object current : root.getKeyInfo().getContent()) + if (((JAXBElement) current).getValue() instanceof X509DataType) { + for (Object currentX509Data : ((JAXBElement) current).getValue() + .getX509IssuerSerialOrX509SKIOrX509SubjectName()) { + JAXBElement casted = ((JAXBElement) currentX509Data); + if (casted.getName().getLocalPart().equals("X509Certificate")) { + return new X509Certificate(((String) casted.getValue()).getBytes("UTF-8")); + } + } + } + return null; + } + + VerifyXMLSignatureResponse verifyXMLSignature(String signature) throws AuthenticationException, ParseException, + BKUException, BuildException, ConfigurationException, ServiceException, UnsupportedEncodingException, + SAXException, IOException, ParserConfigurationException, MOAException { + // Based on MOA demo client + // Factory und Service instanzieren + SPSSFactory spssFac = SPSSFactory.getInstance(); + SignatureVerificationService sigVerifyService = SignatureVerificationService.getInstance(); + + Content sigDocContent1 = spssFac.createContent(IOUtils.toInputStream(signature, "UTF-8"), null); + + // Position der zu prüfenden Signatur im Dokument angeben + // (Nachdem im XPath-Ausdruck ein NS-Präfix verwendet wird, muss in einer Lookup-Tabelle + // der damit bezeichnete Namenraum mitgegeben werden) + HashMap nSMap = new HashMap(); + nSMap.put("dsig", "http://www.w3.org/2000/09/xmldsig#"); + VerifySignatureLocation sigLocation = spssFac.createVerifySignatureLocation("//dsig:Signature", nSMap); + + // Zu prüfendes Dokument und Signaturposition zusammenfassen + + VerifySignatureInfo sigInfo = spssFac.createVerifySignatureInfo(sigDocContent1, sigLocation); + + // Prüfrequest zusammenstellen + VerifyXMLSignatureRequest verifyRequest = spssFac.createVerifyXMLSignatureRequest(null, // Wird Prüfzeit nicht + // angegeben, wird + // aktuelle Zeit + // verwendet + sigInfo, null, // Keine Ergänzungsobjekte notwendig + null, // Signaturmanifest-Prüfung soll nicht durchgeführt werden + false, // Hash-Inputdaten, d.h. tatsächlich signierte Daten werden nicht zurückgeliefert + "MOAIDBuergerkartePersonenbindungMitTestkarten");// TODO load from config + // "Test-Signaturdienste"); // ID des verwendeten Vertrauensprofils + + VerifyXMLSignatureResponse verifyResponse = null; + try { + // Aufruf der Signaturprüfung + verifyResponse = sigVerifyService.verifyXMLSignature(verifyRequest); + } catch (MOAException e) { + // Service liefert Fehler + System.err.println("Die Signaturprüfung hat folgenden Fehler geliefert:"); + System.err.println("Fehlercode: " + e.getMessageId()); + System.err.println("Fehlernachricht: " + e.getMessage()); + throw e; + } + + return verifyResponse; + } + + at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse convert( + VerifyXMLSignatureResponse xMLVerifySignatureResponse) { + at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse response = new at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse(); + response.setCertificateCheckCode(xMLVerifySignatureResponse.getCertificateCheck().getCode()); + response.setPublicAuthority(xMLVerifySignatureResponse.getSignerInfo().isPublicAuthority()); + // response.setPublicAuthorityCode(publicAuthorityCode) + response.setQualifiedCertificate(xMLVerifySignatureResponse.getSignerInfo().isQualifiedCertificate()); + response.setSignatureCheckCode(xMLVerifySignatureResponse.getSignatureCheck().getCode()); + response.setSignatureManifestCheckCode(xMLVerifySignatureResponse.getSignatureManifestCheck().getCode()); + // response.setSigningDateTime() + // response.setX509certificate(x509certificate) + response.setXmlDSIGManifestCheckCode(xMLVerifySignatureResponse.getSignatureManifestCheck().getCode()); + // response.setXmlDSIGManigest(xMLVerifySignatureResponse.getSignatureManifestCheck()) + // response.setXmlDsigSubjectName(xmlDsigSubjectName) + return response; + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java new file mode 100644 index 000000000..f8cc17b93 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/CreateStorkAuthRequestFormTask.java @@ -0,0 +1,112 @@ +package at.gv.egovernment.moa.id.auth.modules.stork.tasks; + +import static at.gv.egovernment.moa.id.auth.MOAIDAuthConstants.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.commons.lang3.StringUtils; + +import at.gv.egovernment.moa.id.auth.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.builder.StartAuthenticationBuilder; +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.auth.exception.WrongParametersException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; +import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.id.config.stork.CPEPS; +import at.gv.egovernment.moa.id.config.stork.STORKConfig; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; +import at.gv.egovernment.moa.id.util.ParamValidatorUtils; +import at.gv.egovernment.moa.logging.Logger; + +/** + * Creates a SAML2 STORK authentication request, embeds it in a form (in order to satisfy saml post binging) and returns the form withing the HttpServletResponse.

+ * In detail: + *

    + *
  • Validates the stork configuration in order to make sure the selected country is supported.
  • + *
  • Puts a flag ({@link #PROCESS_CTX_KEY_CPEPS_ISXMLSIGSUPPORTED}) into the ExecutionContext reflecting the capability of the C-PEPS to create xml signatures.
  • + *
  • Invokes {@link AuthenticationServer#startSTORKAuthentication(HttpServletRequest, HttpServletResponse, AuthenticationSession)} which
  • + *
      + *
    • Creates and signs a SAML2 stork authentication request.
    • + *
    • Creates a signature request for auth block signature (either to be performed by the C-PEPS or locally).
    • + *
    • Using the velocity template engine in order to create a form with the embedded stork request.
    • + *
    • Writes the form to the response output stream.
    • + *
    + *
+ * Expects: + *
    + *
  • HttpServletRequest parameter {@linkplain at.gv.egovernment.moa.id.auth.MOAIDAuthConstants#PARAM_SESSIONID PARAM_SESSIONID}
  • + *
  • Property {@code ccc} set within the moa session.
  • + *
+ * Result: + *
    + *
  • Form containing a SAML2 Stork authentication request and an action url pointing to the selected C-PEPS.
  • + *
  • Assertion consumer URL for C-PEPS set either to {@code /PEPSConnector} in case of a C-PEPS supporting xml signatures or {@code /PEPSConnectorWithLocalSigning} if the selected C-PEPS does not support xml signatures.
  • + *
  • In case of a C-PEPS not supporting xml signature: moasession with set signedDoc property (containing the signature request for local signing).
  • + *
  • ExecutionContext contains the boolean flag {@link #PROCESS_CTX_KEY_CPEPS_ISXMLSIGSUPPORTED}. + *
+ * Code taken from {@link StartAuthenticationBuilder#build(AuthenticationSession, HttpServletRequest, HttpServletResponse)}.
+ * Using {@link AuthenticationServer#startSTORKAuthentication(HttpServletRequest, HttpServletResponse, AuthenticationSession)} + * @see #execute(ExecutionContext, HttpServletRequest, HttpServletResponse) + */ +public class CreateStorkAuthRequestFormTask extends AbstractAuthServletTask { + + /** + * Boolean value reflecting the capability of the selected c-peps of creating xml signatures. + */ + public static final String PROCESS_CTX_KEY_CPEPS_ISXMLSIGSUPPORTED = "C-PEPS:XMLSignatureSupported"; + + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest req, HttpServletResponse resp) + throws Exception { + + String pendingRequestID = null; + String sessionID = null; + try { + setNoCachingHeaders(resp); + + sessionID = StringEscapeUtils.escapeHtml(req.getParameter(PARAM_SESSIONID)); + // check parameter + if (!ParamValidatorUtils.isValidSessionID(sessionID)) { + throw new WrongParametersException("CreateStorkAuthRequestFormTask", PARAM_SESSIONID, "auth.12"); + } + AuthenticationSession moasession = AuthenticationServer.getSession(sessionID); + pendingRequestID = AuthenticationSessionStoreage.getPendingRequestID(sessionID); + + if (StringUtils.isEmpty(moasession.getCcc())) { + // illegal state; task should not have been executed without a selected country + throw new AuthenticationException("stork.22", new Object[] { sessionID }); + } + STORKConfig storkConfig = AuthConfigurationProvider.getInstance().getStorkConfig(); + if (!storkConfig.isSTORKAuthentication(moasession.getCcc())) { + throw new AuthenticationException("stork.23", new Object[] { moasession.getCcc(), sessionID }); + } + + // STORK authentication + // cpeps cannot be null + CPEPS cpeps = storkConfig.getCPEPS(moasession.getCcc()); + Logger.debug("Found C-PEPS configuration for citizen of country: " + moasession.getCcc()); + executionContext.put(PROCESS_CTX_KEY_CPEPS_ISXMLSIGSUPPORTED, cpeps.isXMLSignatureSupported()); + + Logger.info("Starting STORK authentication for a citizen of country: " + moasession.getCcc()); + AuthenticationServer.startSTORKAuthentication(req, resp, moasession); + + } catch (MOAIDException ex) { + handleError(null, ex, req, resp, pendingRequestID); + + } catch (Exception e) { + Logger.error("CreateStorkAuthRequestFormTask has an interal Error.", e); + throw new MOAIDException("Internal error.", new Object[] { sessionID }, e); + } + + finally { + ConfigurationDBUtils.closeSession(); + } + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java new file mode 100644 index 000000000..077bb2dee --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleLocalSignResponseTask.java @@ -0,0 +1,216 @@ +package at.gv.egovernment.moa.id.auth.modules.stork.tasks; + +import iaik.x509.X509Certificate; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; + +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.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; +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.auth.stork.STORKException; +import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; +import at.gv.egovernment.moa.id.moduls.ModulUtils; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; +import at.gv.egovernment.moa.id.util.VelocityProvider; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.spss.api.xmlverify.VerifyXMLSignatureResponse; +import eu.stork.oasisdss.api.ApiUtils; +import eu.stork.oasisdss.profile.SignResponse; +import eu.stork.peps.auth.commons.IPersonalAttributeList; +import eu.stork.peps.auth.commons.PersonalAttribute; + +/** + * Processes the citizen's signature, creates identity link using szr gateway and finalizes authentication. + *

+ * In detail: + *

    + *
  • Changes moa session id.
  • + *
  • Decodes and validates the sign response, extracting the citizen's signature.
  • + *
  • Verifies the citizen's signature.
  • + *
  • Create {@code signedDoc} attribute.
  • + *
  • Retrieve identity link from SZR gateway using the citizen's signature.
  • + *
  • If the S-PEPS did not provide any gender information, the szr gateway will not be able to issue an identity link. + * Therefore a form is presented asking for the subject's gender. The form finally submits the user back to the + * {@code /PepsConnectorWithLocalSigning} servlet (this task).
  • + *
  • The moa session is updated with authentication information.
  • + *
  • Change moa session id.
  • + *
  • Redirects back to {@code /dispatcher} in order to finalize the authentication.
  • + *
+ * Expects: + *
    + *
  • HttpServletRequest parameter {@code moaSessionID}
  • + *
  • HttpServletRequest parameter {@code signresponse}
  • + *
+ * Result: + *
    + *
  • Updated moa id session (signed auth block, signer certificate etc.)
  • + *
  • Redirect to {@code /dispatcher}.
  • + *
  • {@link ExecutionContext} contains boolean flag {@code identityLinkAvailable} indicating if an identitylink has been successfully creates or not.
  • + *
+ * Possible branches: + *
    + *
  • In case the szr gateway throws exception due to missing gender information: + *
      + *
    • Returns a form for gender selection with action url back to this servlet/task.
    • + *
    + *
  • + *
+ * Code taken from {@link at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorWithLocalSigningServlet}.
+ * + * @see #execute(ExecutionContext, HttpServletRequest, HttpServletResponse) + */ +public class PepsConnectorHandleLocalSignResponseTask extends AbstractPepsConnectorWithLocalSigningTask { + + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) + throws Exception { + String moaSessionID = request.getParameter("moaSessionID"); + String signResponse = request.getParameter("signresponse"); + Logger.info("moaSessionID:" + moaSessionID); + Logger.info("signResponse:" + signResponse); + + if (moaSessionID != null && signResponse != null) { + // redirect from oasis with signresponse + handleSignResponse(executionContext, request, response); + } else { + // should not occur + throw new IOException("should not occur"); + } + return; + } + + private void handleSignResponse(ExecutionContext executionContext, HttpServletRequest request, + HttpServletResponse response) { + Logger.info("handleSignResponse started"); + String moaSessionID = request.getParameter("moaSessionID"); + String signResponse = request.getParameter("signresponse"); + Logger.info("moaSessionID:" + moaSessionID); + Logger.info("signResponse:" + signResponse); + String pendingRequestID = null; + try { + + // load MOASession from database + AuthenticationSession moaSession = AuthenticationServer.getSession(moaSessionID); + // change MOASessionID + moaSessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); + + pendingRequestID = AuthenticationSessionStoreage.getPendingRequestID(moaSessionID); + Logger.info("pendingRequestID:" + pendingRequestID); + String signResponseString = new String(Base64.decodeBase64(signResponse), "UTF8"); + Logger.info("RECEIVED signresponse:" + signResponseString); + // create SignResponse object + Source response1 = new StreamSource(new java.io.StringReader(signResponseString)); + SignResponse dssSignResponse = ApiUtils.unmarshal(response1, SignResponse.class); + + // SignResponse dssSignResponse = (SignResponse) ApiUtils.unmarshal(new StreamSource(new + // java.io.StringReader(Base64.signResponse))); + + String citizenSignature = getCitizienSignatureFromSignResponse(dssSignResponse); + + // memorize signature into authblock + moaSession.setAuthBlock(citizenSignature); + + X509Certificate cert = getSignerCertificate(citizenSignature); + moaSession.setSignerCertificate(cert); + VerifyXMLSignatureResponse xMLVerifySignatureResponse = verifyXMLSignature(citizenSignature); + at.gv.egovernment.moa.id.auth.data.VerifyXMLSignatureResponse tmp = convert(xMLVerifySignatureResponse); + + moaSession.setXMLVerifySignatureResponse(tmp); + executionContext.put("identityLinkAvailable", false); + try { + IPersonalAttributeList personalAttributeList = moaSession.getAuthnResponseGetPersonalAttributeList(); + // Add SignResponse TODO Add signature (extracted from signResponse)? + List values = new ArrayList(); + values.add(signResponseString); + // values.add(citizenSignature); + Logger.debug("Assembling signedDoc attribute"); + PersonalAttribute signedDocAttribute = new PersonalAttribute("signedDoc", false, values, "Available"); + personalAttributeList.add(signedDocAttribute); + + String authnContextClassRef = moaSession.getAuthnContextClassRef(); + SZRGInsertion(moaSession, personalAttributeList, authnContextClassRef, citizenSignature); + executionContext.put("identityLinkAvailable", true); + } catch (STORKException e) { + // this is really nasty but we work against the system here. We are supposed to get the gender attribute + // from + // stork. If we do not, we cannot register the person in the ERnP - we have to have the + // gender for the represented person. So here comes the dirty hack. + if (e.getCause() instanceof STORKException + && e.getCause().getMessage().equals("gender not found in response")) { + try { + Logger.trace("Initialize VelocityEngine..."); + + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/fetchGender.html"); + VelocityContext context = new VelocityContext(); + context.put("SAMLResponse", request.getParameter("SAMLResponse")); + context.put("action", request.getRequestURL()); + + StringWriter writer = new StringWriter(); + template.merge(context, writer); + response.getOutputStream().write(writer.toString().getBytes("UTF-8")); + } catch (Exception e1) { + Logger.error("Error sending gender retrival form.", e1); + // httpSession.invalidate(); + throw new MOAIDException("stork.10", null); + } + + return; + } + + Logger.error("Error connecting SZR Gateway", e); + throw new MOAIDException("stork.10", null); + } + + Logger.debug("Add full STORK AuthnResponse to MOA session"); + moaSession.setStorkAuthnResponse(request.getParameter("SAMLResponse"));// TODO ask Florian/Thomas + // authnResponse? + moaSession.setForeigner(true); + + // session is implicit stored in changeSessionID!!!! + String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); + + Logger.info("Changed MOASession " + moaSessionID + " to Session " + newMOASessionID); + + // redirect + String redirectURL = null; + redirectURL = new DataURLBuilder().buildDataURL(moaSession.getAuthURL(), + ModulUtils.buildAuthURL(moaSession.getModul(), moaSession.getAction(), pendingRequestID), + newMOASessionID); + redirectURL = response.encodeRedirectURL(redirectURL); + + response.sendRedirect(redirectURL); + Logger.info("REDIRECT TO: " + redirectURL); + + } catch (AuthenticationException e) { + handleError(null, e, request, response, pendingRequestID); + + } catch (MOAIDException e) { + handleError(null, e, request, response, pendingRequestID); + + } catch (Exception e) { + Logger.error("PEPSConnector has an interal Error.", e); + } + + finally { + ConfigurationDBUtils.closeSession(); + } + } + +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java new file mode 100644 index 000000000..3338804b4 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorHandleResponseWithoutSignatureTask.java @@ -0,0 +1,439 @@ +package at.gv.egovernment.moa.id.auth.modules.stork.tasks; + +import iaik.x509.X509Certificate; + +import java.io.IOException; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.transform.Source; +import javax.xml.transform.stream.StreamSource; + +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.opensaml.saml2.core.StatusCode; + +import at.gv.egovernment.moa.id.auth.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; +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.auth.servlet.PEPSConnectorWithLocalSigningServlet; +import at.gv.egovernment.moa.id.auth.stork.STORKException; +import at.gv.egovernment.moa.id.auth.stork.STORKResponseProcessor; +import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; +import at.gv.egovernment.moa.id.commons.db.dao.config.AttributeProviderPlugin; +import at.gv.egovernment.moa.id.config.auth.AuthConfigurationProvider; +import at.gv.egovernment.moa.id.moduls.ModulUtils; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; +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.oasisdss.api.ApiUtils; +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.STORKAuthnRequest; +import eu.stork.peps.auth.commons.STORKAuthnResponse; +import eu.stork.peps.auth.engine.STORKSAMLEngine; +import eu.stork.peps.exceptions.STORKSAMLEngineException; + +/** + * Validates the SAML response from C-PEPS. + *

+ * In detail: + *

    + *
  • Decodes and validates SAML response from C-PEPS.
  • + *
  • Retrieves the moa session using the session id provided by HttpServletRequest parameter {@code RelayState} or by {@code inResponseTo} attribute of the saml response.
  • + *
  • Store saml response in moa session.
  • + *
  • Change moa session id.
  • + *
  • Redirect to {@code /PEPSConnectorWithLocalSigning}, with providing the moa session id as request parameter.
  • + *
+ * Expects: + *
    + *
  • HttpServletRequest parameter {@code moaSessionID} to be {@code null}
  • + *
  • HttpServletRequest parameter {@code signresponse} to be {@code null}
  • + *
  • HttpServletRequest parameter {@code SAMLResponse}
  • + *
  • Either HttpServletRequest parameter {@code RelayState} or {@code inResponseTo} attribute within the saml response, both reflecting the moa session id.
  • + *
+ * Result: + *
    + *
  • Updated moa session (with saml response).
  • + *
  • Redirect to {@code /PEPSConnectorWithLocalSigning}, with providing the moa session id as request parameter.
  • + *
+ * Code taken from {@link at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorWithLocalSigningServlet}.
+ * + * @see #execute(ExecutionContext, HttpServletRequest, HttpServletResponse) + */ +public class PepsConnectorHandleResponseWithoutSignatureTask extends AbstractPepsConnectorWithLocalSigningTask { + + private String oasisDssWebFormURL = "https://testvidp.buergerkarte.at/oasis-dss/DSSWebFormServlet"; + // load from config below + + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) + throws Exception { + String moaSessionID = request.getParameter("moaSessionID"); + String signResponse = request.getParameter("signresponse"); + Logger.info("moaSessionID:" + moaSessionID); + Logger.info("signResponse:" + signResponse); + + if (moaSessionID == null && signResponse == null) { + // normal saml response + handleSAMLResponse(executionContext, request, response); + + } else { + // should not occur + throw new IOException("should not occur"); + } + return; + } + + private void handleSAMLResponse(ExecutionContext executionContext, HttpServletRequest request, + HttpServletResponse response) { + Logger.info("handleSAMLResponse started"); + String pendingRequestID = null; + + setNoCachingHeaders(response); + try { + Logger.info("PEPSConnector Servlet invoked, expecting C-PEPS message."); + Logger.debug("This ACS endpoint is: " + HTTPUtils.getBaseURL(request)); + + Logger.trace("No Caching headers set for HTTP response"); + + // check if https or only http + super.checkIfHTTPisAllowed(request.getRequestURL().toString()); + + Logger.debug("Beginning to extract SAMLResponse out of HTTP Request"); + + // extract STORK Response from HTTP Request + // Decodes SAML Response + byte[] decSamlToken; + try { + decSamlToken = PEPSUtil.decodeSAMLToken(request.getParameter("SAMLResponse")); + Logger.debug("SAMLResponse: " + new String(decSamlToken)); + + } catch (NullPointerException e) { + Logger.error("Unable to retrieve STORK Response", e); + throw new MOAIDException("stork.04", null); + } + + // Get SAMLEngine instance + STORKSAMLEngine engine = STORKSAMLEngine.getInstance("outgoing"); + + STORKAuthnResponse authnResponse = null; + try { + // validate SAML Token + Logger.debug("Starting validation of SAML response"); + authnResponse = engine.validateSTORKAuthnResponse(decSamlToken, (String) request.getRemoteHost()); + Logger.info("SAML response succesfully verified!"); + } catch (STORKSAMLEngineException e) { + Logger.error("Failed to verify STORK SAML Response", e); + throw new MOAIDException("stork.05", null); + } + + Logger.info("STORK SAML Response message succesfully extracted"); + Logger.debug("STORK response: "); + Logger.debug(authnResponse.toString()); + + Logger.debug("Trying to find MOA Session-ID ..."); + // String moaSessionID = request.getParameter(PARAM_SESSIONID); + // first use SAML2 relayState + String moaSessionID = request.getParameter("RelayState"); + + // escape parameter strings + moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID); + + // check if SAML2 relaystate includes a MOA sessionID + if (StringUtils.isEmpty(moaSessionID)) { + // if relaystate is emtpty, use SAML response -> inResponseTo element as session identifier + + moaSessionID = authnResponse.getInResponseTo(); + moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID); + + if (StringUtils.isEmpty(moaSessionID)) { + // No authentication session has been started before + Logger.error("MOA-SessionID was not found, no previous AuthnRequest had been started"); + Logger.debug("PEPSConnectorURL was: " + request.getRequestURL()); + throw new AuthenticationException("auth.02", new Object[] { moaSessionID }); + + } else + Logger.trace("Use MOA SessionID " + moaSessionID + " from AuthnResponse->inResponseTo attribute."); + + } else + // Logger.trace("MOA SessionID " + moaSessionID + " is found in http GET parameter."); + Logger.trace("MOA SessionID " + moaSessionID + " is found in SAML2 relayState."); + + /* + * INFO!!!! SAML message IDs has an different format then MOASessionIDs This is only a workaround because + * many PEPS does not support SAML2 relayState or MOASessionID as AttributConsumerServiceURL GET parameter + */ + // if (!ParamValidatorUtils.isValidSessionID(moaSessionID)) + // throw new WrongParametersException("VerifyAuthenticationBlock", PARAM_SESSIONID, "auth.12"); + + pendingRequestID = AuthenticationSessionStoreage.getPendingRequestID(moaSessionID); + + // load MOASession from database + AuthenticationSession moaSession = AuthenticationServer.getSession(moaSessionID); + // change MOASessionID + moaSessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); + + Logger.info("Found MOA sessionID: " + moaSessionID); + + String statusCodeValue = authnResponse.getStatusCode(); + + if (!statusCodeValue.equals(StatusCode.SUCCESS_URI)) { + Logger.error("Received ErrorResponse from PEPS: " + statusCodeValue); + throw new MOAIDException("stork.06", new Object[] { statusCodeValue }); + } + + Logger.info("Got SAML response with authentication success message."); + + Logger.debug("MOA session is still valid"); + + STORKAuthnRequest storkAuthnRequest = moaSession.getStorkAuthnRequest(); + + if (storkAuthnRequest == null) { + Logger.error("Could not find any preceeding STORK AuthnRequest to this MOA session: " + moaSessionID); + throw new MOAIDException("stork.07", null); + } + + Logger.debug("Found a preceeding STORK AuthnRequest to this MOA session: " + moaSessionID); + + // //////////// incorporate gender from parameters if not in stork response + + IPersonalAttributeList attributeList = authnResponse.getPersonalAttributeList(); + + // but first, check if we have a representation case + if (STORKResponseProcessor.hasAttribute("mandateContent", attributeList) + || STORKResponseProcessor.hasAttribute("representative", attributeList) + || STORKResponseProcessor.hasAttribute("represented", attributeList)) { + // in a representation case... + moaSession.setUseMandate("true"); + + // and check if we have the gender value + PersonalAttribute gender = attributeList.get("gender"); + if (null == gender) { + String gendervalue = (String) request.getParameter("gender"); + if (null != gendervalue) { + gender = new PersonalAttribute(); + gender.setName("gender"); + ArrayList tmp = new ArrayList(); + tmp.add(gendervalue); + gender.setValue(tmp); + + authnResponse.getPersonalAttributeList().add(gender); + } + } + } + + + + // //////////////////////////////////////////////////////////////////////// + + Logger.debug("Starting extraction of signedDoc attribute"); + // extract signed doc element and citizen signature + String citizenSignature = null; + try { + PersonalAttribute signedDoc = authnResponse.getPersonalAttributeList().get("signedDoc"); + String signatureInfo = null; + // FIXME: Remove nonsense code (signedDoc attribute... (throw Exception for "should not occur" situations)), adjust error messages in order to reflect the true problem... + if (signedDoc != null) { + signatureInfo = signedDoc.getValue().get(0); + // should not occur + } else { + + // store SAMLResponse + moaSession.setSAMLResponse(request.getParameter("SAMLResponse")); + // store authnResponse + + // moaSession.setAuthnResponse(authnResponse);//not serializable + moaSession.setAuthnResponseGetPersonalAttributeList(authnResponse.getPersonalAttributeList()); + + String authnContextClassRef = null; + try { + authnContextClassRef = authnResponse.getAssertions().get(0).getAuthnStatements().get(0) + .getAuthnContext().getAuthnContextClassRef().getAuthnContextClassRef(); + } catch (Throwable e) { + Logger.warn("STORK QAA-Level is not found in AuthnResponse. Set QAA Level to requested level"); + } + + moaSession.setAuthnContextClassRef(authnContextClassRef); + moaSession.setReturnURL(request.getRequestURL()); + + // load signedDoc + String signRequest = moaSession.getSignedDoc(); + + // session is implicit stored in changeSessionID!!!! + String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); + + // set return url to PEPSConnectorWithLocalSigningServlet and add newMOASessionID + // signRequest + + String issuerValue = AuthConfigurationProvider.getInstance().getPublicURLPrefix(); + String acsURL = issuerValue + + PEPSConnectorWithLocalSigningServlet.PEPSCONNECTOR_SERVLET_URL_PATTERN; + + String url = acsURL + "?moaSessionID=" + newMOASessionID; + // redirect to OASIS module and sign there + + boolean found = false; + try { + List aps = AuthConfigurationProvider.getInstance() + .getOnlineApplicationParameter(moaSession.getPublicOAURLPrefix()).getStorkAPs(); + Logger.info("Found AttributeProviderPlugins:" + aps.size()); + for (AttributeProviderPlugin ap : aps) { + Logger.info("Found AttributeProviderPlugin attribute:" + ap.getAttributes()); + if (ap.getAttributes().equalsIgnoreCase("signedDoc")) { + // FIXME: A servlet's class field is not thread safe!!! + oasisDssWebFormURL = ap.getUrl(); + found = true; + Logger.info("Loaded signedDoc attribute provider url from config:" + oasisDssWebFormURL); + break; + } + } + } catch (Exception e) { + e.printStackTrace(); + Logger.error("Loading the signedDoc attribute provider url from config failed"); + } + if (!found) { + Logger.error("Failed to load the signedDoc attribute provider url from config"); + } + performRedirect(url, request, response, signRequest); + + return; + } + + // FIXME: This servlet/task is intended to handle peps responses without signature, so why do we try to process that signature here? + SignResponse dssSignResponse = (SignResponse) ApiUtils.unmarshal(new StreamSource( + new java.io.StringReader(signatureInfo))); + + citizenSignature = getCitizienSignatureFromSignResponse(dssSignResponse); + + // memorize signature into authblock + moaSession.setAuthBlock(citizenSignature); + + X509Certificate cert = getSignerCertificate(citizenSignature); + moaSession.setSignerCertificate(cert); + moaSession.setForeigner(true); + + } catch (Throwable e) { + Logger.error("Could not extract citizen signature from C-PEPS", e); + throw new MOAIDException("stork.09", null); + } + + // FIXME: Same here; we do not have the citizen's signature, so this code might be regarded as dead code. + try { + SZRGInsertion(moaSession, authnResponse.getPersonalAttributeList(), authnResponse.getAssertions() + .get(0).getAuthnStatements().get(0).getAuthnContext().getAuthnContextClassRef() + .getAuthnContextClassRef(), citizenSignature); + } catch (STORKException e) { + // this is really nasty but we work against the system here. We are supposed to get the gender attribute + // from + // stork. If we do not, we cannot register the person in the ERnP - we have to have the + // gender for the represented person. So here comes the dirty hack. + if (e.getCause() instanceof STORKException + && e.getCause().getMessage().equals("gender not found in response")) { + try { + Logger.trace("Initialize VelocityEngine..."); + + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/fetchGender.html"); + VelocityContext context = new VelocityContext(); + context.put("SAMLResponse", request.getParameter("SAMLResponse")); + context.put("action", request.getRequestURL()); + + StringWriter writer = new StringWriter(); + template.merge(context, writer); + + response.getOutputStream().write(writer.toString().getBytes("UTF-8")); + } catch (Exception e1) { + Logger.error("Error sending gender retrival form.", e1); + // httpSession.invalidate(); + throw new MOAIDException("stork.10", null); + } + + return; + } + + Logger.error("Error connecting SZR Gateway", e); + throw new MOAIDException("stork.10", null); + } + + Logger.debug("Add full STORK AuthnResponse to MOA session"); + moaSession.setStorkAuthnResponse(request.getParameter("SAMLResponse"));// TODO ask Florian/Thomas + // authnResponse? + + // session is implicit stored in changeSessionID!!!! + String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); + + Logger.info("Changed MOASession " + moaSessionID + " to Session " + newMOASessionID); + + // redirect + String redirectURL = null; + redirectURL = new DataURLBuilder().buildDataURL(moaSession.getAuthURL(), + ModulUtils.buildAuthURL(moaSession.getModul(), moaSession.getAction(), pendingRequestID), + newMOASessionID); + redirectURL = response.encodeRedirectURL(redirectURL); + + response.setContentType("text/html"); + response.setStatus(302); + response.addHeader("Location", redirectURL); + Logger.info("REDIRECT TO: " + redirectURL); + + } catch (AuthenticationException e) { + handleError(null, e, request, response, pendingRequestID); + + } catch (MOAIDException e) { + handleError(null, e, request, response, pendingRequestID); + + } catch (Exception e) { + Logger.error("PEPSConnector has an interal Error.", e); + } + + finally { + ConfigurationDBUtils.closeSession(); + } + + } + + private void performRedirect(String url, HttpServletRequest req, HttpServletResponse resp, String signRequestString) + 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(); + + Logger.debug("performRedirect, signrequest:" + signRequestString); + Source signDoc = new StreamSource(new java.io.StringReader(signRequestString)); + SignRequest signRequest = ApiUtils.unmarshal(signDoc, SignRequest.class); + signRequest.setReturnURL("TODO"); + signRequestString = IOUtils.toString(ApiUtils.marshalToInputStream(signRequest)); + context.put("signrequest", Base64.encodeBase64String(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); + } + } +} diff --git a/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java new file mode 100644 index 000000000..94017e9f6 --- /dev/null +++ b/id/server/modules/module-stork/src/main/java/at/gv/egovernment/moa/id/auth/modules/stork/tasks/PepsConnectorTask.java @@ -0,0 +1,566 @@ +package at.gv.egovernment.moa.id.auth.modules.stork.tasks; + +import iaik.x509.X509Certificate; + +import java.io.IOException; +import java.io.InputStream; +import java.io.StringWriter; +import java.net.URL; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; + +import javax.activation.DataSource; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.namespace.QName; +import javax.xml.transform.stream.StreamSource; +import javax.xml.ws.BindingProvider; +import javax.xml.ws.Service; +import javax.xml.ws.soap.SOAPBinding; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang.StringEscapeUtils; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.opensaml.saml2.core.StatusCode; + +import at.gv.egovernment.moa.id.auth.AuthenticationServer; +import at.gv.egovernment.moa.id.auth.builder.DataURLBuilder; +import at.gv.egovernment.moa.id.auth.data.AuthenticationSession; +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.MOAIDException; +import at.gv.egovernment.moa.id.auth.modules.AbstractAuthServletTask; +import at.gv.egovernment.moa.id.auth.stork.STORKException; +import at.gv.egovernment.moa.id.auth.stork.STORKResponseProcessor; +import at.gv.egovernment.moa.id.commons.db.ConfigurationDBUtils; +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.ModulUtils; +import at.gv.egovernment.moa.id.process.api.ExecutionContext; +import at.gv.egovernment.moa.id.protocols.pvp2x.PVPConstants; +import at.gv.egovernment.moa.id.storage.AuthenticationSessionStoreage; +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 at.gv.util.xsd.xmldsig.SignatureType; +import at.gv.util.xsd.xmldsig.X509DataType; +import eu.stork.documentservice.DocumentService; +import eu.stork.documentservice.data.DatabaseConnectorMySQLImpl; +import eu.stork.oasisdss.api.ApiUtils; +import eu.stork.oasisdss.api.LightweightSourceResolver; +import eu.stork.oasisdss.api.exceptions.ApiUtilsException; +import eu.stork.oasisdss.profile.DocumentType; +import eu.stork.oasisdss.profile.DocumentWithSignature; +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.commons.STORKAuthnRequest; +import eu.stork.peps.auth.commons.STORKAuthnResponse; +import eu.stork.peps.auth.engine.STORKSAMLEngine; +import eu.stork.peps.exceptions.STORKSAMLEngineException; + +/** + * Evaluates the SAML response from the C-PEPS and authenticates the user. + *

+ * In detail: + *

    + *
  • Decodes and validates the SAML response from the C-PEPS.
  • + *
  • Change moa session id.
  • + *
  • Extracts the subject's gender from request parameter {@code gender} if not available from the saml response.
  • + *
  • Extracts the {@code signedDoc} attribute from the response, get signed doc payload using stork attribute query request.
  • + *
  • Request SZR gateway for verification of the citizen's signature and for creating of an identity link.
  • + *
  • In case of mandate mode: If the S-PEPS did not provide any gender information, the szr gateway will not be able to issue an identity link. Therefore a form is presented asking for the subject's gender. The form submits the user back to the {@code /PepsConnector} servlet (this task).
  • + *
  • The moa session is updated with authentication information.
  • + *
  • Change moa session id.
  • + *
  • Redirects back to {@code /dispatcher} in order to finalize the authentication.
  • + *
+ * Expects: + *
    + *
  • HttpServletRequest parameter {@code SAMLResponse}
  • + *
  • Either HttpServletRequest parameter {@code RelayState} or {@code inResponseTo} attribute from the SAML response (both depicting the moa session id)
  • + *
  • HttpServletRequest parameter {@code gender} in case the request comes from the gender selection form
  • + *
  • {@code signedDoc} attribute within the SAML response.
  • + *
+ * Result: + *
    + *
  • Updated moa id session (identity link, stork attributes...)
  • + *
  • {@link ExecutionContext} contains boolean flag {@code identityLinkAvailable} indicating if an identitylink has been successfully creates or not.
  • + *
  • Redirect to {@code /dispatcher}.
  • + *
+ * Possible branches: + *
    + *
  • In case the szr gateway throws exception due to missing gender information: + *
      + *
    • Returns a form for gender selection with action url back to this servlet/task.
    • + *
    + *
  • + *
+ * Code taken from {@link at.gv.egovernment.moa.id.auth.servlet.PEPSConnectorServlet}.
+ * + * @see #execute(ExecutionContext, HttpServletRequest, HttpServletResponse) + */ +public class PepsConnectorTask extends AbstractAuthServletTask { + + private String dtlUrl = null; + + public PepsConnectorTask() { + super(); + 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(); + } + } + + @Override + public void execute(ExecutionContext executionContext, HttpServletRequest request, HttpServletResponse response) + throws Exception { + String pendingRequestID = null; + + setNoCachingHeaders(response); + + try { + + Logger.info("PEPSConnector Servlet invoked, expecting C-PEPS message."); + Logger.debug("This ACS endpoint is: " + HTTPUtils.getBaseURL(request)); + + // check if https or only http + super.checkIfHTTPisAllowed(request.getRequestURL().toString()); + + Logger.debug("Beginning to extract SAMLResponse out of HTTP Request"); + + // extract STORK Response from HTTP Request + // Decodes SAML Response + byte[] decSamlToken; + try { + decSamlToken = PEPSUtil.decodeSAMLToken(request.getParameter("SAMLResponse")); + Logger.debug("SAMLResponse: " + new String(decSamlToken)); + + } catch (NullPointerException e) { + Logger.error("Unable to retrieve STORK Response", e); + throw new MOAIDException("stork.04", null); + } + + // Get SAMLEngine instance + STORKSAMLEngine engine = STORKSAMLEngine.getInstance("outgoing"); + + STORKAuthnResponse authnResponse = null; + try { + // validate SAML Token + Logger.debug("Starting validation of SAML response"); + authnResponse = engine.validateSTORKAuthnResponse(decSamlToken, (String) request.getRemoteHost()); + Logger.info("SAML response succesfully verified!"); + } catch (STORKSAMLEngineException e) { + Logger.error("Failed to verify STORK SAML Response", e); + throw new MOAIDException("stork.05", null); + } + + Logger.info("STORK SAML Response message succesfully extracted"); + Logger.debug("STORK response: "); + Logger.debug(authnResponse.toString()); + + Logger.debug("Trying to find MOA Session-ID ..."); + // String moaSessionID = request.getParameter(PARAM_SESSIONID); + // first use SAML2 relayState + String moaSessionID = request.getParameter("RelayState"); + + // escape parameter strings + moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID); + + // check if SAML2 relaystate includes a MOA sessionID + if (StringUtils.isEmpty(moaSessionID)) { + // if relaystate is emtpty, use SAML response -> inResponseTo element as session identifier + + moaSessionID = authnResponse.getInResponseTo(); + moaSessionID = StringEscapeUtils.escapeHtml(moaSessionID); + + if (StringUtils.isEmpty(moaSessionID)) { + // No authentication session has been started before + Logger.error("MOA-SessionID was not found, no previous AuthnRequest had been started"); + Logger.debug("PEPSConnectorURL was: " + request.getRequestURL()); + throw new AuthenticationException("auth.02", new Object[] { moaSessionID }); + + } else + Logger.trace("Use MOA SessionID " + moaSessionID + " from AuthnResponse->inResponseTo attribute."); + + } else + // Logger.trace("MOA SessionID " + moaSessionID + " is found in http GET parameter."); + Logger.trace("MOA SessionID " + moaSessionID + " is found in SAML2 relayState."); + + /* + * INFO!!!! SAML message IDs has an different format then MOASessionIDs This is only a workaround because + * many PEPS does not support SAML2 relayState or MOASessionID as AttributConsumerServiceURL GET parameter + */ + // if (!ParamValidatorUtils.isValidSessionID(moaSessionID)) + // throw new WrongParametersException("VerifyAuthenticationBlock", PARAM_SESSIONID, "auth.12"); + + pendingRequestID = AuthenticationSessionStoreage.getPendingRequestID(moaSessionID); + + // load MOASession from database + AuthenticationSession moaSession = AuthenticationServer.getSession(moaSessionID); + // change MOASessionID + moaSessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); + + Logger.info("Found MOA sessionID: " + moaSessionID); + + String statusCodeValue = authnResponse.getStatusCode(); + + if (!statusCodeValue.equals(StatusCode.SUCCESS_URI)) { + Logger.error("Received ErrorResponse from PEPS: " + statusCodeValue); + throw new MOAIDException("stork.06", new Object[] { statusCodeValue }); + } + + Logger.info("Got SAML response with authentication success message."); + + Logger.debug("MOA session is still valid"); + + STORKAuthnRequest storkAuthnRequest = moaSession.getStorkAuthnRequest(); + + if (storkAuthnRequest == null) { + Logger.error("Could not find any preceeding STORK AuthnRequest to this MOA session: " + moaSessionID); + throw new MOAIDException("stork.07", null); + } + + Logger.debug("Found a preceeding STORK AuthnRequest to this MOA session: " + moaSessionID); + + // //////////// incorporate gender from parameters if not in stork response + + IPersonalAttributeList attributeList = authnResponse.getPersonalAttributeList(); + + // but first, check if we have a representation case + if (STORKResponseProcessor.hasAttribute("mandateContent", attributeList) + || STORKResponseProcessor.hasAttribute("representative", attributeList) + || STORKResponseProcessor.hasAttribute("represented", attributeList)) { + // in a representation case... + moaSession.setUseMandate("true"); + + // and check if we have the gender value + PersonalAttribute gender = attributeList.get("gender"); // TODO Do we need to check gender value if + // there is no representation case? + if (null == gender) { + String gendervalue = (String) request.getParameter("gender"); + if (null != gendervalue) { + gender = new PersonalAttribute(); + gender.setName("gender"); + ArrayList tmp = new ArrayList(); + tmp.add(gendervalue); + gender.setValue(tmp); + + authnResponse.getPersonalAttributeList().add(gender); + } + } + } + + // //////////////////////////////////////////////////////////////////////// + + Logger.debug("Starting extraction of signedDoc attribute"); + // extract signed doc element and citizen signature + String citizenSignature = null; + try { + String signatureInfo = authnResponse.getPersonalAttributeList().get("signedDoc").getValue().get(0); // TODO ERROR HANDLING + + Logger.debug("signatureInfo:" + signatureInfo); + + SignResponse dssSignResponse = (SignResponse) ApiUtils.unmarshal(new StreamSource( + new java.io.StringReader(signatureInfo))); + + // fetch signed doc + DataSource ds = LightweightSourceResolver.getDataSource(dssSignResponse); + if (ds == null) { + throw new ApiUtilsException("No datasource found in response"); + } + + InputStream incoming = ds.getInputStream(); + citizenSignature = IOUtils.toString(incoming); + incoming.close(); + + Logger.debug("citizenSignature:" + citizenSignature); + if (isDocumentServiceUsed(citizenSignature) == true) { + Logger.debug("Loading document from DocumentService."); + String url = getDtlUrlFromResponse(dssSignResponse); + // get Transferrequest + String transferRequest = getDocTransferRequest(dssSignResponse.getDocUI(), url); + // Load document from DocujmentService + byte[] data = getDocumentFromDtl(transferRequest, url); + citizenSignature = new String(data, "UTF-8"); + Logger.debug("Overridung citizenSignature with:" + citizenSignature); + } + + JAXBContext ctx = JAXBContext.newInstance(SignatureType.class.getPackage().getName()); + SignatureType root = ((JAXBElement) ctx.createUnmarshaller().unmarshal( + IOUtils.toInputStream(citizenSignature))).getValue(); + + // memorize signature into authblock + moaSession.setAuthBlock(citizenSignature); + + // extract certificate + for (Object current : root.getKeyInfo().getContent()) + if (((JAXBElement) current).getValue() instanceof X509DataType) { + for (Object currentX509Data : ((JAXBElement) current).getValue() + .getX509IssuerSerialOrX509SKIOrX509SubjectName()) { + JAXBElement casted = ((JAXBElement) currentX509Data); + if (casted.getName().getLocalPart().equals("X509Certificate")) { + moaSession.setSignerCertificate(new X509Certificate(((String) casted.getValue()) + .getBytes("UTF-8"))); + break; + } + } + } + + } catch (Throwable e) { + Logger.error("Could not extract citizen signature from C-PEPS", e); + throw new MOAIDException("stork.09", null); + } + Logger.debug("Foregin Citizen signature successfully extracted from STORK Assertion (signedDoc)"); + Logger.debug("Citizen signature will be verified by SZR Gateway!"); + + Logger.debug("fetching OAParameters from database"); + + // //read configuration paramters of OA + // AuthenticationSession moasession; + // try { + // moasession = AuthenticationSessionStoreage.getSession(moaSessionID); + // } catch (MOADatabaseException e2) { + // Logger.error("could not retrieve moa session"); + // throw new AuthenticationException("auth.01", null); + // } + OAAuthParameter oaParam = AuthConfigurationProvider.getInstance().getOnlineApplicationParameter( + moaSession.getPublicOAURLPrefix()); + if (oaParam == null) + throw new AuthenticationException("auth.00", new Object[] { moaSession.getPublicOAURLPrefix() }); + + // retrieve target + // TODO: check in case of SSO!!! + String targetType = null; + if (oaParam.getBusinessService()) { + String id = oaParam.getIdentityLinkDomainIdentifier(); + if (id.startsWith(AuthenticationSession.REGISTERANDORDNR_PREFIX_)) + targetType = id; + else + targetType = AuthenticationSession.REGISTERANDORDNR_PREFIX_ + moaSession.getDomainIdentifier(); + } else { + targetType = AuthenticationSession.TARGET_PREFIX_ + oaParam.getTarget(); + } + + Logger.debug("Starting connecting SZR Gateway"); + // contact SZR Gateway + IdentityLink identityLink = null; + executionContext.put("identityLinkAvailable", false); + try { + identityLink = STORKResponseProcessor.connectToSZRGateway(authnResponse.getPersonalAttributeList(), + oaParam.getFriendlyName(), targetType, null, oaParam.getMandateProfiles(), citizenSignature); + } catch (STORKException e) { + // this is really nasty but we work against the system here. We are supposed to get the gender attribute + // from + // stork. If we do not, we cannot register the person in the ERnP - we have to have the + // gender for the represented person. So here comes the dirty hack. + if (e.getCause() instanceof STORKException + && e.getCause().getMessage().equals("gender not found in response")) { + try { + Logger.trace("Initialize VelocityEngine..."); + + VelocityEngine velocityEngine = VelocityProvider.getClassPathVelocityEngine(); + Template template = velocityEngine.getTemplate("/resources/templates/fetchGender.html"); + VelocityContext context = new VelocityContext(); + context.put("SAMLResponse", request.getParameter("SAMLResponse")); + context.put("action", request.getRequestURL()); + + StringWriter writer = new StringWriter(); + template.merge(context, writer); + + response.getOutputStream().write(writer.toString().getBytes("UTF-8")); + } catch (Exception e1) { + Logger.error("Error sending gender retrival form.", e1); + // httpSession.invalidate(); + throw new MOAIDException("stork.10", null); + } + + return; + } + + Logger.error("Error connecting SZR Gateway", e); + throw new MOAIDException("stork.10", null); + } + Logger.debug("SZR communication was successfull"); + + if (identityLink == null) { + Logger.error("SZR Gateway did not return an identity link."); + throw new MOAIDException("stork.10", null); + } + moaSession.setForeigner(true); + + Logger.info("Received Identity Link from SZR Gateway"); + executionContext.put("identityLinkAvailable", true); + moaSession.setIdentityLink(identityLink); + + Logger.debug("Adding addtional STORK attributes to MOA session"); + moaSession.setStorkAttributes(authnResponse.getPersonalAttributeList()); + + Logger.debug("Add full STORK AuthnResponse to MOA session"); + moaSession.setStorkAuthnResponse(request.getParameter("SAMLResponse")); + + // We don't have BKUURL, setting from null to "Not applicable" + moaSession.setBkuURL("Not applicable (STORK Authentication)"); + + // free for single use + moaSession.setAuthenticatedUsed(false); + + // stork did the authentication step + moaSession.setAuthenticated(true); + + // TODO: found better solution, but QAA Level in response could be not supported yet + try { + + moaSession.setQAALevel(authnResponse.getAssertions().get(0).getAuthnStatements().get(0) + .getAuthnContext().getAuthnContextClassRef().getAuthnContextClassRef()); + + } catch (Throwable e) { + Logger.warn("STORK QAA-Level is not found in AuthnResponse. Set QAA Level to requested level"); + moaSession.setQAALevel(PVPConstants.STORK_QAA_PREFIX + oaParam.getQaaLevel()); + + } + + // session is implicit stored in changeSessionID!!!! + String newMOASessionID = AuthenticationSessionStoreage.changeSessionID(moaSession); + + Logger.info("Changed MOASession " + moaSessionID + " to Session " + newMOASessionID); + + // redirect + String redirectURL = null; + redirectURL = new DataURLBuilder().buildDataURL(moaSession.getAuthURL(), + ModulUtils.buildAuthURL(moaSession.getModul(), moaSession.getAction(), pendingRequestID), + newMOASessionID); + redirectURL = response.encodeRedirectURL(redirectURL); + + // response.setContentType("text/html"); + // response.setStatus(302); + // response.addHeader("Location", redirectURL); + response.sendRedirect(redirectURL); + Logger.info("REDIRECT TO: " + redirectURL); + + } catch (AuthenticationException e) { + handleError(null, e, request, response, pendingRequestID); + + } catch (MOAIDException e) { + handleError(null, e, request, response, pendingRequestID); + + } catch (Exception e) { + Logger.error("PEPSConnector has an interal Error.", e); + } + + finally { + ConfigurationDBUtils.closeSession(); + } + + } + + private boolean isDocumentServiceUsed(String citizenSignature) // TODo add better check + { + if (citizenSignature + .contains("
Service Name:{http://stork.eu}DocumentService
Port Name:{http://stork.eu}DocumentServicePort
")) + return true; + return false; + } + + /** + * Get DTL uril from the oasis sign response + * + * @param signRequest + * The signature response + * @return The URL of DTL service + * @throws SimpleException + */ + private String getDtlUrlFromResponse(SignResponse dssSignResponse) { + List documents = ApiUtils.findNamedElement(dssSignResponse.getOptionalOutputs(), + ApiUtils.OPTIONAL_OUTPUT_DOCUMENTWITHSIGNATURE, DocumentWithSignature.class); + DocumentType sourceDocument = documents.get(0).getDocument(); + + if (sourceDocument.getDocumentURL() != null) + return sourceDocument.getDocumentURL(); + else + return null;// throw new Exception("No document url found"); + } + + // From DTLPEPSUTIL + + /** + * 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 { + 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); + } + } + +} diff --git a/id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORK.authmodule.beans.xml b/id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORK.authmodule.beans.xml new file mode 100644 index 000000000..2e924bdd0 --- /dev/null +++ b/id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORK.authmodule.beans.xml @@ -0,0 +1,14 @@ + + + + + + + + + + diff --git a/id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthentication.process.xml b/id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthentication.process.xml new file mode 100644 index 000000000..60989e638 --- /dev/null +++ b/id/server/modules/module-stork/src/main/resources/at/gv/egovernment/moa/id/auth/modules/stork/STORKAuthentication.process.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/id/server/modules/pom.xml b/id/server/modules/pom.xml new file mode 100644 index 000000000..64b1b57b4 --- /dev/null +++ b/id/server/modules/pom.xml @@ -0,0 +1,48 @@ + + 4.0.0 + + + MOA.id + moa-id + 2.x + + + MOA.id.server.modules + moa-id-modules + ${moa-id-version} + pom + + MOA ID-Modules + + + ${basedir}/../../../repository + + + + module-stork + + + + + MOA.id.server + moa-id-lib + + + commons-logging + commons-logging + + + ch.qos.logback + logback-classic + + + + + javax.servlet + javax.servlet-api + provided + + + + diff --git a/id/server/pom.xml b/id/server/pom.xml index 14cb227e7..9d34cce78 100644 --- a/id/server/pom.xml +++ b/id/server/pom.xml @@ -28,6 +28,7 @@ moa-id-commons stork2-saml-engine stork2-commons + modules -- cgit v1.2.3