diff options
Diffstat (limited to 'id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy')
20 files changed, 4118 insertions, 0 deletions
diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/ConnectionBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/ConnectionBuilder.java new file mode 100644 index 000000000..8a8a55442 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/ConnectionBuilder.java @@ -0,0 +1,79 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy; + +import java.io.IOException; +import java.net.HttpURLConnection; +import java.util.Vector; + +import javax.net.ssl.SSLSocketFactory; +import javax.servlet.http.HttpServletRequest; + +/** + * Builder for {@link java.net.URLConnection} objects used to forward requests + * to the remote online application. + * + * @author Paul Ivancsics + * @version $Id$ + */ + +public interface ConnectionBuilder { + + /** + * Builds an HttpURLConnection to a {@link java.net.URL} which is derived + * from an {@link HttpServletRequest} URL, by substitution of a + * public URL prefix for the real URL prefix.<br> + * The HttpURLConnection has been created by {@link java.net.URL#openConnection}, but + * it has not yet been connected to by {@link java.net.URLConnection#connect}.<br> + * The field settings of the HttpURLConnection are: + * <ul> + * <li><code>allowUserInteraction = false</code></li> + * <li><code>doInput = true</code></li> + * <li><code>doOutput = true</code></li> + * <li><code>requestMethod = request.getMethod()</code></li> + * <li><code>useCaches = false</code></li> + * </ul> + * + * @param request the incoming request which shall be forwarded + * @param publicURLPrefix the public URL prefix to be substituted by the real URL prefix + * @param realURLPrefix the URL prefix to substitute the public URL prefix + * @param sslSocketFactory factory to be used for creating an SSL socket in case + * of a URL for scheme <code>"https:"</code>; + * <br>if <code>null</code>, the default SSL socket factory would be used + * @param parameters parameters to be forwarded + * @return a URLConnection created by {@link java.net.URL#openConnection}, connecting to + * the requested URL with <code>publicURLPrefix</code> substituted by <code>realURLPrefix</code> + * @throws IOException if an I/O exception occurs during opening the connection + * @see java.net.URL#openConnection() + * @see com.sun.net.ssl.HttpsURLConnection#getDefaultSSLSocketFactory() + */ + public HttpURLConnection buildConnection( + HttpServletRequest request, + String publicURLPrefix, + String realURLPrefix, + SSLSocketFactory sslSocketFactory, + Vector parameters) throws IOException; + + + /** + * Disconnects the HttpURLConnection if necessary. + * The implementation of the Connectionbuilder decides wether + * if this should be happen or not. + * + * @param con the HttpURLConnection which is normaly to be closed + */ + public void disconnect(HttpURLConnection con); +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/ConnectionBuilderFactory.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/ConnectionBuilderFactory.java new file mode 100644 index 000000000..5ea2c1f86 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/ConnectionBuilderFactory.java @@ -0,0 +1,83 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy; + +import java.util.HashMap; +import java.util.Map; + +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.proxy.OAProxyParameter; +import at.gv.egovernment.moa.id.config.proxy.ProxyConfigurationProvider; + +/** + * Factory delivering a {@link ConnectionBuilder} implementation for + * an online application, initialized from configuration data. + * @author Paul Ivancsics + * @version $Id$ + */ +public class ConnectionBuilderFactory { + + /** default connection builder to be used for online application + * where no special implementation of the <code>ConnectionBuilder</code> + * interface is configured + */ + private static ConnectionBuilder defaultConnectionBuilder; + /** mapping from online application public URL prefix to an implementation + * of the <code>ConnectionBuilder</code> interface to be used; + * if no mapping is given for an online application, the + * <code>DefaultConnectionBuilder</code> will be used */ + private static Map connectionBuilderMap; + + /** + * Initializes the <code>ConnectionBuilder</code> map from the configuration data. + * @throws ConfigurationException when the configuration cannot be read, + * or when a class name configured cannot be instantiated + */ + public static void initialize() throws ConfigurationException { + defaultConnectionBuilder = new DefaultConnectionBuilder(); + connectionBuilderMap = new HashMap(); + ProxyConfigurationProvider proxyConf = ProxyConfigurationProvider.getInstance(); + for (int i = 0; i < proxyConf.getOnlineApplicationParameters().length; i++) { + OAProxyParameter oaParam = proxyConf.getOnlineApplicationParameters()[i]; + String publicURLPrefix = oaParam.getPublicURLPrefix(); + String className = oaParam.getConnectionBuilderImpl(); + if (className != null) { + try { + ConnectionBuilder cb = (ConnectionBuilder)Class.forName(className).newInstance(); + connectionBuilderMap.put(publicURLPrefix, cb); + } + catch (Throwable ex) { + throw new ConfigurationException("config.07", new Object[] {publicURLPrefix}, ex); + } + } + } + } + + /** + * Gets the <code>ConnectionBuilder</code> implementation to be used for the given + * online application. + * @param publicURLPrefix public URL prefix of the online application + * @return <code>ConnectionBuilder</code> implementation + */ + public static ConnectionBuilder getConnectionBuilder(String publicURLPrefix) { + ConnectionBuilder cb = (ConnectionBuilder) connectionBuilderMap.get(publicURLPrefix); + if (cb == null) + return defaultConnectionBuilder; + else + return cb; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/DefaultConnectionBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/DefaultConnectionBuilder.java new file mode 100644 index 000000000..8a7b2a8bd --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/DefaultConnectionBuilder.java @@ -0,0 +1,196 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.Iterator; +import java.util.Vector; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.servlet.http.HttpServletRequest; + +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.proxy.ProxyConfigurationProvider; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.BoolUtils; +import at.gv.egovernment.moa.util.URLEncoder; + + + +/** + * Defaultimplementierung von <code>ConnectionBuilder</code>. + * @author Paul Ivancsics + * @version $Id$ + */ +public class DefaultConnectionBuilder implements ConnectionBuilder { + + /** a boolean to disable the HostnameVerification (default = false)*/ + private static boolean cbDisableHostnameVerification = false; + + /** + * Constructor for DefaultConnectionBuilder. + * @throws ConfigurationException on any config error + */ + public DefaultConnectionBuilder() throws ConfigurationException { + cbDisableHostnameVerification = BoolUtils.valueOf( + ProxyConfigurationProvider.getInstance().getGenericConfigurationParameter( + "ProxyComponent.DisableHostnameVerification")); + //TODO MOA-ID BRZ undocumented feature + if (cbDisableHostnameVerification) + Logger.warn("ProxyComponent.DisableHostnameVerification: " + cbDisableHostnameVerification); + } + + /** + * @see at.gv.egovernment.moa.id.proxy.ConnectionBuilder#buildConnection + */ + public HttpURLConnection buildConnection( + HttpServletRequest req, + String publicURLPrefix, + String realURLPrefix, + SSLSocketFactory sslSocketFactory, + Vector parameters) + throws IOException { + + // Bug [#540] + //String requestedURL = req.getRequestURL().toString(); + String requestedURL = escapeUrl(req.getRequestURL().toString()); + + // check whether requested URL starts with publicURLPrefix + + //Temporary allow http:// urls instead of the https:// in publicURLPrefix + //if (req.getSession().getAttribute("authorizationkey")==null) { + // if (! requestedURL.startsWith(publicURLPrefix)) + // throw new IOException(MOAIDMessageProvider.getInstance().getMessage( + // "proxy.01", new Object[] {requestedURL, publicURLPrefix})); + //} + + // in case of GET request, append query string to requested URL; + // otherwise, HttpURLConnection would perform a POST request + if ("get".equalsIgnoreCase(req.getMethod()) && ! parameters.isEmpty()) { + requestedURL = appendQueryString(requestedURL, parameters); + } + // build real URL in online application + String realURLString = realURLPrefix + requestedURL.substring(publicURLPrefix.length()); + URL url = new URL(realURLString); + Logger.debug("OA Request: " + req.getMethod() + " " + url.toString()); + + HttpURLConnection conn = (HttpURLConnection)url.openConnection(); + conn.setRequestMethod(req.getMethod()); + conn.setDoInput(true); + conn.setDoOutput(true); + //conn.setUseCaches(false); + //conn.setAllowUserInteraction(true); + conn.setInstanceFollowRedirects(false); + + // JSSE Abhängigkeit + if (conn instanceof HttpsURLConnection && sslSocketFactory != null) { + HttpsURLConnection httpsConn = (HttpsURLConnection) conn; + httpsConn.setSSLSocketFactory(sslSocketFactory); + if (cbDisableHostnameVerification) + httpsConn.setHostnameVerifier(new HostnameNonVerifier()); + } + + return conn; + } + + private static String escapeUrl(String unescapedUrlString) throws RuntimeException { + try { + URL unescapedUrl = new URL(unescapedUrlString); + String protocol = unescapedUrl.getProtocol(); + String fragment = unescapedUrl.getRef(); + String ssp = unescapedUrlString.substring(protocol.length() + 1, unescapedUrlString.length() - ((fragment == null) ? 0 : fragment.length() + 1)); + + URL url2 = new URI(protocol, ssp, fragment).toURL(); + return url2.toExternalForm(); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + + /** + * Disconnects the HttpURLConnection if necessary. + * The implementation of the Connectionbuilder decides wether + * if this should be happen or not. + * + * @param conn the HttpURLConnection which is normaly to be closed + */ + public void disconnect(HttpURLConnection conn) { + conn.disconnect(); + } + + + /** + * @param requestedURL + * @param parameters + * @return + */ + private String appendQueryString(String requestedURL, Vector parameters) { + String newURL = requestedURL; + String parameter[] = new String[2]; + String paramValue =""; + String paramName =""; + String paramString =""; + for (Iterator iter = parameters.iterator(); iter.hasNext();) { + try { + parameter = (String[]) iter.next(); + //next two lines work not with OWA-SSL-Login-form + paramName = URLEncoder.encode((String) parameter[0], "UTF-8"); + paramValue = URLEncoder.encode((String) parameter[1], "UTF-8"); + + } catch (UnsupportedEncodingException e) { + //UTF-8 should be supported + } + paramString = "&" + paramName + "=" + paramValue + paramString; + } + if (paramString.length()>0) newURL = newURL + "?" + paramString.substring(1); + return newURL; + } + + /** + * @author Stefan Knirsch + * @version $Id$ + * A private class to change the standard HostName verifier to disable the + * Hostname Verification Check + */ + + // JSSE Abhängigkeit + private class HostnameNonVerifier implements HostnameVerifier { + + public boolean verify(String hostname, SSLSession session) { + return true; + } + + /** + * @see com.sun.net.ssl.HostnameVerifier#verify(String, String) + */ + /*public boolean verify(String arg0, String arg1) { + return true; + }*/ + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/DefaultLoginParameterResolver.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/DefaultLoginParameterResolver.java new file mode 100644 index 000000000..badee38ac --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/DefaultLoginParameterResolver.java @@ -0,0 +1,158 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import at.gv.egovernment.moa.id.config.proxy.OAConfiguration; +import at.gv.egovernment.moa.id.data.AuthenticationData; +import at.gv.egovernment.moa.util.Base64Utils; +import at.gv.egovernment.moa.util.URLEncoder; + +/** + * Implementation of interface <code>LoginParameterResolver</code> + * @author Paul Ivancsics + * @version $Id$ + */ +public class DefaultLoginParameterResolver implements LoginParameterResolver { + + /** + * Constructor + */ + //public DefaultLoginParameterResolver() { + //} + //@TODO: Änderung von 1.4.4 + + /** + * Configuration mehtod (not used) + */ + public void configure(String configuration, Boolean businessService) throws LoginParameterResolverException { + } + + + /** + * @see at.gv.egovernment.moa.id.proxy.LoginParameterResolver#getAuthenticationHeaders(OAConfiguration, AuthenticationData, String, boolean, String) + */ + public Map getAuthenticationHeaders( + OAConfiguration oaConf, + AuthenticationData authData, + String clientIPAddress, + boolean businessService, + String publicURLPrefix) { + + Map result = new HashMap(); + + if (oaConf.getAuthType().equals(OAConfiguration.BASIC_AUTH)) { + String useridPredicate = oaConf.getBasicAuthUserIDMapping(); + String userid = resolveValue(useridPredicate, authData, clientIPAddress); + String passwordPredicate = oaConf.getBasicAuthPasswordMapping(); + String password = resolveValue(passwordPredicate, authData, clientIPAddress); + + try { + String userIDPassword = userid + ":" + password; + String credentials = Base64Utils.encode(userIDPassword.getBytes()); + result.put("Authorization", "Basic " + credentials); + } + catch (IOException ignore) { + } + } + else if (oaConf.getAuthType().equals(OAConfiguration.HEADER_AUTH)) { + for (Iterator iter = oaConf.getHeaderAuthMapping().keySet().iterator(); iter.hasNext();) { + String key = (String) iter.next(); + String predicate = (String) oaConf.getHeaderAuthMapping().get(key); + String resolvedValue = resolveValue(predicate, authData, clientIPAddress); + result.put(key, resolvedValue); + } + } + + return result; + } + + /** + * @see at.gv.egovernment.moa.id.proxy.LoginParameterResolver#getAuthenticationParameters(OAConfiguration, AuthenticationData, String, boolean, String) + */ + public Map getAuthenticationParameters( + OAConfiguration oaConf, + AuthenticationData authData, + String clientIPAddress, + boolean businessService, + String publicURLPrefix) { + + Map result = new HashMap(); + + if (oaConf.getAuthType().equals(OAConfiguration.PARAM_AUTH)) { + for (Iterator iter = oaConf.getParamAuthMapping().keySet().iterator(); iter.hasNext();) { + String key = (String) iter.next(); + String predicate = (String) oaConf.getParamAuthMapping().get(key); + String resolvedValue; + try { + resolvedValue = + URLEncoder.encode(resolveValue(predicate, authData, clientIPAddress), "ISO-8859-1"); + } catch (UnsupportedEncodingException e) { + //ISO-8859-1 is supported + resolvedValue = null; + } + result.put(key, resolvedValue); + } + } + + return result; + } + + /** + * Resolves a login header or parameter value. + * @param predicate header or parameter predicate name from online application configuration + * @param authData authentication data for current login + * @param clientIPAddress client IP address + * @return header or parameter value resolved; <code>null</code> if unknown name is given + */ + private static String resolveValue(String predicate, AuthenticationData authData, String clientIPAddress) { + if (predicate.equals(MOAGivenName)) + return authData.getGivenName(); + if (predicate.equals(MOAFamilyName)) + return authData.getFamilyName(); + if (predicate.equals(MOADateOfBirth)) + return authData.getDateOfBirth(); + if (predicate.equals(MOABPK)) + return authData.getBPK(); + if (predicate.equals(MOAWBPK)) + return authData.getWBPK(); + if (predicate.equals(MOAPublicAuthority)) + if (authData.isPublicAuthority()) + return "true"; + else + return "false"; + if (predicate.equals(MOABKZ)) + return authData.getPublicAuthorityCode(); + if (predicate.equals(MOAQualifiedCertificate)) + if (authData.isQualifiedCertificate()) + return "true"; + else + return "false"; + if (predicate.equals(MOAStammzahl)) + return authData.getIdentificationValue(); + if (predicate.equals(MOAIdentificationValueType)) + return authData.getIdentificationType(); + if (predicate.equals(MOAIPAddress)) + return clientIPAddress; + else return null; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/ElakConnectionBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/ElakConnectionBuilder.java new file mode 100644 index 000000000..f3527055d --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/ElakConnectionBuilder.java @@ -0,0 +1,273 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy; + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLStreamHandler; +import java.util.Iterator; +import java.util.StringTokenizer; +import java.util.Vector; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.servlet.http.HttpServletRequest; + +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.proxy.ProxyConfigurationProvider; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.BoolUtils; +import at.gv.egovernment.moa.util.URLEncoder; + +import com.ibm.webdav.protocol.http.WebDAVURLConnection; + + +/** + * Defaultimplementierung von <code>ConnectionBuilder</code>. + * @author Paul Ivancsics + * @version $Id$ + */ +public class ElakConnectionBuilder implements ConnectionBuilder { + + /** a boolean to disable the HostnameVerification (default = false)*/ + private static boolean cbDisableHostnameVerification = false; + + /** a boolean to indicat if webdav protocol handler was already set */ + private static boolean webdavPHSet = false; + + /** + * The system property name used to register a protocol handler. + */ + public final static String PROTOCOL_HANDLER_PROPERTY_NAME = "java.protocol.handler.pkgs"; + + /** + * The package providing the ldap protocol handler. + */ + public final static String WEBDAV_PROTOCOL_HANDLER = "com.ibm.webdav.protocol"; + + /** + * The pipe character used to sepearte different protocol handlers. + */ + public final static char PIPE_CHAR = '|'; + + + + + + /** + * Constructor for ElakConnectionBuilder. + * @throws ConfigurationException on any config error + */ + public ElakConnectionBuilder() throws ConfigurationException { + cbDisableHostnameVerification = BoolUtils.valueOf( + ProxyConfigurationProvider.getInstance().getGenericConfigurationParameter( + "ProxyComponent.DisableHostnameVerification")); + //TODO MOA-ID BRZ undocumented feature + if (cbDisableHostnameVerification) + Logger.warn("ProxyComponent.DisableHostnameVerification: " + cbDisableHostnameVerification); + } + + /** + * @see at.gv.egovernment.moa.id.proxy.ConnectionBuilder#buildConnection + */ + public HttpURLConnection buildConnection( + HttpServletRequest req, + String publicURLPrefix, + String realURLPrefix, + SSLSocketFactory sslSocketFactory, + Vector parameters) + throws IOException { + + String requestedURL = req.getRequestURL().toString(); + // check whether requested URL starts with publicURLPrefix + if (! requestedURL.startsWith(publicURLPrefix)) + throw new IOException(MOAIDMessageProvider.getInstance().getMessage( + "proxy.01", new Object[] {requestedURL, publicURLPrefix})); + + + + // in case of GET request, append query string to requested URL; + // otherwise, HttpURLConnection would perform a POST request + //FIXME right parameters + /* + if ("get".equalsIgnoreCase(req.getMethod()) && ! parameters.isEmpty()) { + requestedURL = appendQueryString(requestedURL, parameters); + } + */ + //TODO RSCH check functionality + if (null != req.getQueryString() && 0 != req.getQueryString().length() ) { + String query = req.getQueryString(); + requestedURL = requestedURL + "?" + query; + + String parameter[] = new String[2]; + for (Iterator iter = parameters.iterator(); iter.hasNext();) { + parameter = (String[]) iter.next(); + + if(query.indexOf(parameter[0]) >= 0) iter.remove(); + } + } + + // build real URL in online application + String realURLString = realURLPrefix + requestedURL.substring(publicURLPrefix.length()); + + + Logger.info("Registering WebDAV protocol handler"); + String protocolHandlers = System.getProperty(ElakConnectionBuilder.PROTOCOL_HANDLER_PROPERTY_NAME); + if (protocolHandlers == null) { + protocolHandlers = ElakConnectionBuilder.WEBDAV_PROTOCOL_HANDLER; + System.setProperty(ElakConnectionBuilder.PROTOCOL_HANDLER_PROPERTY_NAME, protocolHandlers); + } else { + // check, if WEBDAV protocol handler is already configured + boolean isConfigured = false; + StringTokenizer tokenizer = new StringTokenizer(protocolHandlers, "| "); + while (tokenizer.hasMoreTokens()) { + String protocolHandler = tokenizer.nextToken(); + if (protocolHandler.equals(ElakConnectionBuilder.WEBDAV_PROTOCOL_HANDLER)) { + isConfigured = true; + break; + } + } + // if it has not been configured yet, configure it + if (!isConfigured) { + protocolHandlers = ElakConnectionBuilder.WEBDAV_PROTOCOL_HANDLER + ElakConnectionBuilder.PIPE_CHAR + protocolHandlers; + System.setProperty(ElakConnectionBuilder.PROTOCOL_HANDLER_PROPERTY_NAME, protocolHandlers); + } + } + Logger.info("Registered protocol handlers: " + protocolHandlers); + Class webdavSH = null; + try + { + webdavSH = Class.forName(ElakConnectionBuilder.WEBDAV_PROTOCOL_HANDLER + ".http.Handler"); + } + catch (ClassNotFoundException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + URLStreamHandler urlStreamHandler = null; + try + { + urlStreamHandler = (URLStreamHandler) webdavSH.newInstance(); + } + catch (InstantiationException e1) + { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + catch (IllegalAccessException e1) + { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + //URL testURL = new URL("http", realURLString.substring("http://localhost:82".length()), 82, "", urlStreamHandler); + //WebDAVURLConnection webDavTest = (WebDAVURLConnection) testURL.openConnection(); + + + URL testURL = new URL(realURLString); + Logger.debug("TEST URL ist von der Klasse: " + testURL.getClass().getName()); + + //URL url = new URL(realURLString); + URL testURL2 = new URL(realURLString); + + URL url = new URL("http", "localhost", 82, realURLString.substring("http://localhost:82".length()), urlStreamHandler); + + Logger.debug("OA Request: " + req.getMethod() + " " + url.toString()); + WebDAVURLConnection webDavConn = (WebDAVURLConnection) url.openConnection(); + HttpURLConnection conn = (HttpURLConnection)webDavConn; + webDavConn.setRequestMethod(req.getMethod()); + webDavConn.setDoInput(true); + webDavConn.setDoOutput(true); + //conn.setUseCaches(false); + webDavConn.setAllowUserInteraction(true); + webDavConn.setInstanceFollowRedirects(false); + // JSSE Abhängigkeit + if (conn instanceof HttpsURLConnection && sslSocketFactory != null) { + HttpsURLConnection httpsConn = (HttpsURLConnection) conn; + httpsConn.setSSLSocketFactory(sslSocketFactory); + if (cbDisableHostnameVerification) + httpsConn.setHostnameVerifier(new HostnameNonVerifier()); + } + return conn; + } + + /** + * Disconnects the HttpURLConnection if necessary. + * The implementation of the Connectionbuilder decides wether + * if this should be happen or not. + * + * @param conn the HttpURLConnection which is normaly to be closed + */ + public void disconnect(HttpURLConnection conn) { + conn.disconnect(); + } + + /** + * @param requestedURL + * @param parameters + * @return + */ + private String appendQueryString(String requestedURL, Vector parameters) { + String newURL = requestedURL; + String parameter[] = new String[2]; + String paramValue =""; + String paramName =""; + String paramString =""; + for (Iterator iter = parameters.iterator(); iter.hasNext();) { + try { + parameter = (String[]) iter.next(); + //Following two lines do not work with OWA-SSL-Login-form + paramName = URLEncoder.encode((String) parameter[0], "UTF-8"); + paramValue = URLEncoder.encode((String) parameter[1], "UTF-8"); + + } catch (UnsupportedEncodingException e) { + //UTF-8 should be supported + } + paramString = "&" + paramName + "=" + paramValue + paramString; + } + if (paramString.length()>0) newURL = newURL + "?" + paramString.substring(1); + return newURL; + } + + /** + * @author Stefan Knirsch + * @version $Id$ + * A private class to change the standard HostName verifier to disable the + * Hostname Verification Check + */ +//JSSE Abhängigkeit + private class HostnameNonVerifier implements HostnameVerifier { + + + public boolean verify(String hostname, SSLSession session) { + // TODO Auto-generated method stub + return true; + } + /** + * @see com.sun.net.ssl.HostnameVerifier#verify(String, String) + */ +// public boolean verify(String arg0, String arg1) { +// return true; +// } + + + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/EnhancedConnectionBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/EnhancedConnectionBuilder.java new file mode 100644 index 000000000..7e27082a0 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/EnhancedConnectionBuilder.java @@ -0,0 +1,232 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy; + +import java.io.IOException; +import java.net.URL; +import java.net.URLStreamHandler; +import java.util.Iterator; +import java.util.Vector; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.servlet.http.HttpServletRequest; + +import HTTPClient.HTTPConnection; +import HTTPClient.HttpURLConnection; +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.proxy.ProxyConfigurationProvider; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.BoolUtils; + + +/** + * Outlook Web Access (OWA) Implementierung von <code>ConnectionBuilder</code>. + * uses the HTTP(s)Client from Ronald Tschalär. + * origin version (without https support) is available at http://www.innovation.ch/java/HTTPClient/ + * + * @author pdanner + */ +public class EnhancedConnectionBuilder implements ConnectionBuilder { + + /** a boolean to disable the HostnameVerification (default = false)*/ + private static boolean cbDisableHostnameVerification = false; + /** Name of the Parameter for the Target */ + private static final String PARAM_TARGET = "Target"; + /** Name of the Parameter for the SAMLArtifact */ + private static final String PARAM_SAMLARTIFACT = "SAMLArtifact"; + /** Name of the Attribute for marking the session as authenticated*/ + private static final String ATT_AUTHDATAFETCHED = "AuthDataFetched"; + + static { + HTTPConnection.setDefaultTimeout(0); + try { + HTTPConnection.removeDefaultModule(Class.forName("HTTPClient.AuthorizationModule")); + HTTPConnection.removeDefaultModule(Class.forName("HTTPClient.RedirectionModule")); + HTTPConnection.removeDefaultModule(Class.forName("HTTPClient.CookieModule")); + //HTTPConnection.removeDefaultModule(Class.forName("HTTPClient.RetryModule")); + } catch (ClassNotFoundException e) { + + } + } + + /** + * Constructor for OWAConnectionBuilder. + * @throws ConfigurationException on any config error + */ + public EnhancedConnectionBuilder() throws ConfigurationException { + cbDisableHostnameVerification = BoolUtils.valueOf( + ProxyConfigurationProvider.getInstance().getGenericConfigurationParameter( + "ProxyComponent.DisableHostnameVerification")); + //TODO MOA-ID BRZ undocumented feature + if (cbDisableHostnameVerification) + Logger.warn("ProxyComponent.DisableHostnameVerification: " + cbDisableHostnameVerification); + } + + /** + * @see at.gv.egovernment.moa.id.proxy.ConnectionBuilder#buildConnection + */ + public java.net.HttpURLConnection buildConnection(HttpServletRequest req, String publicURLPrefix, String realURLPrefix, SSLSocketFactory sslSocketFactory, Vector parameters) throws IOException { + + String requestedURL = req.getRequestURL().toString(); + // check whether requested URL starts with publicURLPrefix + + if (! requestedURL.startsWith(publicURLPrefix.substring(0,5))) + throw new IOException(MOAIDMessageProvider.getInstance().getMessage( + "proxy.01", new Object[] {requestedURL, publicURLPrefix})); + + String query = req.getQueryString(); + if (req.getSession().getAttribute(ATT_AUTHDATAFETCHED)!=null) { + query = removeParameter(query, PARAM_SAMLARTIFACT); + query = removeParameter(query, PARAM_TARGET); + req.getSession().removeAttribute(ATT_AUTHDATAFETCHED); + } + if (null != query && 0 != query.length() ) { + requestedURL = requestedURL + "?" + query; + + String parameter[] = new String[2]; + for (Iterator iter = parameters.iterator(); iter.hasNext();) { + parameter = (String[]) iter.next(); + if(query.indexOf(parameter[0]) >= 0) iter.remove(); + } + } + + // build real URL in online application + String realURLString = realURLPrefix + requestedURL.substring(publicURLPrefix.length()); + + // build real URL in online application + URLStreamHandler urlStreamHandler = null; + + //URL url = new URL(realURLString); + if (realURLString.startsWith("https")) { + urlStreamHandler = new HTTPClient.https.Handler(); + } else{ + urlStreamHandler = new HTTPClient.http.Handler(); + } + URL url = new URL(null, realURLString, urlStreamHandler); + Logger.debug("OA Request: " + req.getMethod() + " " + url.toString()); + + HttpURLConnection conn = (HttpURLConnection)url.openConnection(); + + conn.setRequestMethod(req.getMethod()); + conn.setDoInput(true); + conn.setDoOutput(true); + //conn.setUseCaches(false); + //conn.setAllowUserInteraction(true); + conn.setInstanceFollowRedirects(false); + + if (realURLString.startsWith("https") && sslSocketFactory != null) { + conn.setSSLSocketFactory(sslSocketFactory); + //Not available in HTTPClient + //if (cbDisableHostnameVerification) + // conn.setHostnameVerifier(new HostnameNonVerifier()); + } + + return conn; + + } + + /** + * Disconnects the HttpURLConnection if necessary. + * The implementation of the Connectionbuilder decides wether + * if this should be happen or not. + * + * @param conn the HttpURLConnection which is normaly to be closed + */ + public void disconnect(java.net.HttpURLConnection conn) { + // In HTTPClient there must not be an diconnect! + // conn.disconnect(); + } + + /** + * @author Stefan Knirsch + * @version $Id$ + * A private class to change the standard HostName verifier to disable the + * Hostname Verification Check + */ + // JSSE Abhängigkeit + private class HostnameNonVerifier implements HostnameVerifier { + + + public boolean verify(String hostname, SSLSession session) { + return true; + } + + /** + * @see com.sun.net.ssl.HostnameVerifier#verify(String, String) + */ +// public boolean verify(String arg0, String arg1) { +// return true; +// } + + } + + /** + * Removes parameters from the query-URL recursively + * + * @param query the query from which the parameter is to be removed + * @param parameter the parameter to be removed + * @return the parameterclean query + */ + private String removeParameter(String query, String parameter) { + return removeParameter(query, parameter, true); + } + + /** + * Removes one parameter from the query-URL recursively + * + * @param query the query from which the parameter is to be removed + * @param parameter the parameter to be removed + * @param remove. Boolean value wether a parameter was removed in last call or not. In initial call set to true to check for new occurrences + * @return the parameterclean query + */ + private String removeParameter(String query, String parameter, boolean remove) { + String result = query; + if (remove && query!=null && !query.equals("") && parameter!=null && !parameter.equals("")) { + String param = parameter; + int capEnd=0; + if (!param.endsWith("=")) param=param+"="; + if (query.startsWith(param)) { + //remove leading + result=""; + } else { + if (!param.startsWith("&")) param="&"+param; + capEnd = query.indexOf(param); + if (capEnd!=-1) { + //leading part + result=query.substring(0, capEnd); + } + } + if (capEnd!=-1) { + //trailing part + capEnd += param.length(); + int capBegin = -1; + if (capEnd <query.length()) capBegin = query.indexOf("&", capEnd); + if (capBegin!=-1) { + if (capBegin<query.length()) { + result=result + query.substring(capBegin); + if (result.startsWith("&")) result = result.substring(1); //if now is leading part + } + } + } + result = removeParameter(result, parameter, !query.equals(result)); + } + return result; + } + + } diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/LoginParameterResolver.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/LoginParameterResolver.java new file mode 100644 index 000000000..2b087ff1f --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/LoginParameterResolver.java @@ -0,0 +1,101 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy; + +import java.util.Map; + +import at.gv.egovernment.moa.id.config.proxy.OAConfiguration; +import at.gv.egovernment.moa.id.data.AuthenticationData; + +/** + * Determines authentication parameters and headers to be added to a {@link java.net.URLConnection} + * to the remote online application. + * Utilizes {@link OAConfiguration} and {@link AuthenticationData}. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public interface LoginParameterResolver { + + /** Constants used in <code>MOAIDConfiguration-1.2.xsd</code>, type <code>MOAAuthDataType</code>, + * naming predicates used by the <code>LoginParameterResolver</code>. */ + public static final String MOAGivenName = "MOAGivenName"; + /** Constant used in <code>MOAIDConfiguration-1.2.xsd</code>, type <code>MOAAuthDataType</code> */ + public static final String MOAFamilyName = "MOAFamilyName"; + /** Constant used in <code>MOAIDConfiguration-1.2.xsd</code>, type <code>MOAAuthDataType</code> */ + public static final String MOADateOfBirth = "MOADateOfBirth"; + /** Constant used in <code>MOAIDConfiguration-1.2.xsd</code>, type <code>MOAAuthDataType</code> */ + public static final String MOABPK = "MOABPK"; + /** Constant used in <code>MOAIDConfiguration-1.3.xsd</code>, type <code>MOAAuthDataType</code> */ + public static final String MOAWBPK = "MOAWBPK"; + /** Constant used in <code>MOAIDConfiguration-1.2.xsd</code>, type <code>MOAAuthDataType</code> */ + public static final String MOAPublicAuthority = "MOAPublicAuthority"; + /** Constant used in <code>MOAIDConfiguration-1.2.xsd</code>, type <code>MOAAuthDataType</code> */ + public static final String MOABKZ = "MOABKZ"; + /** Constant used in <code>MOAIDConfiguration-1.2.xsd</code>, type <code>MOAAuthDataType</code> */ + public static final String MOAQualifiedCertificate = "MOAQualifiedCertificate"; + /** Constant used in <code>MOAIDConfiguration-1.2.xsd</code>, type <code>MOAAuthDataType</code> */ + public static final String MOAStammzahl = "MOAStammzahl"; + /** Constant used in <code>MOAIDConfiguration-1.2.xsd</code>, type <code>MOAAuthDataType</code> */ + public static final String MOAIdentificationValueType = "MOAIdentificationValueType"; + /** Constant used in <code>MOAIDConfiguration-1.2.xsd</code>, type <code>MOAAuthDataType</code> */ + public static final String MOAIPAddress = "MOAIPAddress"; + + /** + * Returns authentication headers to be added to a URLConnection. + * + * @param oaConf configuration data + * @param authData authentication data + * @param clientIPAddress client IP address + * @param businessService boolean value for recognizing (w)bPK-mode + * @param publicURLPrefix to distinguish different online applications + * @return A map, the keys being header names and values being corresponding header values. + * <br>In case of authentication type <code>"basic-auth"</code>, header fields + * <code>username</code> and <code>password</code>. + * <br>In case of authentication type <code>"header-auth"</code>, header fields + * derived from parameter mapping and authentication data provided. + * <br>Otherwise, an empty map. + */ + public Map getAuthenticationHeaders( + OAConfiguration oaConf, + AuthenticationData authData, + String clientIPAddress, + boolean businessService, + String publicURLPrefix) throws LoginParameterResolverException, NotAllowedException; + + /** + * Returns request parameters to be added to a URLConnection. + * + * @param oaConf configuration data + * @param authData authentication data + * @param clientIPAddress client IP address + * @param businessService boolean value for recognizing (w)bPK-mode + * @param publicURLPrefix to distinguish different online applications + * @return A map, the keys being parameter names and values being corresponding parameter values. + * <br>In case of authentication type <code>"param-auth"</code>, parameters + * derived from parameter mapping and authentication data provided. + * <br>Otherwise, an empty map. + */ + public Map getAuthenticationParameters( + OAConfiguration oaConf, + AuthenticationData authData, + String clientIPAddress, + boolean businessService, + String publicURLPrefix) throws LoginParameterResolverException, NotAllowedException; + + public void configure(String configuration, Boolean businessService) throws LoginParameterResolverException; + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/LoginParameterResolverException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/LoginParameterResolverException.java new file mode 100644 index 000000000..7f42a64fb --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/LoginParameterResolverException.java @@ -0,0 +1,52 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy; + +import at.gv.egovernment.moa.id.MOAIDException; + +/** + * Exception thrown while proxying a request to the online application + * + * @author Rudolf Schamberger + * @version $Id$ + */ +public class LoginParameterResolverException extends MOAIDException { + + /** + * Constructor for LoginParameterResolverException. + * @param messageId + * @param parameters + */ + public LoginParameterResolverException( + String messageId, + Object[] parameters) { + super(messageId, parameters); + } + + /** + * Constructor for LoginParameterResolverException. + * @param messageId + * @param parameters + * @param wrapped + */ + public LoginParameterResolverException( + String messageId, + Object[] parameters, + Throwable wrapped) { + super(messageId, parameters, wrapped); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/LoginParameterResolverFactory.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/LoginParameterResolverFactory.java new file mode 100644 index 000000000..ff7451143 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/LoginParameterResolverFactory.java @@ -0,0 +1,97 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.proxy.OAProxyParameter; +import at.gv.egovernment.moa.id.config.proxy.ProxyConfigurationProvider; + +/** + * Factory delivering a {@link LoginParameterResolver} implementation for + * an online application, initialized from configuration data. + * @author Paul Ivancsics + * @version $Id$ + */ +public class LoginParameterResolverFactory { + + /** default login parameter resolver to be used for online application + * where no special implementation of the <code>LoginParameterResolver</code> + * interface is configured + */ + private static LoginParameterResolver defaultLoginParameterResolver; + /** mapping from online application public URL prefix to an implementation + * of the <code>LoginParameterResolver</code> interface to be used; + * if no mapping is given for an online application, the + * <code>DefaultLoginParameterResolver</code> will be used */ + private static Map loginParameterResolverMap; + + /** + * Initializes the <code>LoginParameterResolver</code> map from the configuration data. + * @throws ConfigurationException when the configuration cannot be read, + * or when a class name configured cannot be instantiated + */ + public static void initialize() throws ConfigurationException { + defaultLoginParameterResolver = new DefaultLoginParameterResolver(); + loginParameterResolverMap = new HashMap(); + ProxyConfigurationProvider proxyConf = ProxyConfigurationProvider.getInstance(); + for (int i = 0; i < proxyConf.getOnlineApplicationParameters().length; i++) { + OAProxyParameter oaParam = proxyConf.getOnlineApplicationParameters()[i]; + String publicURLPrefix = oaParam.getPublicURLPrefix(); + String className = oaParam.getLoginParameterResolverImpl(); + String configuration = oaParam.getLoginParameterResolverConfiguration(); + if (className != null) { + try { + Class lprClass = Class.forName(className); + LoginParameterResolver lpr = (LoginParameterResolver)Class.forName(className).newInstance(); + + Class[] argumentTypes = { String.class, Boolean.class }; + Method confMethod = lprClass.getMethod( "configure", argumentTypes ); + + Object[] arguments = { new String(configuration), new Boolean(oaParam.getBusinessService()) }; + confMethod.invoke( lpr, arguments ); + + loginParameterResolverMap.put(publicURLPrefix, lpr); + } + catch (InvocationTargetException lpex) { + throw new ConfigurationException("config.11", new Object[] {className}, lpex); + } + catch (Throwable ex) { + throw new ConfigurationException("config.07", new Object[] {publicURLPrefix}, ex); + } + } + } + } + + /** + * Gets the <code>LoginParameterResolver</code> implementation to be used for the given + * online application. + * @param publicURLPrefix public URL prefix of the online application + * @return <code>LoginParameterResolver</code> implementation + */ + public static LoginParameterResolver getLoginParameterResolver(String publicURLPrefix) { + LoginParameterResolver lpr = (LoginParameterResolver) loginParameterResolverMap.get(publicURLPrefix); + if (lpr == null) + return defaultLoginParameterResolver; + else + return lpr; + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/MOAIDProxyInitializer.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/MOAIDProxyInitializer.java new file mode 100644 index 000000000..f34da55b5 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/MOAIDProxyInitializer.java @@ -0,0 +1,110 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy; + +import iaik.pki.PKIException; +import iaik.pki.jsse.IAIKX509TrustManager; + +import java.io.IOException; +import java.security.GeneralSecurityException; + +import javax.net.ssl.SSLSocketFactory; + +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.ConnectionParameter; +import at.gv.egovernment.moa.id.config.proxy.OAProxyParameter; +import at.gv.egovernment.moa.id.config.proxy.ProxyConfigurationProvider; +import at.gv.egovernment.moa.id.iaik.config.LoggerConfigImpl; +import at.gv.egovernment.moa.id.util.AxisSecureSocketFactory; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.id.util.SSLUtils; +import at.gv.egovernment.moa.logging.Logger; + +/** + * Web application initializer + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class MOAIDProxyInitializer { + + /** + * Initializes the web application components which need initialization: + * logging, JSSE, MOA-ID Auth configuration, Axis, session cleaner. + */ + public static void initialize() + throws ConfigurationException, IOException, GeneralSecurityException, PKIException { + + Logger.setHierarchy("moa.id.proxy"); + + // Restricts TLS cipher suites + System.setProperty("https.cipherSuites", "SSL_RSA_WITH_RC4_128_SHA,SSL_RSA_WITH_RC4_128_MD5,SSL_RSA_WITH_3DES_EDE_CBC_SHA"); + + // load some jsse classes so that the integrity of the jars can be verified + // before the iaik jce is installed as the security provider + // this workaround is only needed when sun jsse is used in conjunction with + // iaik-jce (on jdk1.3) + ClassLoader cl = MOAIDProxyInitializer.class.getClassLoader(); + try { + cl.loadClass("javax.security.cert.Certificate"); // from jcert.jar + } + catch (ClassNotFoundException e) { + Logger.warn(MOAIDMessageProvider.getInstance().getMessage("init.01", null), e); + } + + // Initializes the SSLSocketFactory store + SSLUtils.initialize(); + + // Initializes IAIKX509TrustManager logging + String log4jConfigURL = System.getProperty("log4j.configuration"); + if (log4jConfigURL != null) { + IAIKX509TrustManager.initLog(new LoggerConfigImpl(log4jConfigURL)); + } + + // Loads the configuration + ProxyConfigurationProvider proxyConf = ProxyConfigurationProvider.reload(); + + // Initializes the Axis secure socket factory for use in calling the MOA-Auth web service, + // using configuration data + ConnectionParameter connParamAuth = proxyConf.getAuthComponentConnectionParameter(); + if (connParamAuth!=null) { + if (connParamAuth.isHTTPSURL()) { + SSLSocketFactory ssf = SSLUtils.getSSLSocketFactory(proxyConf, connParamAuth); + AxisSecureSocketFactory.initialize(ssf); + } + } else { + throw new ConfigurationException("config.16", null); + } + + // Initializes the Axis secure socket factories for use in calling the online applications, + // using configuration data + OAProxyParameter[] oaParams = proxyConf.getOnlineApplicationParameters(); + for (int i = 0; i < oaParams.length; i++) { + OAProxyParameter oaParam = oaParams[i]; + ConnectionParameter oaConnParam = oaParam.getConnectionParameter(); + if (oaConnParam.isHTTPSURL()) + SSLUtils.getSSLSocketFactory(proxyConf, oaConnParam); + } + + // Initializes the ConnectionBuilderFactory from configuration data + ConnectionBuilderFactory.initialize(); + + // Initializes the LoginParameterResolverFactory from configuration data + LoginParameterResolverFactory.initialize(); + + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/NotAllowedException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/NotAllowedException.java new file mode 100644 index 000000000..aff4e3a78 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/NotAllowedException.java @@ -0,0 +1,54 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy; + +import at.gv.egovernment.moa.id.MOAIDException; + +/** + * Exception thrown while proxying a request to the online application + * Reason for this exception: the dedicated LoginParameterResolver does + * not allow access to the desired ressource. + * + * @author Rudolf Schamberger + * @version $Id$ + */ +public class NotAllowedException extends MOAIDException { + + /** + * Constructor for NotAllowedException. + * @param messageId + * @param parameters + */ + public NotAllowedException( + String messageId, + Object[] parameters) { + super(messageId, parameters); + } + + /** + * Constructor for NotAllowedException. + * @param messageId + * @param parameters + * @param wrapped + */ + public NotAllowedException( + String messageId, + Object[] parameters, + Throwable wrapped) { + super(messageId, parameters, wrapped); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/XMLLoginParameterResolverEncryptedData.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/XMLLoginParameterResolverEncryptedData.java new file mode 100644 index 000000000..b16bd417f --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/XMLLoginParameterResolverEncryptedData.java @@ -0,0 +1,693 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy; + +import iaik.security.provider.IAIK; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Security; +import java.util.HashMap; +import java.util.Map; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.IvParameterSpec; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; +import org.xml.sax.SAXException; + +import at.gv.egovernment.moa.id.config.ConfigurationProvider; +import at.gv.egovernment.moa.id.config.proxy.OAConfiguration; +import at.gv.egovernment.moa.id.data.AuthenticationData; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Base64Utils; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.FileUtils; +import at.gv.egovernment.moa.util.URLEncoder; + +/** + * XMLLoginParameterResolver an implementation of implementation of interface + * <code>LoginParameterResolver</code> + * This implementation used to map identities stored in an XML file to parameters + * which are given to OAs. + * + * @author Rudolf Schamberger + * @version $Id$ + */ +public class XMLLoginParameterResolverEncryptedData implements LoginParameterResolver { + + //file which is parsed and interpreted for paremeter resolving. + private String identityFile; + + private Cipher blowfishCipher; + private Key key; + /** + * inner class used to store mapped parameters + */ + class LPRParams { + + /** + * getter method for parameter Enabled. + * Parameter Enabled decides if mapped parameters should be used by XMLLoginParameterResolver + */ + public boolean getEnabled() { + return enabled.booleanValue(); + } + + /** + * getter method for parameter UN (username) + * @return Parameter UN or <code>null</code> not set. + */ + public String getUN() { + return UN; + } + + /** + * getter method for parameter UN (username) + * @return Parameter UN or <code>null</code> not set. + */ + //TODO XMLLPR decrypt + public String getPlainUN() { + //Security.addProvider(); + + + return UN; + } + + + /** + * getter method for parameter PW (password) + * @return Parameter PW or <code>null</code> not set. + */ + public String getPW() { + return PW; + } + + /** + * getter method for generic parameter Param1 + * @return Parameter Param1 or <code>null</code> not set. + */ + public String getParam1() { + return Param1; + } + + /** + * getter method for generic parameter Param2 + * @return Parameter Param2 or <code>null</code> not set. + */ + public String getParam2() { + return Param2; + } + + /** + * getter method for generic parameter Param3 + * @return Parameter Param3 or <code>null</code> not set. + */ + public String getParam3() { + return Param3; + } + + /** + * Returns a string representation of LPRParams + * + * @return a <code>String</code> representation of this object. + * @see XMLLoginParameterResolver.LPRParams + */ + public String toString() { + return "Enabled: " + + enabled.toString() + + "UN: '" + + UN + + "' PW: '" + + PW + + "' Param1: '" + + Param1 + + "' Param2: '" + + Param2 + + "' Param3: '" + + Param3 + + "'\n"; + } + + //private member variables used to store the parameters + private Boolean enabled = null; + private String UN = null; + private String PW = null; + private String Param1 = null; + private String Param2 = null; + private String Param3 = null; + + /** + * Constructs a newly allocated <code>XMLLoginParameterResolver.LPRParams</code> object. + * + * @param enabled enable user mapping to parameter set for the parameter set. + * @param UN username used in HTTP 401 - BasicAuthentication + * @param PW password used in HTTP 401 - BasicAuthentication + * @param Param1 generic parameter1 used in HeaderAuthentication and ParameterAuthentication + * @param Param2 generic parameter2 used in HeaderAuthentication and ParameterAuthentication + * @param Param3 generic parameter3 used in HeaderAuthentication and ParameterAuthentication + **/ + LPRParams(boolean enabled, String UN, String PW, String Param1, String Param2, String Param3) { + this.enabled = new Boolean(enabled); + this.UN = UN; + this.PW = PW; + this.Param1 = Param1; + this.Param2 = Param2; + this.Param3 = Param3; + } + + /** + * Constructs a newly allocated <code>XMLLoginParameterResolver.LPRParams</code> object. + * + * @param enabled enable user mapping to parameter set for the parameter set. + * @param UN username used in HTTP 401 - BasicAuthentication + * @param PW password used in HTTP 401 - BasicAuthentication + **/ + LPRParams(boolean enabled, String UN, String PW) { + this(enabled, UN, PW, null, null, null); + } + } + + /** + * Constructs a newly allocated <code>XMLLoginParameterResolver</code> object. + **/ + public XMLLoginParameterResolverEncryptedData() { + bPKMap = new HashMap(); + namedMap = new HashMap(); + } + + /** + * configuration method + * @param configuration enabled enable user mapping to parameter set for the parameter set. + */ + public void configure(String configuration, Boolean businessService) throws LoginParameterResolverException { + File idFile; + Element rootElement; + + Security.addProvider(new IAIK()); + try { + blowfishCipher = Cipher.getInstance("Blowfish/CBC/PKCS5Padding", "IAIK"); + + } catch (NoSuchPaddingException e) { + throw new LoginParameterResolverException("config.11", + new Object[] { "XMLLoginParameterResolver: NoSuchPaddingException \n" + e.toString()}); + } catch (NoSuchProviderException e) { + throw new LoginParameterResolverException("config.11", + new Object[] { "XMLLoginParameterResolver: NoSuchProviderException \n" + e.toString()}); + } catch (NoSuchAlgorithmException e) { + throw new LoginParameterResolverException("config.11", + new Object[] { "XMLLoginParameterResolver: NoSuchAlgorithmException \n" + e.toString()}); + } + + String plaintext = "start"; + String encrypted = encryptData(plaintext, "1234567890123456", "123hochgeheim"); + String decrypted = decryptData(encrypted, "1234567890123456", "123hochgeheim"); + Logger.debug("plaintext: " + plaintext); + Logger.debug("encrypted: " + encrypted); + Logger.debug("decrypted: " + decrypted); + + //make file name absolut (if it is relative to main config file) + //TODO MOAID XMLLPR check + String moaIDConfigFileName = System.getProperty(ConfigurationProvider.CONFIG_PROPERTY_NAME); + String rootConfigFileDir = new File(moaIDConfigFileName).getParent(); + this.identityFile = FileUtils.makeAbsoluteURL(configuration, rootConfigFileDir); + + if (null == identityFile || false == (idFile = new File(identityFile)).canRead()) { + throw new LoginParameterResolverException("config.11", + new Object[] { "XMLLoginParameterResolver: could not read '" + identityFile + "' " }); + } + try { + rootElement = readXMLFile(identityFile); + } catch (IOException lex) { + Logger.error(lex.toString()); + throw new LoginParameterResolverException("config.11", + new Object[] { "XMLLoginParameterResolver: could not read '" + identityFile + "' " }); + + } catch (SAXException sex) { + Logger.error(sex.toString()); + throw new LoginParameterResolverException("config.11", + new Object[] { "XMLLoginParameterResolver: parsing problem in file:'" + identityFile + "' ", sex.toString() }); + } catch (ParserConfigurationException e) { + // TODO XMLPR Auto-generated catch block + Logger.error(e.toString()); + throw new LoginParameterResolverException("config.11", + new Object[] { "XMLLoginParameterResolver: parsing problem in file:'" + identityFile + "' ", e.toString() }); + } + buildInfo(rootElement, businessService.booleanValue()); + isConfigured = true; + } + + /** + * encryptData method uses parameters masterSecret and bPK as key information to encrypt plaintext + * @param plaintext + * @param bPK + * @param masterSecret + * @return encrypted data (blowfish encrypted, base64 encoded) + * @throws LoginParameterResolverException + */ + public String encryptData(String plaintext, String bPK, String masterSecret) throws LoginParameterResolverException + { + try { + String keyString = bPK + masterSecret; + key = new iaik.security.cipher.SecretKey(keyString.getBytes("UTF-8"), "Blowfish"); + IvParameterSpec param = new IvParameterSpec(new byte [] {0,0,0,0,0,0,0,0}); + + blowfishCipher.init(Cipher.ENCRYPT_MODE, key, param); + byte [] cipherText = blowfishCipher.doFinal(plaintext.getBytes("UTF-8")); + return Base64Utils.encode(cipherText); + } catch (UnsupportedEncodingException e) { + throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); + } catch (InvalidKeyException e) { + throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); + } catch (BadPaddingException e) { + throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); + } catch (IllegalBlockSizeException e) { + throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); + } catch (IllegalStateException e) { + throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); + } catch (InvalidAlgorithmParameterException e) { + throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); + } catch (IOException e) { + throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); + } + } + + + /** + * encryptData method uses parameters masterSecret and bPK as key information to decrypt ciphertext + * @param ciphertext (blowfish encrypted, base64encoded) + * @param bPK + * @param masterSecret + * @return decrypted Data (plaintext) + * @throws LoginParameterResolverException + */ + public String decryptData(String ciphertext, String bPK, String masterSecret) throws LoginParameterResolverException + { + try { + String keyString = bPK + masterSecret; + key = new iaik.security.cipher.SecretKey(keyString.getBytes("UTF-8"), "Blowfish"); + IvParameterSpec param = new IvParameterSpec(new byte [] {0,0,0,0,0,0,0,0}); + blowfishCipher.init(Cipher.DECRYPT_MODE, key, param); + byte [] plaintext = blowfishCipher.doFinal(Base64Utils.decode(ciphertext, true)); + return new String(plaintext); + } catch (UnsupportedEncodingException e) { + throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); + } catch (InvalidKeyException e) { + throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); + } catch (BadPaddingException e) { + throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); + } catch (IllegalBlockSizeException e) { + throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); + } catch (IllegalStateException e) { + throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); + } catch (InvalidAlgorithmParameterException e) { + throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); + } catch (IOException e) { + throw new LoginParameterResolverException("config.14", new Object [] {"Blowfish: " + e.toString()}); + } + } + + + + /** + * @see at.gv.egovernment.moa.id.proxy.LoginParameterResolver#getAuthenticationHeaders(OAConfiguration, AuthenticationData, String, boolean, String) + */ + public Map getAuthenticationHeaders( + OAConfiguration oaConf, + AuthenticationData authData, + String clientIPAddress, + boolean businessService, + String publicURLPrefix) throws LoginParameterResolverException, NotAllowedException { + Map result = new HashMap(); + + if (!isConfigured) { + //TODO XMLLPR + throw new LoginParameterResolverException("XMLLoginParameterResolver with configuration '" + + identityFile + "' is not configured!", null); + } + + //get the Identity of the user + String famName = resolveValue("MOAFamilyName", authData, clientIPAddress); + String givenName = resolveValue("MOAGivenName", authData, clientIPAddress); + String dateOfBirth = resolveValue("MOADateOfBirth", authData, clientIPAddress); + String bPK =""; + String wType= ""; + if (businessService) { + bPK = resolveValue(MOAWBPK, authData, clientIPAddress); + wType = "w"; + } else { + bPK = resolveValue(MOABPK, authData, clientIPAddress); + } + String userid = ""; + String password = ""; + LPRParams params = null; + boolean userFound = false; + + //try (w)bPK and named search + params = bPKIdentitySearch(bPK, wType); + + if (null == params) + params = namedIdentitySearch(famName, givenName, dateOfBirth); + + //if both searches failed, report error. + if(null == params) + throw new NotAllowedException("User:_" + wType + "bPK:'" +bPK+ ", " + famName + ", " + givenName + "' not authorized.", null); + + //HTTP 401 - Basic Authentication + if (oaConf.getAuthType().equals("basic")) { + userid = (null != params.getUN()) ? params.getUN() : ""; + password = (null != params.getPW()) ? params.getPW() : ""; + + try { + String userIDPassword = userid + ":" + password; + String credentials = Base64Utils.encode(userIDPassword.getBytes("UTF-8")); + Logger.debug("XMLLoginParameterResolver: calculated credentials: " + credentials); + result.put("Authorization", "Basic " + credentials); + } catch (IOException ignore) { + throw new LoginParameterResolverException("config.14", new Object[] {"internal error while encoding in Base64"}); + } + } else if (oaConf.getAuthType().equals("header")) { //HTTP Authentication + String key; + String resolvedValue; + //TODO MOAID XMLLPR select value through OA-ConfigFile; + if(null != params.getUN()) result.put("UN", params.getUN()); + if(null != params.getPW()) result.put("UN", params.getPW()); + if(null != params.getParam1()) result.put("UN", params.getParam1()); + if(null != params.getParam2()) result.put("UN", params.getParam2()); + if(null != params.getParam3()) result.put("UN", params.getParam3()); + + } else { + throw new LoginParameterResolverException("config.14", new Object[] {"AuthType not supported"}); + } + + return result; + } + + /** + * @see at.gv.egovernment.moa.id.proxy.LoginParameterResolver#getAuthenticationParameters(OAConfiguration, AuthenticationData, String, boolean, String) + */ + public Map getAuthenticationParameters( + OAConfiguration oaConf, + AuthenticationData authData, + String clientIPAddress, + boolean businessService, + String publicURLPrefix) throws LoginParameterResolverException, NotAllowedException { + + Map result = new HashMap(); + + if (!isConfigured) { + Logger.warn("XMLLoginParameterResolver with configuration '" + identityFile + " is not configured"); + return result; + } + + String famName = resolveValue("MOAFamilyName", authData, clientIPAddress); + String givenName = resolveValue("MOAGivenName", authData, clientIPAddress); + String dateOfBirth = resolveValue("MOADateOfBirth", authData, clientIPAddress); + String bPK =""; + String wType= ""; + if (businessService) { + bPK = resolveValue(MOAWBPK, authData, clientIPAddress); + wType = "w"; + } else { + bPK = resolveValue(MOABPK, authData, clientIPAddress); + } + String userid = ""; + String password = ""; + LPRParams params = null; + + //try (w)bPK and named search + params = bPKIdentitySearch(bPK, wType); + + if (null == params) + params = namedIdentitySearch(famName, givenName, dateOfBirth); + + //if both searches failed, report error. + if(null == params) + throw new NotAllowedException("User:_" + wType + "bPK:'" +bPK+ ", " + famName + ", " + givenName + "' not authorized.", null); + + //TODO MOAID XMLLPR URLEncoder.encode + if (oaConf.getAuthType().equals("param")) { + try { + if(null != params.getUN()) result.put(XSD_UNATTR, URLEncoder.encode(params.getUN(),"ISO-8859-1")); + if(null != params.getPW()) result.put(XSD_PWATTR, URLEncoder.encode(params.getPW(),"ISO-8859-1")); + if(null != params.getParam1()) result.put(XSD_PARAM1ATTR, URLEncoder.encode(params.getParam1(),"ISO-8859-1")); + if(null != params.getParam2()) result.put(XSD_PARAM2ATTR, URLEncoder.encode(params.getParam2(),"ISO-8859-1")); + if(null != params.getParam3()) result.put(XSD_PARAM3ATTR, URLEncoder.encode(params.getParam3(),"ISO-8859-1")); + } catch (UnsupportedEncodingException e) { + // ISO-8859-1 is supported + throw new LoginParameterResolverException("URLEncoder error", null); + } + } else { + throw new LoginParameterResolverException("AuthType not supported", null); + } + return result; + } + + /** + * Resolves a login header or parameter value. + * @param predicate header or parameter predicate name from online application configuration + * @param authData authentication data for current login + * @param clientIPAddress client IP address + * @return header or parameter value resolved; <code>null</code> if unknown name is given + */ + private static String resolveValue( + String predicate, + AuthenticationData authData, + String clientIPAddress) { + if (predicate.equals("MOAGivenName")) + return authData.getGivenName(); + if (predicate.equals("MOAFamilyName")) + return authData.getFamilyName(); + if (predicate.equals("MOADateOfBirth")) + return authData.getDateOfBirth(); + if (predicate.equals("MOABPK")) + return authData.getBPK(); + if (predicate.equals("MOAWBPK")) + return authData.getWBPK(); + if (predicate.equals("MOAPublicAuthority")) + if (authData.isPublicAuthority()) + return "true"; + else + return "false"; + if (predicate.equals("MOABKZ")) + return authData.getPublicAuthorityCode(); + if (predicate.equals("MOAQualifiedCertificate")) + if (authData.isQualifiedCertificate()) + return "true"; + else + return "false"; + if (predicate.equals("MOAStammzahl")) + return authData.getIdentificationValue(); + if (predicate.equals(MOAIdentificationValueType)) + return authData.getIdentificationType(); + if (predicate.equals("MOAIPAddress")) + return clientIPAddress; + else + return null; + } + + /** + * reads, parses the configuration file of XMLLoginParameterResolver and returns the document element. + * @param fileName of the configuration file. + */ + private Element readXMLFile(String fileName) throws ParserConfigurationException, SAXException, IOException { + Logger.info("XMLLoginParameterResolver: Loading and parsing XMLPLoginParameterConfiguration configuration: " + fileName); + + InputStream stream = null; + Element configElem; + + stream = new BufferedInputStream(new FileInputStream(fileName)); + configElem = DOMUtils.parseDocument(stream, true, Constants.ALL_SCHEMA_LOCATIONS, null).getDocumentElement(); + return configElem; + } + + /** + * buildInfo builds up the internal data mapping between the "Identities" and the "Parameters" from the parsed XML file. + * @param root document root element. + */ + private void buildInfo(Element root, boolean businessService) { + NodeList idList = root.getElementsByTagName(XSD_IDELEM); + NodeList paramList = root.getElementsByTagName(XSD_PARAMELEM); + String wType =""; + if (businessService) wType = "w"; + for (int i = 0; i < idList.getLength(); i++) + Logger.debug("XMLLoginParameterResolver: LocalName idList: " + idList.item(i).getLocalName()); + + for (int i = 0; i < paramList.getLength(); i++) + Logger.debug("XMLLoginParameterResolver: LocalName paramList: " + paramList.item(i).getLocalName()); + + for (int i = 0; i < idList.getLength(); i++) { + Element tmpElem = (Element) idList.item(i); + NodeList tmpList = tmpElem.getElementsByTagName(XSD_NAMEDIDELEM); + for (int j = 0; j < tmpList.getLength(); j++) + Logger.debug("XMLLoginParameterResolver: LocalName tmp: " + tmpList.item(j).getLocalName()); + + //Search for NamedIdentity Elements + if (1 == tmpList.getLength()) { + tmpElem = (Element) tmpList.item(0); + String tmpStr = tmpElem.getAttribute(XSD_SURNAMEATTR) + "," + + tmpElem.getAttribute(XSD_GIVENNAMEATTR) + "," + + tmpElem.getAttribute(XSD_BIRTHDATEATTR); + boolean tmpBool = false; + if (tmpElem.getFirstChild() != null + && "1".compareTo(tmpElem.getFirstChild().getNodeValue()) == 0) + tmpBool = true; + //TODO XMLLPR remove + Logger.debug("XMLLoginParameterResolver: tmpStr: " + tmpStr + " value: " + (new Boolean(tmpBool)).toString()); + tmpElem = (Element) paramList.item(i); + Logger.debug("XMLLoginParameterResolver: attribute UN: " + tmpElem.getAttribute(XSD_UNATTR) + + " attribute PW: " + tmpElem.getAttribute(XSD_PWATTR) + + " attribute Param1: " + tmpElem.getAttribute(XSD_PARAM1ATTR) + + " attribute Param2: " + tmpElem.getAttribute(XSD_PARAM2ATTR) + + " attribute Param3: " + tmpElem.getAttribute(XSD_PARAM3ATTR) ); + namedMap.put(tmpStr, new LPRParams(tmpBool, tmpElem.getAttribute(XSD_UNATTR), tmpElem.getAttribute(XSD_PWATTR), + tmpElem.getAttribute(XSD_PARAM1ATTR), tmpElem.getAttribute(XSD_PARAM2ATTR), + tmpElem.getAttribute(XSD_PARAM3ATTR)) ); + } else { + + //(w)bPKIdentity Elements + if (businessService) { + tmpList = tmpElem.getElementsByTagName(XSD_WBPKIDELEM); + } else { + tmpList = tmpElem.getElementsByTagName(XSD_BPKIDELEM); + } + if (1 == tmpList.getLength()) { + tmpElem = (Element) tmpList.item(0); + String tmpStr = ""; + if (businessService) { + tmpStr = tmpElem.getAttribute(XSD_WBPKATTR); + } else { + tmpStr = tmpElem.getAttribute(XSD_BPKATTR); + } + boolean tmpBool = false; + if (tmpElem.getFirstChild() != null + && "1".compareTo(tmpElem.getFirstChild().getNodeValue()) == 0) + tmpBool = true; + Logger.debug("XMLLoginParameterResolver: tmpStr: " + tmpStr + " value: " + (new Boolean(tmpBool)).toString()); + tmpElem = (Element) paramList.item(i); + Logger.debug("XMLLoginParameterResolver: attribute UN: " + tmpElem.getAttribute(XSD_UNATTR) + + " attribute PW: " + tmpElem.getAttribute(XSD_PWATTR) + + " attribute Param1: " + tmpElem.getAttribute(XSD_PARAM1ATTR) + + " attribute Param2: " + tmpElem.getAttribute(XSD_PARAM2ATTR) + + " attribute Param3: " + tmpElem.getAttribute(XSD_PARAM3ATTR) ); + namedMap.put(tmpStr, new LPRParams(tmpBool, tmpElem.getAttribute(XSD_UNATTR), tmpElem.getAttribute(XSD_PWATTR), + tmpElem.getAttribute(XSD_PARAM1ATTR), tmpElem.getAttribute(XSD_PARAM2ATTR), + tmpElem.getAttribute(XSD_PARAM3ATTR)) ); + } else { + if (businessService) { + Logger.warn("XMLLoginParameterResolver: wrong format no Elements " + XSD_NAMEDIDELEM + " or " + XSD_WBPKIDELEM + " found"); + } else { + Logger.warn("XMLLoginParameterResolver: wrong format no Elements " + XSD_NAMEDIDELEM + " or " + XSD_BPKIDELEM + " found"); + } + } + } + } + + Logger.debug("namedMap:" + namedMap.toString()); + Logger.debug(wType + "bPKMap:" + bPKMap.toString()); + } + + + + + /** + * searches for a given bPK and returns the appropriate LPRParams structure + * @param bPK search argument + * @return LPRParams if bPK could be found in internal mappings or null otherwise. + */ + LPRParams bPKIdentitySearch(String bPK, String wType) { + //search for mapping with (w)bPK of the user + Logger.info("XMLLoginParameterResolver: search for login data mapped to " + wType + "bPK:" + bPK); + LPRParams params = (LPRParams) bPKMap.get(bPK); + if (null == params) { + Logger.info("XMLLoginParameterResolver: params for " + wType + "bPK: " + bPK + " not found!"); + return null; + } else if (params.getEnabled()) { + Logger.info("XMLLoginParameterResolver: " + wType + "bPK: " + bPK + "found in list; user is enabled"); + Logger.debug("XMLLoginParameterResolver: using: " + params.toString()); + return params; + } + Logger.info("XMLLoginParameterResolver: " + wType + "bPK: " + bPK + "found in list but user is NOT enabled"); + return null; + } + + /** + * searches for a given namedIdentity and returns the appropriate LPRParams structure + * @param surName surname search argument + * @param givenName givenname search argument + * @param dateOfBirth dateofbirth search argument + * @return LPRParams if (w)bPK could be found in internal mappings or null otherwise. + */ + LPRParams namedIdentitySearch(String surName, String givenName, String dateOfBirth) { + Logger.info("XMLLoginParameterResolver: search for login data for SurName:" + surName + " GivenName: " + givenName + " DateOfBirth" + dateOfBirth); + //try first a search with surname, givenname and birthdate + LPRParams params = (LPRParams) namedMap.get(surName + "," + givenName + "," + dateOfBirth); + if (null == params) { + Logger.debug("XMLLoginParameterResolver: params for Surname: " + surName + " GivenName: " + givenName + "BirthDate: " + dateOfBirth + " not found!"); + //try a search with surname, givenname only + params = (LPRParams) namedMap.get(surName + "," + givenName + "," + XSD_BIRTHDATEBLANKATTR); + if(null == params) { + Logger.debug("XMLLoginParameterResolver: params for Surname: " + surName + " GivenName: " + givenName + " not found!"); + return null; + } + } + + if (params.getEnabled()) { + Logger.info("XMLLoginParameterResolver: Surname:" + surName + " GivenName: " + givenName + " found in list; user is enabled"); + Logger.debug("XMLLoginParameterResolver: using: " + params.toString()); + return params; + } + Logger.info("XMLLoginParameterResolver: SurName:" + surName + " GivenName: " + givenName + "found in list; user is NOT enabled"); + return null; + } + + //public static final String XSD_MAPPING = "Mapping"; + //public static final String XSD_DOCELEM = "MOAIdentities"; + public static final String XSD_IDELEM = "Identity"; + public static final String XSD_NAMEDIDELEM = "NamedIdentity"; + public static final String XSD_BPKIDELEM = "bPKIdentity"; + public static final String XSD_WBPKIDELEM = "wbPKIdentity"; + public static final String XSD_PARAMELEM = "Parameters"; + public static final String XSD_SURNAMEATTR = "SurName"; + public static final String XSD_GIVENNAMEATTR = "GivenName"; + public static final String XSD_BIRTHDATEATTR = "BirthDate"; + public static final String XSD_BIRTHDATEBLANKATTR = "any"; + public static final String XSD_BPKATTR = "bPK"; + public static final String XSD_WBPKATTR = "wbPK"; + public static final String XSD_UNATTR = "UN"; + public static final String XSD_PWATTR = "PW"; + public static final String XSD_PARAM1ATTR = "Param1"; + public static final String XSD_PARAM2ATTR = "Param2"; + public static final String XSD_PARAM3ATTR = "Param3"; + private Map bPKMap; + private Map namedMap; + private boolean isConfigured = false; +}
\ No newline at end of file diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/XMLLoginParameterResolverPlainData.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/XMLLoginParameterResolverPlainData.java new file mode 100644 index 000000000..2183278c3 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/XMLLoginParameterResolverPlainData.java @@ -0,0 +1,437 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy; + +import at.gv.egovernment.moa.id.config.proxy.OAConfiguration; +import at.gv.egovernment.moa.id.data.AuthenticationData; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Base64Utils; +import java.io.IOException; +import java.util.*; +import org.apache.xerces.parsers.DOMParser; +import org.w3c.dom.*; + +// Referenced classes of package at.gv.egovernment.moa.id.proxy: +// +// TODO MOA-ID test full functionality + +public class XMLLoginParameterResolverPlainData + implements LoginParameterResolver +{ + private String configuration; + + /** + * inner class used to store mapped parameters + */ + class LPRParams { + + /** + * getter method for parameter Enabled. + * Parameter Enabled decides if mapped parameters should be used by XMLLoginParameterResolver + */ + public boolean getEnabled() { + return enabled.booleanValue(); + } + + /** + * getter method for parameter UN (username) + * @return Parameter UN or <code>null</code> not set. + */ + public String getUN() { + return UN; + } + + /** + * getter method for parameter UN (username) + * @return Parameter UN or <code>null</code> not set. + */ + public String getPlainUN() { + return UN; + } + + + /** + * getter method for parameter PW (password) + * @return Parameter PW or <code>null</code> not set. + */ + public String getPW() { + return PW; + } + + /** + * getter method for generic parameter Param1 + * @return Parameter Param1 or <code>null</code> not set. + */ + public String getParam1() { + return Param1; + } + + /** + * getter method for generic parameter Param2 + * @return Parameter Param2 or <code>null</code> not set. + */ + public String getParam2() { + return Param2; + } + + /** + * getter method for generic parameter Param3 + * @return Parameter Param3 or <code>null</code> not set. + */ + public String getParam3() { + return Param3; + } + + /** + * Returns a string representation of LPRParams + * + * @return a <code>String</code> representation of this object. + * @see XMLLoginParameterResolver.LPRParams + */ + public String toString() { + return "Enabled: " + + enabled.toString() + + "UN: '" + + UN + + "' PW: '" + + PW + + "' Param1: '" + + Param1 + + "' Param2: '" + + Param2 + + "' Param3: '" + + Param3 + + "'\n"; + } + + //private member variables used to store the parameters + private Boolean enabled = null; + private String UN = null; + private String PW = null; + private String Param1 = null; + private String Param2 = null; + private String Param3 = null; + + /** + * Constructs a newly allocated <code>XMLLoginParameterResolver.LPRParams</code> object. + * + * @param enabled enable user mapping to parameter set for the parameter set. + * @param UN username used in HTTP 401 - BasicAuthentication + * @param PW password used in HTTP 401 - BasicAuthentication + * @param Param1 generic parameter1 used in HeaderAuthentication and ParameterAuthentication + * @param Param2 generic parameter2 used in HeaderAuthentication and ParameterAuthentication + * @param Param3 generic parameter3 used in HeaderAuthentication and ParameterAuthentication + **/ + LPRParams(boolean enabled, String UN, String PW, String Param1, String Param2, String Param3) { + this.enabled = new Boolean(enabled); + this.UN = UN; + this.PW = PW; + this.Param1 = Param1; + this.Param2 = Param2; + this.Param3 = Param3; + } + + /** + * Constructs a newly allocated <code>XMLLoginParameterResolver.LPRParams</code> object. + * + * @param enabled enable user mapping to parameter set for the parameter set. + * @param UN username used in HTTP 401 - BasicAuthentication + * @param PW password used in HTTP 401 - BasicAuthentication + **/ + LPRParams(boolean enabled, String UN, String PW) { + this(enabled, UN, PW, null, null, null); + } + } + + //TODO document + public XMLLoginParameterResolverPlainData() + { + bPKMap = new HashMap(); + namedMap = new HashMap(); + + } + + //TODO document + public Map getAuthenticationHeaders(OAConfiguration oaConf, AuthenticationData authData, String clientIPAddress, boolean businessService, String publicURLPrefix) throws NotAllowedException + { + Map result = new HashMap(); + if(oaConf.getAuthType().equals("basic")) + { + String famName = resolveValue(MOAFamilyName, authData, clientIPAddress); + String givenName = resolveValue(MOAGivenName, authData, clientIPAddress); + String dateOfBirth = resolveValue(MOADateOfBirth, authData, clientIPAddress); + String bPK =""; + String wType= ""; + if (businessService) { + bPK = resolveValue(MOAWBPK, authData, clientIPAddress); + wType = "w"; + } else { + bPK = resolveValue(MOABPK, authData, clientIPAddress); + } + String userid = ""; + String password = ""; + String param1 = ""; + String param2 = ""; + String param3 = ""; + + LPRParams params = null; + boolean userFound = false; + + //first step: search for (w)bPK entry in user list + Logger.debug("XMLLoginParameterResolverPlainData: search for automatic login data for "+ wType + "bPK:" + bPK); + params = (LPRParams)bPKMap.get(bPK); + if(params == null) + Logger.debug("XMLLoginParameterResolverPlainData: params for "+ wType + "bPK: " + bPK + " not found in file!"); + else + if(params.getEnabled()) + { //if user is enabled: get related parameters + Logger.debug("XMLLoginParameterResolverPlainData: "+ wType + "bPK: " + bPK + " found in list; user is enabled"); + Logger.debug("XMLLoginParameterResolverPlainData: using: " + params.toString()); + userid = params.getUN(); + password = params.getPW(); + param1 = params.getParam1(); + param2 = params.getParam2(); + param3 = params.getParam3(); + userFound = true; + } else + { + Logger.info("XMLLoginParameterResolverPlainData: "+ wType + "bPK: " + bPK + " found in list; user is NOT enabled"); + } + if(!userFound) //secound step: search for name entry in user list + { + Logger.debug("XMLLoginParameterResolverPlainData: search for automatic login data for SurName:" + famName + " GivenName: " + givenName + " DateOfBirth: " + dateOfBirth); + params = (LPRParams)namedMap.get(famName + "," + givenName + "," + dateOfBirth); + if(params == null) { + Logger.debug("XMLLoginParameterResolverPlainData: params for Surname: " + famName + " GivenName: " + givenName + " DateOfBirth: " + dateOfBirth + " not found in file!"); + //try also with wildcard ("*") birthdate + params = (LPRParams)namedMap.get(famName + "," + givenName + "," + "*"); + if(params != null) Logger.debug("XMLLoginParameterResolverPlainData: params for Surname: " + famName + " GivenName: " + givenName + " DateOfBirth: " + "*" + " found!"); + } + + if(null != params && params.getEnabled()) + { + Logger.debug("XMLLoginParameterResolverPlainData: SurName:" + famName + " GivenName: " + givenName + " DateOfBirth: " + dateOfBirth + " found in file; user is enabled"); + Logger.debug("XMLLoginParameterResolverPlainData: using: " + params.toString()); + userid = params.getUN(); + password = params.getPW(); + param1 = params.getParam1(); + param2 = params.getParam2(); + param3 = params.getParam3(); + userFound = true; + } + } + if(!userFound) //third step: search for default user in user list + { + //third step: search for (w)bPK for the default user entry in user list + Logger.debug("XMLLoginParameterResolverPlainData: search for automatic login data for default user"); + params = (LPRParams)bPKMap.get("default"); + if(params == null) + Logger.debug("XMLLoginParameterResolverPlainData: params for default user not found in file!"); + else + if(params.getEnabled()) + { //if user is enabled: get related parameters + Logger.debug("XMLLoginParameterResolverPlainData: default user found in list; user is enabled"); + Logger.debug("XMLLoginParameterResolverPlainData: using: " + params.toString()); + userid = params.getUN(); + password = params.getPW(); + param1 = params.getParam1(); + param2 = params.getParam2(); + param3 = params.getParam3(); + userFound = true; + } else + { + Logger.info("XMLLoginParameterResolverPlainData: default user found in list; user is NOT enabled"); + } + } + + if(!userFound) //if user is not found then throw NotAllowedException exception + { + //TODO MOA-ID proove this with testcases! + Logger.info("XMLLoginParameterResolverPlainData: Person is not allowed No automatic login"); + throw new NotAllowedException("XMLLoginParameterResolverPlainData: Person is not allowed No automatic login ", new Object[] { }); + } + try //if user was found: generate Authorization header entry with associated credemtials + { + String userIDPassword = userid + ":" + password; + String credentials = Base64Utils.encode(userIDPassword.getBytes()); + Logger.debug("XMLLoginParameterResolverPlainData: calculated credentials: " + credentials); + result.put("Authorization", "Basic " + credentials); + } + catch(IOException ignore) { } + } else + if(oaConf.getAuthType().equals("header")) + { + String key; + String resolvedValue; + for(Iterator iter = oaConf.getHeaderAuthMapping().keySet().iterator(); iter.hasNext(); result.put(key, resolvedValue)) + { + key = (String)iter.next(); + String predicate = (String)oaConf.getHeaderAuthMapping().get(key); + resolvedValue = resolveValue(predicate, authData, clientIPAddress); + } + + } + return result; + } + + public Map getAuthenticationParameters(OAConfiguration oaConf, AuthenticationData authData, String clientIPAddress, boolean businessService, String publicURLPrefix) + { + Map result = new HashMap(); + if(oaConf.getAuthType().equals("param")) + { + String key; + String resolvedValue; + for(Iterator iter = oaConf.getParamAuthMapping().keySet().iterator(); iter.hasNext(); result.put(key, resolvedValue)) + { + key = (String)iter.next(); + String predicate = (String)oaConf.getParamAuthMapping().get(key); + resolvedValue = resolveValue(predicate, authData, clientIPAddress); + } + + } + return result; + } + + private static String resolveValue(String predicate, AuthenticationData authData, String clientIPAddress) + { + if(predicate.equals(MOAGivenName)) + return authData.getGivenName(); + if(predicate.equals(MOAFamilyName)) + return authData.getFamilyName(); + if(predicate.equals(MOADateOfBirth)) + return authData.getDateOfBirth(); + if(predicate.equals(MOABPK)) + return authData.getBPK(); + if(predicate.equals(MOAWBPK)) + return authData.getWBPK(); + if(predicate.equals(MOAPublicAuthority)) + if(authData.isPublicAuthority()) + return "true"; + else + return "false"; + if(predicate.equals(MOABKZ)) + return authData.getPublicAuthorityCode(); + if(predicate.equals(MOAQualifiedCertificate)) + if(authData.isQualifiedCertificate()) + return "true"; + else + return "false"; + if(predicate.equals(MOAStammzahl)) + return authData.getIdentificationValue(); + if (predicate.equals(MOAIdentificationValueType)) + return authData.getIdentificationType(); + if(predicate.equals(MOAIPAddress)) + return clientIPAddress; + else + return null; + } + + private Document readXMLFile(String fileName) throws LoginParameterResolverException + { + Logger.info("XMLLoginParameterResolverPlainData: Loading MOA-OA configuration " + fileName); + DOMParser parser = new DOMParser(); + try + { + parser.setFeature("http://xml.org/sax/features/validation", true); + parser.setFeature("http://apache.org/xml/features/validation/schema", true); + parser.parse(fileName); + return parser.getDocument(); + } + catch(Exception e) + { + String msg = e.toString(); + throw new LoginParameterResolverException("proxy.13", new Object[] {"<noURL>: XMLLoginParameterResolverPlainData: Error parsing file " + fileName, "detail problem: " + msg}); + } + } + + private void buildInfo(Document doc, boolean businessService) + { + Element root = doc.getDocumentElement(); + NodeList idList = root.getElementsByTagName("Identity"); + NodeList paramList = root.getElementsByTagName("Parameters"); + String wType =""; + if (businessService) wType = "w"; + for(int i = 0; i < idList.getLength(); i++) + Logger.debug("XMLLoginParameterResolverPlainData: LocalName idList: " + idList.item(i).getLocalName()); + + for(int i = 0; i < paramList.getLength(); i++) + Logger.debug("XMLLoginParameterResolverPlainData: LocalName paramList: " + paramList.item(i).getLocalName()); + + for(int i = 0; i < idList.getLength(); i++) + { + Element tmpElem = (Element)idList.item(i); + NodeList tmpList = tmpElem.getElementsByTagName("NamedIdentity"); + for(int j = 0; j < tmpList.getLength(); j++) + Logger.debug("XMLLoginParameterResolverPlainData: LocalName tmp: " + tmpList.item(j).getLocalName()); + + if(1 == tmpList.getLength()) + { + tmpElem = (Element)tmpList.item(0); + String tmpStr = tmpElem.getAttribute("SurName") + "," + tmpElem.getAttribute("GivenName") + "," + tmpElem.getAttribute("BirthDate"); + boolean tmpBool = false; + if(tmpElem.getFirstChild() != null && "1".compareTo(tmpElem.getFirstChild().getNodeValue()) == 0) + tmpBool = true; + Logger.debug("XMLLoginParameterResolverPlainData: tmpStr: " + tmpStr + " value: " + (new Boolean(tmpBool)).toString()); + tmpElem = (Element)paramList.item(i); + Logger.debug("XMLLoginParameterResolverPlainData: attribute UN: " + tmpElem.getAttribute("UN") + " attribute PW: " + tmpElem.getAttribute("PW")); + namedMap.put(tmpStr, new LPRParams(tmpBool, tmpElem.getAttribute("UN"), tmpElem.getAttribute("PW"))); + } else + { + tmpList = tmpElem.getElementsByTagName(wType + "bPKIdentity"); + if(1 == tmpList.getLength()) + { + tmpElem = (Element)tmpList.item(0); + String tmpStr = tmpElem.getAttribute(wType + "bPK"); + boolean tmpBool = false; + if(tmpElem.getFirstChild() != null && "1".compareTo(tmpElem.getFirstChild().getNodeValue()) == 0) + tmpBool = true; + Logger.debug("XMLLoginParameterResolverPlainData: tmpStr: " + tmpStr + " value: " + (new Boolean(tmpBool)).toString()); + tmpElem = (Element)paramList.item(i); + Logger.debug("XMLLoginParameterResolverPlainData: attribute UN: " + tmpElem.getAttribute("UN") + " attribute PW: " + tmpElem.getAttribute("PW") + " attribute Param1: " + tmpElem.getAttribute("Param1")); + bPKMap.put(tmpStr, new LPRParams(tmpBool, tmpElem.getAttribute("UN"), tmpElem.getAttribute("PW"))); + } else + { + Logger.warn("XMLLoginParameterResolverPlainData: wrong format or incorrect mode; no NamedIdentity or " + wType + "bPKIdentity found"); + } + } + } + + Logger.debug("namedMap:" + namedMap.toString()); + Logger.debug(wType + "bPKMap:" + bPKMap.toString()); + } + + //public static final String XSD_DOCELEM = "MOAIdentities"; + //public static final String XSD_IDELEM = "Identity"; + //public static final String XSD_NAMEDIDELEM = "NamedIdentity"; + //public static final String XSD_BPKIDELEM = "bPKIdentity"; + //public static final String XSD_PARAMELEM = "Parameters"; + //public static final String XML_LPR_CONFIG_PROPERTY_NAME1 = "moa.id.xmllpr1.configuration"; + private Map bPKMap; + private Map namedMap; + + + public void configure(String configuration, Boolean businessService) throws LoginParameterResolverException { + Logger.info("XMLLoginParameterResolverPlainData: initialization string: " + configuration); + this.configuration = configuration; + String fileName = configuration; + if(fileName == null) { + fileName = "file:conf/moa-id/Identities.xml"; + Logger.info("XMLLoginParameterResolverPlainData: used file name string: " + fileName); + } + Document doc = readXMLFile(fileName); + buildInfo(doc, businessService.booleanValue() ); + } +}
\ No newline at end of file diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/builder/SAMLRequestBuilder.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/builder/SAMLRequestBuilder.java new file mode 100644 index 000000000..28bf04e6f --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/builder/SAMLRequestBuilder.java @@ -0,0 +1,70 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy.builder; + +import java.text.MessageFormat; +import java.util.Calendar; + +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.DateTimeUtils; + +/** + * Builder for the <code><samlp:Request></code> used for querying + * the authentication data <code><saml:Assertion></code>. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class SAMLRequestBuilder implements Constants { + /** samlp-Request template */ + private static final String REQUEST = + "<samlp:Request xmlns:samlp=\"urn:oasis:names:tc:SAML:1.0:protocol\" RequestID=\"{0}\" MajorVersion=\"1\" MinorVersion=\"0\" IssueInstant=\"{1}\">" + + "<samlp:AssertionArtifact>{2}</samlp:AssertionArtifact>" + + "</samlp:Request>"; + + /** + * Constructor for SAMLRequestBuilder. + */ + public SAMLRequestBuilder() { + super(); + } + + /** + * Builds the <code><samlp:Request></code>. + * @param requestID request ID + * @param samlArtifactBase64 SAML artifact, encoded BASE64 + * @return the DOM element + */ + public Element build(String requestID, String samlArtifactBase64) throws BuildException { + try { + String issueInstant = DateTimeUtils.buildDateTime(Calendar.getInstance()); + String request = MessageFormat.format(REQUEST, new Object[] {requestID, issueInstant, samlArtifactBase64}); + Element requestElem = DOMUtils.parseDocument(request, false, ALL_SCHEMA_LOCATIONS, null).getDocumentElement(); + return requestElem; + } + catch (Throwable ex) { + throw new BuildException( + "builder.00", + new Object[] {"samlp:Request", ex.toString()}, + ex); + } + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/invoke/GetAuthenticationDataInvoker.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/invoke/GetAuthenticationDataInvoker.java new file mode 100644 index 000000000..3b6ea273f --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/invoke/GetAuthenticationDataInvoker.java @@ -0,0 +1,158 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy.invoke; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Vector; + +import javax.xml.namespace.QName; +import javax.xml.rpc.Call; +import javax.xml.rpc.Service; +import javax.xml.rpc.ServiceFactory; + +import org.apache.axis.message.SOAPBodyElement; +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.id.AuthenticationException; +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.ServiceException; +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.ConnectionParameter; +import at.gv.egovernment.moa.id.config.proxy.ProxyConfigurationProvider; +import at.gv.egovernment.moa.id.data.AuthenticationData; +import at.gv.egovernment.moa.id.data.SAMLStatus; +import at.gv.egovernment.moa.id.proxy.builder.SAMLRequestBuilder; +import at.gv.egovernment.moa.id.proxy.parser.SAMLResponseParser; +import at.gv.egovernment.moa.id.proxy.servlet.ProxyException; +import at.gv.egovernment.moa.id.util.Random; + +/** + * Invoker of + * <ul> + * <li>either the GetAuthenticationData web service of MOA-ID Auth</li> + * <li>or the API call {@link at.gv.egovernment.moa.id.auth.AuthenticationServer#getAuthenticationData},</li> + * </ul> + * depending of the configuration. + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class GetAuthenticationDataInvoker { + /** Create a new QName object for the webservice endpoint */ + private static final QName SERVICE_QNAME = new QName("GetAuthenticationData"); + + /** invoked object for API call of MOA-ID Auth */ + private static Object apiServer = null; + /** invoked method for API call of MOA-ID Auth */ + private static Method apiMethod = null; + + /** + * Invokes the service passing domain model objects. + * @param samlArtifact SAML artifact + * @return AuthenticationData object + * @throws ServiceException on any exception thrown + */ + /** + * Get authentication data from the MOA-ID Auth component, + * either via API call or via web service call. + * @param samlArtifact SAML artifact to be used as a parameter + * @return AuthenticationData + */ + public AuthenticationData getAuthenticationData(String samlArtifact) + throws ConfigurationException, ProxyException, BuildException, ServiceException, ParseException, AuthenticationException { + + ConnectionParameter authConnParam = + ProxyConfigurationProvider.getInstance().getAuthComponentConnectionParameter(); + if (authConnParam == null) { + try { + if (apiServer == null) { + Class serverClass = Class.forName("at.gv.egovernment.moa.id.auth.AuthenticationServer"); + Method getInstanceMethod = serverClass.getMethod("getInstance", (Class[]) null); + apiServer = getInstanceMethod.invoke(null, (Object[]) null); + apiMethod = serverClass.getMethod( + "getAuthenticationData", new Class[] {String.class}); + } + AuthenticationData authData = (AuthenticationData)apiMethod.invoke(apiServer, new Object[] {samlArtifact}); + return authData; + } + catch (InvocationTargetException ex) { + Throwable targetEx = ex.getTargetException(); + if (targetEx instanceof AuthenticationException) + throw (AuthenticationException) targetEx; + else + throw new ProxyException("proxy.09", new Object[] {targetEx.toString()}); + } + catch (Throwable ex) { + throw new ProxyException("proxy.09", new Object[] {ex.toString()}); + } + } + else { + Element samlpRequest = new SAMLRequestBuilder().build(Random.nextRandom(), samlArtifact); + Element samlpResponse = getAuthenticationData(samlpRequest); + SAMLResponseParser srp = new SAMLResponseParser(samlpResponse); + SAMLStatus status = srp.parseStatusCode(); + if (! "samlp:Success".equals(status.getStatusCode())) { + // on error status throw exception + String code = status.getStatusCode(); + if (status.getSubStatusCode() != null && status.getSubStatusCode().length() > 0) + code += "(" + status.getSubStatusCode() + ")"; + throw new ServiceException("service.02", new Object[] {code, status.getStatusMessage()}); + } + return srp.parseAuthenticationData(); + } + } + + /** + * Invokes the service passing DOM elements. + * @param request request DOM element + * @return response DOM element + * @throws ServiceException on any exception thrown + */ + public Element getAuthenticationData(Element request) throws ServiceException { + try { + Service service = ServiceFactory.newInstance().createService(SERVICE_QNAME); + Call call = service.createCall(); + SOAPBodyElement body = + new SOAPBodyElement(request); + SOAPBodyElement[] params = new SOAPBodyElement[] {body}; + Vector responses; + SOAPBodyElement response; + + String endPoint; + ConnectionParameter authConnParam = + ProxyConfigurationProvider.getInstance().getAuthComponentConnectionParameter(); + + //If the ConnectionParameter do NOT exist, we throw an exception .... + if (authConnParam!=null) { + endPoint = authConnParam.getUrl(); + call.setTargetEndpointAddress(endPoint); + responses = (Vector) call.invoke(SERVICE_QNAME, params); + response = (SOAPBodyElement) responses.get(0); + return response.getAsDOM(); + } + else + { + throw new ServiceException("service.01", null); + } + } + catch (Exception ex) { + throw new ServiceException("service.00", new Object[] {ex.toString()}, ex); + } + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/parser/AuthenticationDataAssertionParser.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/parser/AuthenticationDataAssertionParser.java new file mode 100644 index 000000000..b051fe182 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/parser/AuthenticationDataAssertionParser.java @@ -0,0 +1,173 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy.parser; + +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.auth.builder.BPKBuilder; +import at.gv.egovernment.moa.id.data.AuthenticationData; +import at.gv.egovernment.moa.util.BoolUtils; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.DOMUtils; +import at.gv.egovernment.moa.util.XPathUtils; + +/** + * Parser for the <code><saml:Assertion></code> returned by the + * <code>GetAuthenticationData</code> web service. + * @author Paul Ivancsics + * @version $Id$ + */ +public class AuthenticationDataAssertionParser implements Constants { + + /** Prefix for SAML-Xpath-expressions */ + private static String SAML = SAML_PREFIX + ":"; + /** Prefix for PersonData-Xpath-expressions */ + private static String PR = PD_PREFIX + ":"; + /** Prefix for Attribute MajorVersion in an Xpath-expression */ + private static String MAJOR_VERSION_XPATH = + "@MajorVersion"; + /** Prefix for Attribute MinorVersion in an Xpath-expression */ + private static String MINOR_VERSION_XPATH = + "@MinorVersion"; + /** Prefix for Attribute AssertionID in an Xpath-expression */ + private static String ASSERTION_ID_XPATH = + "@AssertionID"; + /** Prefix for Attribute Issuer in an Xpath-expression */ + private static String ISSUER_XPATH = + "@Issuer"; + /** Prefix for Attribute IssueInstant in an Xpath-expression */ + private static String ISSUE_INSTANT_XPATH = + "@IssueInstant"; + /** Prefix for Element AttributeStatement in an Xpath-expression */ + private static String ATTRIBUTESTATEMENT_XPATH = + SAML + "AttributeStatement/"; + /** Prefix for Element NameIdentifier in an Xpath-expression */ + private static String PK_XPATH = + ATTRIBUTESTATEMENT_XPATH + + SAML + "Subject/" + + SAML + "NameIdentifier"; + private static String NAME_QUALIFIER_XPATH = + PK_XPATH + "/@NameQualifier"; + /** Prefix for Element Person in an Xpath-expression */ + private static String PERSONDATA_XPATH = + ATTRIBUTESTATEMENT_XPATH + + SAML + "Attribute[@AttributeName=\"PersonData\"]/" + + SAML + "AttributeValue/" + + PR + "Person/"; + /** Prefix for Element Value in an Xpath-expression */ + private static String IDENTIFICATION_VALUE_XPATH = + PERSONDATA_XPATH + + PR + "Identification/" + + PR + "Value"; + private static String IDENTIFICATION_TYPE_XPATH = + PERSONDATA_XPATH + + PR + "Identification/" + + PR + "Type"; + /** Prefix for Element GivenName in an Xpath-expression */ + private static String GIVEN_NAME_XPATH = + PERSONDATA_XPATH + + PR + "Name/" + + PR + "GivenName"; + /** Prefix for Element FamilyName in an Xpath-expression */ + private static String FAMILY_NAME_XPATH = + PERSONDATA_XPATH + + PR + "Name/" + + PR + "FamilyName"; + /** Prefix for Element DateOfBirth in an Xpath-expression */ + private static String DATE_OF_BIRTH_XPATH = + PERSONDATA_XPATH + + PR + "DateOfBirth"; + /** Prefix for Element AttributeValue in an Xpath-expression */ + private static String IS_QUALIFIED_CERT_XPATH = + ATTRIBUTESTATEMENT_XPATH + + SAML + "Attribute[@AttributeName=\"isQualifiedCertificate\"]/" + + SAML + "AttributeValue"; + /** Prefix for Element AttributeValue in an Xpath-expression */ + private static String PUBLIC_AUTHORITY_XPATH = + ATTRIBUTESTATEMENT_XPATH + + SAML + "Attribute[@AttributeName=\"isPublicAuthority\"]/" + + SAML + "AttributeValue"; + /** Element samlAssertion represents the SAML:Assertion */ + private Element samlAssertion; + + /** + * Constructor + * @param samlAssertion samlpResponse the <code><samlp:Response></code> as a DOM element + */ + public AuthenticationDataAssertionParser(Element samlAssertion) { + this.samlAssertion = samlAssertion; + } + + /** + * Parses the <code><saml:Assertion></code>. + * @return <code>AuthenticationData</code> object + * @throws ParseException on any error + */ + public AuthenticationData parseAuthenticationData() + throws ParseException { + + try { + AuthenticationData authData = new AuthenticationData(); + //ÄNDERN: NUR der Identification-Teil + authData.setSamlAssertion(DOMUtils.serializeNode(samlAssertion)); + authData.setMajorVersion(new Integer( + XPathUtils.getAttributeValue(samlAssertion, MAJOR_VERSION_XPATH, "-1")).intValue()); + authData.setMinorVersion(new Integer( + XPathUtils.getAttributeValue(samlAssertion, MINOR_VERSION_XPATH, "-1")).intValue()); + authData.setAssertionID( + XPathUtils.getAttributeValue(samlAssertion, ASSERTION_ID_XPATH, "")); + authData.setIssuer( + XPathUtils.getAttributeValue(samlAssertion, ISSUER_XPATH, "")); + authData.setIssueInstant( + XPathUtils.getAttributeValue(samlAssertion, ISSUE_INSTANT_XPATH, "")); + String pkValue = XPathUtils.getElementValue(samlAssertion, PK_XPATH, ""); + if (XPathUtils.getAttributeValue(samlAssertion, NAME_QUALIFIER_XPATH, "").equalsIgnoreCase(URN_PREFIX_BPK)) { + authData.setBPK(pkValue); + } else { + authData.setWBPK(pkValue); + } + authData.setIdentificationValue( + XPathUtils.getElementValue(samlAssertion, IDENTIFICATION_VALUE_XPATH, "")); + authData.setIdentificationType( + XPathUtils.getElementValue(samlAssertion, IDENTIFICATION_TYPE_XPATH, "")); + authData.setGivenName( + XPathUtils.getElementValue(samlAssertion, GIVEN_NAME_XPATH, "")); + authData.setFamilyName( + XPathUtils.getElementValue(samlAssertion, FAMILY_NAME_XPATH, "")); + authData.setDateOfBirth( + XPathUtils.getElementValue(samlAssertion, DATE_OF_BIRTH_XPATH, "")); + authData.setQualifiedCertificate(BoolUtils.valueOf( + XPathUtils.getElementValue(samlAssertion, IS_QUALIFIED_CERT_XPATH, ""))); + String publicAuthority = + XPathUtils.getElementValue(samlAssertion, PUBLIC_AUTHORITY_XPATH, null); + if (publicAuthority == null) { + authData.setPublicAuthority(false); + authData.setPublicAuthorityCode(""); + } + else { + authData.setPublicAuthority(true); + if (! publicAuthority.equalsIgnoreCase("true")) + authData.setPublicAuthorityCode(publicAuthority); + } + return authData; + } + catch (Throwable t) { + throw new ParseException("parser.01", new Object[] { t.toString() }, t); + } + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/parser/SAMLResponseParser.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/parser/SAMLResponseParser.java new file mode 100644 index 000000000..9c50990cd --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/parser/SAMLResponseParser.java @@ -0,0 +1,115 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy.parser; + +import org.w3c.dom.Element; + +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.data.AuthenticationData; +import at.gv.egovernment.moa.id.data.SAMLStatus; +import at.gv.egovernment.moa.util.Constants; +import at.gv.egovernment.moa.util.XPathUtils; + +/** + * Parser for the <code><samlp:Response></code> returned by the + * <code>GetAuthenticationData</code> web service. + * @author Paul Ivancsics + * @version $Id$ + */ +public class SAMLResponseParser implements Constants { + /** Element containing the samlResponse */ + private Element samlResponse; + /** Xpath prefix for reaching SAMLP Namespaces */ + private static String SAMLP = SAMLP_PREFIX + ":"; + /** Xpath prefix for reaching SAML Namespaces */ + private static String SAML = SAML_PREFIX + ":"; + /** Xpath prefix for reaching PersonData Namespaces */ + private static String PR = PD_PREFIX + ":"; + /** Xpath expression for reaching the SAMLP:Response element */ + private static final String ROOT = + "/" + SAMLP + "Response/"; + /** Xpath expression for reaching the SAMLP:Status element */ + private static final String STATUS_XPATH = + ROOT + + SAMLP + "Status/"; + /** Xpath expression for reaching the SAMLP:StatusCode_Value attribute */ + private static final String STATUSCODE_XPATH = + STATUS_XPATH + + SAMLP + "StatusCode/@Value"; + /** Xpath expression for reaching the SAMLP:SubStatusCode_Value attribute */ + private static final String SUBSTATUSCODE_XPATH = + STATUS_XPATH + + SAMLP + "StatusCode/" + + SAMLP + "StatusCode/@Value"; + /** Xpath expression for reaching the SAMLP:StatusMessage element */ + private static final String STATUSMESSAGE_XPATH = + STATUS_XPATH + + SAMLP + "StatusMessage"; + /** Xpath expression for reaching the SAML:Assertion element */ + private static String ASSERTION_XPATH = + ROOT + + SAML + "Assertion"; + + /** + * Constructor + * @param samlResponse the <code><samlp:Response></code> as a DOM element + */ + public SAMLResponseParser(Element samlResponse) { + this.samlResponse = samlResponse; + } + + /** + * Parses the <code><samlp:StatusCode></code> from the <code><samlp:Response></code>. + * @return <code>AuthenticationData</code> object + * @throws ParseException on any parsing error + */ + public SAMLStatus parseStatusCode() + throws ParseException { + + SAMLStatus status = new SAMLStatus(); + try { + status.setStatusCode( + XPathUtils.getAttributeValue(samlResponse, STATUSCODE_XPATH, "")); + status.setSubStatusCode( + XPathUtils.getAttributeValue(samlResponse, SUBSTATUSCODE_XPATH, "")); + status.setStatusMessage( + XPathUtils.getElementValue(samlResponse, STATUSMESSAGE_XPATH, "")); + } + catch (Throwable t) { + throw new ParseException("parser.01", new Object[] { t.toString() }, t); + } + return status; + } + + /** + * Parses the <code><saml:Assertion></code> from the <code><samlp:Response></code>. + * @return <code>AuthenticationData</code> object + * @throws ParseException on any parsing error + */ + public AuthenticationData parseAuthenticationData() + throws ParseException { + + Element samlAssertion; + try { + samlAssertion = (Element)XPathUtils.selectSingleNode(samlResponse, ASSERTION_XPATH); + } + catch (Throwable t) { + throw new ParseException("parser.01", new Object[] { t.toString() }, t); + } + return new AuthenticationDataAssertionParser(samlAssertion).parseAuthenticationData(); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/servlet/ConfigurationServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/servlet/ConfigurationServlet.java new file mode 100644 index 000000000..38db17f10 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/servlet/ConfigurationServlet.java @@ -0,0 +1,86 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy.servlet; + +import java.io.IOException; +import java.text.DateFormat; +import java.util.Date; +import java.util.Locale; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import at.gv.egovernment.moa.id.proxy.MOAIDProxyInitializer; +import at.gv.egovernment.moa.id.util.HTTPRequestJSPForwarder; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.logging.Logger; + +/** + * Servlet requested for updating the MOA-ID Auth configuration from configuration file + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class ConfigurationServlet extends HttpServlet { + + /** + * Handle a HTTP GET request, used to indicated that the MOA + * configuration needs to be updated (reloaded). + * + * @see javax.servlet.http.HttpServlet#doGet(HttpServletRequest, HttpServletResponse) + */ + public void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + MOAIDMessageProvider msg = MOAIDMessageProvider.getInstance(); + try { + MOAIDProxyInitializer.initialize(); + + String message = msg.getMessage("config.00", new Object[] + { DateFormat.getTimeInstance(DateFormat.MEDIUM, Locale.GERMAN).format(new Date())} ); + Logger.info(message); + + HTTPRequestJSPForwarder.forwardNamed(message, "/message-proxy.jsp", getServletContext(), request, response); + } catch (Throwable t) { + String errorMessage = msg.getMessage("config.04", null); + Logger.error(errorMessage, t); + HTTPRequestJSPForwarder.forwardNamed(errorMessage, "/message-proxy.jsp", getServletContext(), request, response); + } + } + + /** + * Do the same as <code>doGet</code>. + * + * @see javax.servlet.http.HttpServlet#doPost(HttpServletRequest, HttpServletResponse) + */ + public void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + doGet(request, response); + } + +/** + * Calls the web application initializer. + * + * @see javax.servlet.Servlet#init(ServletConfig) + */ +public void init(ServletConfig servletConfig) throws ServletException { + super.init(servletConfig); +} + +}
\ No newline at end of file diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/servlet/ProxyException.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/servlet/ProxyException.java new file mode 100644 index 000000000..993f4b935 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/servlet/ProxyException.java @@ -0,0 +1,50 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy.servlet; + +import at.gv.egovernment.moa.id.MOAIDException; + +/** + * Exception thrown while proxying a request to the online application + * + * @author Paul Ivancsics + * @version $Id$ + */ +public class ProxyException extends MOAIDException { + + /** + * Constructor for ProxyException. + * @param messageId + * @param parameters + */ + public ProxyException(String messageId, Object[] parameters) { + super(messageId, parameters); + } + + /** + * Constructor for ProxyException. + * @param messageId + * @param parameters + * @param wrapped + */ + public ProxyException( + String messageId, + Object[] parameters, + Throwable wrapped) { + super(messageId, parameters, wrapped); + } + +} diff --git a/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/servlet/ProxyServlet.java b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/servlet/ProxyServlet.java new file mode 100644 index 000000000..6802005f1 --- /dev/null +++ b/id/server/idserverlib/src/main/java/at/gv/egovernment/moa/id/proxy/servlet/ProxyServlet.java @@ -0,0 +1,901 @@ +/* +* Copyright 2003 Federal Chancellery Austria +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package at.gv.egovernment.moa.id.proxy.servlet; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.HttpURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Vector; + +import javax.net.ssl.SSLSocketFactory; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.commons.lang.StringEscapeUtils; + +import at.gv.egovernment.moa.id.AuthenticationException; +import at.gv.egovernment.moa.id.BuildException; +import at.gv.egovernment.moa.id.MOAIDException; +import at.gv.egovernment.moa.id.ParseException; +import at.gv.egovernment.moa.id.ServiceException; +import at.gv.egovernment.moa.id.config.ConfigurationException; +import at.gv.egovernment.moa.id.config.ConnectionParameter; +import at.gv.egovernment.moa.id.config.proxy.ProxyConfigurationProvider; +import at.gv.egovernment.moa.id.config.proxy.OAConfiguration; +import at.gv.egovernment.moa.id.config.proxy.OAProxyParameter; +import at.gv.egovernment.moa.id.data.AuthenticationData; +import at.gv.egovernment.moa.id.data.CookieManager; +import at.gv.egovernment.moa.id.proxy.ConnectionBuilder; +import at.gv.egovernment.moa.id.proxy.ConnectionBuilderFactory; +import at.gv.egovernment.moa.id.proxy.LoginParameterResolver; +import at.gv.egovernment.moa.id.proxy.LoginParameterResolverException; +import at.gv.egovernment.moa.id.proxy.LoginParameterResolverFactory; +import at.gv.egovernment.moa.id.proxy.MOAIDProxyInitializer; +import at.gv.egovernment.moa.id.proxy.NotAllowedException; +import at.gv.egovernment.moa.id.proxy.invoke.GetAuthenticationDataInvoker; +import at.gv.egovernment.moa.id.util.MOAIDMessageProvider; +import at.gv.egovernment.moa.id.util.SSLUtils; +import at.gv.egovernment.moa.logging.Logger; +import at.gv.egovernment.moa.util.Base64Utils; + +/** + * Servlet requested for logging in at an online application, + * and then for proxying requests to the online application. + * @author Paul Ivancsics + * @version $Id$ + */ +public class ProxyServlet extends HttpServlet { + /** Name of the Parameter for the Target */ + private static final String PARAM_TARGET = "Target"; + /** Name of the Parameter for the SAMLArtifact */ + private static final String PARAM_SAMLARTIFACT = "SAMLArtifact"; + + /** Name of the Attribute for marking the session as authenticated*/ + private static final String ATT_AUTHDATAFETCHED = "AuthDataFetched"; + /** Name of the Attribute for the PublicURLPrefix */ + private static final String ATT_PUBLIC_URLPREFIX = "PublicURLPrefix"; + /** Name of the Attribute for the RealURLPrefix */ + private static final String ATT_REAL_URLPREFIX = "RealURLPrefix"; + /** Name of the Attribute for the SSLSocketFactory */ + private static final String ATT_SSL_SOCKET_FACTORY = "SSLSocketFactory"; + /** Name of the Attribute for the LoginHeaders */ + private static final String ATT_LOGIN_HEADERS = "LoginHeaders"; + /** Name of the Attribute for the LoginParameters */ + private static final String ATT_LOGIN_PARAMETERS = "LoginParameters"; + /** Name of the Attribute for the SAMLARTIFACT */ + private static final String ATT_SAML_ARTIFACT = "SamlArtifact"; + /** Name of the Attribute for the state of the browser request for login dialog*/ + private static final String ATT_BROWSERREQU = "BrowserLoginRequest"; + /** Name of the Attribute for the state of the browser request for login dialog*/ + private static final String ATT_OA_CONF = "oaConf"; + /** Name of the Attribute for the Logintype of the OnlineApplication*/ + private static final String ATT_OA_LOGINTYPE = "LoginType"; + /** Name of the Attribute for the number of the try to login into the OnlineApplication*/ + private static final String ATT_OA_LOGINTRY = "LoginTry"; + /** Maximum permitted login tries */ + private static final int MAX_OA_LOGINTRY = 3; + /** Name of the Attribute for authorization value for further connections*/ + private static final String ATT_OA_AUTHORIZATION_HEADER = "authorizationkey"; + /** Name of the Attribute for user binding */ + private static final String ATT_OA_USER_BINDING = "UserBinding"; + /** For extended internal debug messages */ + private static final boolean INTERNAL_DEBUG = false; + /** Message to be given if browser login failed */ + private static final String RET_401_MSG = "<html><head><title>Ein Fehler ist aufgetreten</title></head><body><h1>Fehler bei der Anmeldung</h1><p>Bei der Anmeldung ist ein Fehler aufgetreten.</p><p>Fehler bei der Anmeldung. <br>Prüfen Sie bitte ihre Berechtigung.<br><b>Abbruch durch den Benutzer.</b><br></p></body></html>"; + + /** + * @see javax.servlet.http.HttpServlet#service(HttpServletRequest, HttpServletResponse) + */ + protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { + + Logger.debug("getRequestURL:" + req.getRequestURL().toString()); + + String artifact = req.getParameter(PARAM_SAMLARTIFACT); + artifact = StringEscapeUtils.escapeHtml(artifact); + + try { + if (artifact != null) { + // check if SAML Artifact was already used in this session (in case of page reload) + HttpSession session = req.getSession(); + if (null != session && artifact.equals(session.getAttribute(ATT_SAML_ARTIFACT))) { + if (session.getAttribute(ATT_BROWSERREQU)==null) { + tunnelRequest(req, resp); + }else{ + login(req, resp); //login after browser login dialog + } + } else + // it is the first time that the SAML Artifact was used + login(req, resp); + } + else + tunnelRequest(req, resp); + } + catch (MOAIDException ex) { + handleError(ex.getMessage(), ex, req, resp); + } + catch (Throwable ex) { + handleError(ex.getMessage(), ex, req, resp); + } + } + + /** + * Login to online application at first call of servlet for a user session.<br/> + * <ul> + * <li>Acquires authentication data from the MOA-ID Auth component.</li> + * <li>Reads configuration data for the online application.</li> + * <li>Resolves login parameters.</li> + * <li>Sets up an SSLSocketFactory in case of a secure connection to the online application.</li> + * <li>For a stateless online application, stores data in the HttpSession.</li> + * <li>Tunnels the request to the online application.</li> + * </ul> + * @param req + * @param resp + * @throws ConfigurationException when wrong configuration is encountered + * @throws ProxyException when wrong configuration is encountered + * @throws BuildException while building the request for MOA-ID Auth + * @throws ServiceException while invoking MOA-ID Auth + * @throws ParseException while parsing the response from MOA-ID Auth + */ + private void login(HttpServletRequest req, HttpServletResponse resp) throws ConfigurationException, ProxyException, BuildException, ServiceException, ParseException, AuthenticationException { + + HttpSession session = req.getSession(); + String samlArtifact = ""; + Map loginHeaders = null; + Map loginParameters = null; + String publicURLPrefix = ""; + String realURLPrefix = ""; + SSLSocketFactory ssf = null; + String urlRequested = req.getRequestURL().toString(); + OAConfiguration oaConf = null; + String loginType = ""; + String binding = ""; + + if (session.getAttribute(ATT_BROWSERREQU)==null) { + + //@TODO Parameter + samlArtifact = req.getParameter(PARAM_SAMLARTIFACT); + Logger.debug("moa-id-proxy login " + PARAM_SAMLARTIFACT + ": " + samlArtifact); + // String target = req.getParameter(PARAM_TARGET); parameter given but not processed + // boolean targetprovided = req.getParameter(PARAM_TARGET) != null; + + // get authentication data from the MOA-ID Auth component + AuthenticationData authData; + try { + authData = new GetAuthenticationDataInvoker().getAuthenticationData(samlArtifact); + } catch (ServiceException ex) { + throw new ProxyException("proxy.14", new Object[] {ex.getMessage()}, ex); + } catch (ProxyException ex) { + throw new ProxyException("proxy.14", new Object[] {ex.getMessage()}, ex); + } + session.setAttribute(ATT_AUTHDATAFETCHED, "true"); + + // read configuration data + ProxyConfigurationProvider proxyConf = ProxyConfigurationProvider.getInstance(); + OAProxyParameter oaParam = proxyConf.getOnlineApplicationParameter(urlRequested); + if (oaParam == null) { + throw new ProxyException("proxy.02", new Object[] { urlRequested }); + } + publicURLPrefix = oaParam.getPublicURLPrefix(); + Logger.debug("OA: " + publicURLPrefix); + oaConf = oaParam.getOaConfiguration(); + ConnectionParameter oaConnParam = oaParam.getConnectionParameter(); + realURLPrefix = oaConnParam.getUrl(); + + // resolve login parameters to be forwarded to online application + LoginParameterResolver lpr = LoginParameterResolverFactory.getLoginParameterResolver(publicURLPrefix); + String clientIPAddress = req.getRemoteAddr(); + boolean businessService = oaParam.getBusinessService(); + try { + if (oaConf.getAuthType().equals(OAConfiguration.PARAM_AUTH)) { + loginParameters = lpr.getAuthenticationParameters(oaConf, authData, clientIPAddress, businessService, publicURLPrefix); + } else { + loginHeaders = lpr.getAuthenticationHeaders(oaConf, authData, clientIPAddress, businessService, publicURLPrefix); + for (Iterator iter = loginHeaders.keySet().iterator(); iter.hasNext();) { + //extract user-defined bindingValue + String headerKey = (String) iter.next(); + String headerKeyValue = (String) loginHeaders.get(headerKey); + if (headerKey.equalsIgnoreCase("binding")) { + binding = (String) loginHeaders.get(headerKey); + } + for (int i = 1; i <= 3; i++) { + if (headerKey.equalsIgnoreCase("param" + i)) { + int sep = headerKeyValue.indexOf("="); + if (sep>-1) { + if (sep>0) { + String value = ""; + if (headerKeyValue.length()>sep+1) value = headerKeyValue.substring(sep+1); + if (loginParameters == null) loginParameters = new HashMap(); + loginParameters.put(headerKeyValue.substring(0,sep) , value); + } + } else { + loginParameters.put(headerKey, ""); + } + } + } + } + loginHeaders.remove("binding"); + loginHeaders.remove("param1"); + loginHeaders.remove("param2"); + loginHeaders.remove("param3"); + } + } catch (LoginParameterResolverException ex) { + throw new ProxyException("proxy.13", new Object[] { publicURLPrefix }); + } catch (NotAllowedException e) { + throw new ProxyException("proxy.15", new Object[] { }); + } + + // setup SSLSocketFactory for communication with the online application + if (oaConnParam.isHTTPSURL()) { + try { + ssf = SSLUtils.getSSLSocketFactory(proxyConf, oaConnParam); + } catch (Throwable ex) { + throw new ProxyException( + "proxy.05", + new Object[] { oaConnParam.getUrl(), ex.toString()}, + ex); + } + } + + // for stateless online application, store data in HttpSession + loginType = oaConf.getLoginType(); + if ("".equalsIgnoreCase(binding)) { + binding = oaConf.getBinding(); + if ("".equalsIgnoreCase(binding)) binding = "full"; + } + Logger.debug("Login type: " + loginType); + if (loginType.equals(OAConfiguration.LOGINTYPE_STATELESS)) { + int sessionTimeOut = oaParam.getSessionTimeOut(); + if (sessionTimeOut == 0) + sessionTimeOut = 60 * 60; // default 1 h + + session.setMaxInactiveInterval(sessionTimeOut); + session.setAttribute(ATT_PUBLIC_URLPREFIX, publicURLPrefix); + session.setAttribute(ATT_REAL_URLPREFIX, realURLPrefix); + session.setAttribute(ATT_SSL_SOCKET_FACTORY, ssf); + session.setAttribute(ATT_LOGIN_HEADERS, loginHeaders); + session.setAttribute(ATT_LOGIN_PARAMETERS, loginParameters); + session.setAttribute(ATT_SAML_ARTIFACT, samlArtifact); + session.setAttribute(ATT_OA_CONF, oaConf); + session.setAttribute(ATT_OA_LOGINTYPE, loginType); + session.setAttribute(ATT_OA_USER_BINDING, binding); + session.removeAttribute(ATT_BROWSERREQU); + session.removeAttribute(ATT_OA_AUTHORIZATION_HEADER); + session.removeAttribute(ATT_OA_LOGINTRY); + Logger.debug("moa-id-proxy: HTTPSession " + session.getId() + " angelegt"); + } + + } else { + loginHeaders = (Map) session.getAttribute(ATT_LOGIN_HEADERS); + publicURLPrefix = (String) session.getAttribute(ATT_PUBLIC_URLPREFIX); + realURLPrefix = (String) session.getAttribute(ATT_REAL_URLPREFIX); + ssf = (SSLSocketFactory) session.getAttribute(ATT_SSL_SOCKET_FACTORY); + loginHeaders = (Map) session.getAttribute(ATT_LOGIN_HEADERS); + loginParameters = (Map) session.getAttribute(ATT_LOGIN_PARAMETERS); + samlArtifact = (String) session.getAttribute(ATT_SAML_ARTIFACT); + oaConf = (OAConfiguration) session.getAttribute(ATT_OA_CONF); + loginType = (String) session.getAttribute(ATT_OA_LOGINTYPE); + binding = (String) session.getAttribute(ATT_OA_USER_BINDING); + session.removeAttribute(ATT_BROWSERREQU); + Logger.debug("moa-id-proxy: HTTPSession " + session.getId() + " aufgenommen"); + } + + try { + int respcode = 0; + + // tunnel request to the online application + respcode = tunnelRequest(req, resp, loginHeaders, loginParameters, publicURLPrefix, realURLPrefix, ssf, binding); + if (respcode == 401) { + if (OAConfiguration.BINDUNG_FULL.equals(binding) && oaConf.getLoginType().equals(OAConfiguration.LOGINTYPE_STATELESS)) { + throw new ProxyException("proxy.12", new Object[] { realURLPrefix }); + } + } + } catch (ProxyException ex) { + throw new ProxyException("proxy.12", new Object[] { realURLPrefix }); + } catch (Throwable ex) { + throw new ProxyException("proxy.04", new Object[] { urlRequested, ex.toString()}, ex); + } + } + + /** + * Tunnels a request to the stateless online application using data stored in the HTTP session. + * @param req HTTP request + * @param resp HTTP response + * @throws IOException if an I/O error occurs + */ + private void tunnelRequest(HttpServletRequest req, HttpServletResponse resp) throws ProxyException, IOException { + + //Logger.debug("Tunnel request (stateless)"); + HttpSession session = req.getSession(false); + + if (session == null) + throw new ProxyException("proxy.07", null); + String publicURLPrefix = (String) session.getAttribute(ATT_PUBLIC_URLPREFIX); + //A session is automatically created when forwarded 1st time to errorpage-proxy.jsp (with the handleError method) + //additional check if publicURLPrefix is OK, if not throw an Exception + if (publicURLPrefix == null) + throw new ProxyException("proxy.07", null); + + String realURLPrefix = (String) session.getAttribute(ATT_REAL_URLPREFIX); + SSLSocketFactory ssf = (SSLSocketFactory) session.getAttribute(ATT_SSL_SOCKET_FACTORY); + Map loginHeaders = (Map) session.getAttribute(ATT_LOGIN_HEADERS); + Map loginParameters = (Map) session.getAttribute(ATT_LOGIN_PARAMETERS); + String binding = (String) session.getAttribute(ATT_OA_USER_BINDING); + if (publicURLPrefix == null || realURLPrefix == null) + throw new ProxyException("proxy.08", new Object[] { req.getRequestURL().toString()}); + + int respcode = tunnelRequest(req, resp, loginHeaders, loginParameters, publicURLPrefix, realURLPrefix, ssf, binding); + if (respcode == -401) // #tries to login exceeded + throw new ProxyException("proxy.16", new Object[] {realURLPrefix, Integer.toString(MAX_OA_LOGINTRY)}); + } + +/** + * Tunnels a request to the online application using given URL mapping and SSLSocketFactory. + * This method returns the ResponseCode of the request to the online application. + * @param req HTTP request + * @param resp HTTP response + * @param loginHeaders header field/values to be inserted for purposes of authentication; + * may be <code>null</code> + * @param loginParameters parameter name/values to be inserted for purposes of authentication; + * may be <code>null</code> + * @param publicURLPrefix prefix of request URL to be substituted for the <code>realURLPrefix</code> + * @param realURLPrefix prefix of online application URL to substitute the <code>publicURLPrefix</code> + * @param ssf SSLSocketFactory to use + * @throws IOException if an I/O error occurs + */ +private int tunnelRequest(HttpServletRequest req, HttpServletResponse resp, Map loginHeaders, Map loginParameters, String publicURLPrefix, String realURLPrefix, SSLSocketFactory ssf, String binding) + throws IOException { + + String originBinding = binding; + String browserUserID = ""; + String browserPassword = ""; + //URL url = new URL(realURLPrefix); + //String realURLHost = url.getHost(); + if (INTERNAL_DEBUG && !binding.equals("")) Logger.debug("Binding: " + binding); + + // collect headers from request + Map headers = new HashMap(); + for (Enumeration enu = req.getHeaderNames(); enu.hasMoreElements();) { + String headerKey = (String) enu.nextElement(); + String headerKeyValue = req.getHeader(headerKey); + if (INTERNAL_DEBUG) Logger.debug("Incoming:" + headerKey + "=" + headerKeyValue); + //Analyze Basic-Auth-Headers from the client + if (headerKey.equalsIgnoreCase("Authorization")) { + if (headerKeyValue.substring(0,6).equalsIgnoreCase("Basic ")) { + String credentials = headerKeyValue.substring(6); + byte [] bplaintextcredentials = Base64Utils. decode(credentials, true); + String plaintextcredentials = new String(bplaintextcredentials); + browserUserID = plaintextcredentials.substring(0,plaintextcredentials.indexOf(":")); + browserPassword = plaintextcredentials.substring(plaintextcredentials.indexOf(":")+1); + //deactivate following line for security + //if (INTERNAL_DEBUG) Logger.debug("Analyzing authorization-header from browser: " + headerKeyValue + "gives UN:PW=" + browserUserID + ":" + browserPassword ); + } + if (headerKeyValue.substring(0,9).equalsIgnoreCase("Negotiate")) { + //deactivate following line for security + //if (INTERNAL_DEBUG) Logger.debug("Analyzing authorization-header from browser: Found NTLM Aut.: " + headerKeyValue + "gives UN:PW=" + browserUserID + ":" + browserPassword ); + } + } + else + { + /* Headers MUST NOT be repaced according to our Spec. + if (headerKey.equalsIgnoreCase("Host")) { + headerKeyValue = realURLHost; + //headerKeyValue= realURLPrefix.substring(hoststartpos); + if (INTERNAL_DEBUG) Logger.debug("replaced:" + headerKey + "=" + headerKeyValue); + } + */ + headers.put(headerKey, headerKeyValue); + } + } + + + // collect login headers, possibly overwriting headers from request + String authorizationvalue=""; + if (req.getSession().getAttribute(ATT_OA_AUTHORIZATION_HEADER)==null) { + + if (OAConfiguration.BINDUNG_NOMATCH.equals(binding)) { + int loginTry = getLoginTry(req); + Logger.debug("Binding: mode = " + OAConfiguration.BINDUNG_NOMATCH + "(try #" + Integer.toString(loginTry) + ")"); + if (loginTry==1) { + binding = OAConfiguration.BINDUNG_FULL; + } else { + binding = OAConfiguration.BINDUNG_USERNAME; + } + } + + /* Soll auch bei anderen bindings zuerst ein passwort probiert werden können: + //if we have the first Login-Try and we have Binding to Username and a predefined Password we try this one first + // full binding will be covered by next block + if (loginTry==1 && !OAConfiguration.BINDUNG_FULL.equals(binding)) { + //1st try: if we have a password, try this one first + for (Iterator iter = loginHeaders.keySet().iterator(); iter.hasNext();) { + String headerKey = (String) iter.next(); + String headerKeyValue = (String) loginHeaders.get(headerKey); + if (isBasicAuthenticationHeader(headerKey, headerKeyValue)) { + String credentials = headerKeyValue.substring(6); + byte [] bplaintextcredentials = Base64Utils.decode(credentials, true); + String plaintextcredentials = new String(bplaintextcredentials); + String password = plaintextcredentials.substring(plaintextcredentials.indexOf(":")+1); + if (password!=null && !password.equals("")) { + Logger.debug("Binding: found predefined password. Trying full binding first"); + binding = OAConfiguration.BINDUNG_FULL; + break; + } + } + } + } + */ + + + + //we have a connection with not having logged on + if (loginHeaders != null && (browserPassword.length()!=0 || browserUserID.length()!=0 || OAConfiguration.BINDUNG_FULL.equals(binding))) { + for (Iterator iter = loginHeaders.keySet().iterator(); iter.hasNext();) { + String headerKey = (String) iter.next(); + String headerKeyValue = (String) loginHeaders.get(headerKey); + //customize loginheaders if necessary + if (isBasicAuthenticationHeader(headerKey, headerKeyValue)) + { + if (OAConfiguration.BINDUNG_FULL.equals(binding)) { + authorizationvalue = headerKeyValue; + Logger.debug("Binding: full binding to user established"); + } else { + String credentials = headerKeyValue.substring(6); + byte [] bplaintextcredentials = Base64Utils.decode(credentials, true); + String plaintextcredentials = new String(bplaintextcredentials); + String userID = plaintextcredentials.substring(0,plaintextcredentials.indexOf(":")); + String password = plaintextcredentials.substring(plaintextcredentials.indexOf(":")+1); + String userIDPassword = ":"; + if (OAConfiguration.BINDUNG_USERNAME.equals(binding)) { + Logger.debug("Binding: Access with necessary binding to user"); + userIDPassword = userID + ":" + browserPassword; + } else if (OAConfiguration.BINDUNG_NONE.equals(binding)) { + Logger.debug("Binding: Access without binding to user"); + //If first time + if (browserUserID.length()==0) browserUserID = userID; + if (browserPassword.length()==0) browserPassword = password; + userIDPassword = browserUserID + ":" + browserPassword; + } else { + userIDPassword = userID + ":" + password; + } + credentials = Base64Utils.encode(userIDPassword.getBytes()); + authorizationvalue = "Basic " + credentials; + headerKeyValue = authorizationvalue; + } + } + headers.put(headerKey, headerKeyValue); + } + } + }else{ + //if OA needs Authorization header in each further request + authorizationvalue = (String) req.getSession().getAttribute(ATT_OA_AUTHORIZATION_HEADER); + if (loginHeaders != null) headers.put("Authorization", authorizationvalue); + } + + + Vector parameters = new Vector(); + for (Enumeration enu = req.getParameterNames(); enu.hasMoreElements();) { + String paramName = (String) enu.nextElement(); + if (!(paramName.equals(PARAM_SAMLARTIFACT) || paramName.equals(PARAM_TARGET))) { + if (INTERNAL_DEBUG) Logger.debug("Req Parameter-put: " + paramName + ":" + req.getParameter(paramName)); + String parameter[] = new String[2]; + parameter[0]= paramName; + parameter[1]= req.getParameter(paramName); + parameters.add(parameter); + } + } + // collect login parameters, possibly overwriting parameters from request + if (loginParameters != null) { + for (Iterator iter = loginParameters.keySet().iterator(); iter.hasNext();) { + String paramName = (String) iter.next(); + if (!(paramName.equals(PARAM_SAMLARTIFACT) || paramName.equals(PARAM_TARGET))) { + if (INTERNAL_DEBUG) Logger.debug("Req Login-Parameter-put: " + paramName + ":" + loginParameters.get(paramName)); + String parameter[] = new String[2]; + parameter[0]= paramName; + parameter[1]= (String) loginParameters.get(paramName); + parameters.add(parameter); + } + } + } + + ConnectionBuilder cb = ConnectionBuilderFactory.getConnectionBuilder(publicURLPrefix); + HttpURLConnection conn = cb.buildConnection(req, publicURLPrefix, realURLPrefix, ssf, parameters); + + // set headers as request properties of URLConnection + for (Iterator iter = headers.keySet().iterator(); iter.hasNext();) { + String headerKey = (String) iter.next(); + String headerValue = (String) headers.get(headerKey); + String LogStr = "Req header " + headerKey + ": " + headers.get(headerKey); + if (isBasicAuthenticationHeader(headerKey, headerValue)) { + String credentials = headerValue.substring(6); + byte [] bplaintextcredentials = Base64Utils. decode(credentials, true); + String plaintextcredentials = new String(bplaintextcredentials); + String uid = plaintextcredentials.substring(0,plaintextcredentials.indexOf(":")); + String pwd = plaintextcredentials.substring(plaintextcredentials.indexOf(":")+1); + //Sollte AuthorizationInfo vom HTTPClient benutzt werden: cb.addBasicAuthorization(publicURLPrefix, uid, pwd); + //deactivate following line for security + //if (INTERNAL_DEBUG && Logger.isDebugEnabled()) LogStr = LogStr + " >UserID:Password< >" + uid + ":" + pwd + "<"; + } + conn.setRequestProperty(headerKey, headerValue); + if (INTERNAL_DEBUG) Logger.debug(LogStr); + } + + StringWriter sb = new StringWriter(); + + // Write out parameters into output stream of URLConnection. + // On GET request, do not send parameters in any case, + // otherwise HttpURLConnection would send a POST. + if (!"get".equalsIgnoreCase(req.getMethod()) && !parameters.isEmpty()) { + boolean firstParam = true; + String parameter[] = new String[2]; + for (Iterator iter = parameters.iterator(); iter.hasNext();) { + parameter = (String[]) iter.next(); + String paramName = parameter[0]; + String paramValue = parameter[1]; + if (firstParam) + firstParam = false; + else + sb.write("&"); + sb.write(paramName); + sb.write("="); + sb.write(paramValue); + if (INTERNAL_DEBUG) Logger.debug("Req param " + paramName + ": " + paramValue); + } + } + + // For WebDAV and POST: copy content + if (!"get".equalsIgnoreCase(req.getMethod())) { + if (INTERNAL_DEBUG && !"post".equalsIgnoreCase(req.getMethod())) Logger.debug("---- WEBDAV ---- copying content"); + try { + OutputStream out = conn.getOutputStream(); + InputStream in = req.getInputStream(); + if (!parameters.isEmpty()) out.write(sb.toString().getBytes()); //Parameter nicht mehr mittels Printwriter schreiben + copyStream(in, out, null, req.getMethod()); + out.flush(); + out.close(); + } catch (IOException e) { + if (!"post".equalsIgnoreCase(req.getMethod())) + Logger.debug("---- WEBDAV ---- streamcopy problem"); + else + Logger.debug("---- POST ---- streamcopy problem"); + } + } + + // connect + if (INTERNAL_DEBUG) Logger.debug("Connect Request"); + conn.connect(); + if (INTERNAL_DEBUG) Logger.debug("Connect Response"); + + // check login tries + if (conn.getResponseCode()==HttpURLConnection.HTTP_UNAUTHORIZED) { + int loginTry = getLoginTry(req); + req.getSession().setAttribute(ATT_OA_LOGINTRY, Integer.toString(loginTry)); + if (loginTry > MAX_OA_LOGINTRY) { + Logger.debug("Found 401 UNAUTHORIZED, maximum tries exceeded; leaving..."); + cb.disconnect(conn); + return -401; + } + } + + + + if (conn.getResponseCode()==HttpURLConnection.HTTP_UNAUTHORIZED && OAConfiguration.BINDUNG_FULL.equals(originBinding)) { + Logger.debug("Found 401 UNAUTHORIZED, leaving..."); + cb.disconnect(conn); + return conn.getResponseCode(); + } + + + resp.setStatus(conn.getResponseCode()); + //Issue by Gregor Karlinger - content type was annotated twice + //resp.setContentType(conn.getContentType()); + + if (loginHeaders != null && (conn.getResponseCode()==HttpURLConnection.HTTP_OK || conn.getResponseCode()==HttpURLConnection.HTTP_MOVED_TEMP) && req.getSession().getAttribute(ATT_OA_AUTHORIZATION_HEADER)==null) { + req.getSession().setAttribute(ATT_OA_AUTHORIZATION_HEADER, authorizationvalue); + Logger.debug("Login OK. Saving authorization header to remember in further requests"); + } + + // Read response headers + // Omit response header "content-length" if response header "Transfer-encoding: chunked" is set. + // Otherwise, the connection will not be kept alive, resulting in subsequent missing requests. + // See JavaDoc of javax.servlet.http.HttpServlet: + // When using HTTP 1.1 chunked encoding (which means that the response has a Transfer-Encoding header), do not set the Content-Length header. + Vector respHeaders = new Vector(); + + boolean chunked = false; + String contentLengthKey = null; + String transferEncodingKey = null; + int i = 1; + String headerKey; + String loginType = (String) req.getSession().getAttribute(ATT_OA_LOGINTYPE); + while ((headerKey = conn.getHeaderFieldKey(i)) != null) { + String headerValue = conn.getHeaderField(i); + // Überschrift im Browser-Passworteingabedialog setzen (sonst ist der reale host eingetragen) + if (headerKey.equalsIgnoreCase("WWW-Authenticate") && headerValue.startsWith("Basic realm=\"")) { + headerValue = "Basic realm=\"" + publicURLPrefix + "\""; + if (OAConfiguration.BINDUNG_USERNAME.equals(originBinding) || OAConfiguration.BINDUNG_NOMATCH.equals(originBinding)) { + headerValue = "Basic realm=\"Bitte Passwort eingeben\""; + } else if (OAConfiguration.BINDUNG_NONE.equals(originBinding)) { + headerValue = "Basic realm=\"Bitte Benutzername und Passwort eingeben\""; + } + } + String respHeader[] = new String[2]; + if ((conn.getResponseCode()==HttpURLConnection.HTTP_UNAUTHORIZED) && headerKey.equalsIgnoreCase("content-length")) { + //alter the unauthorized message with template for login + //TODO: supply a special login form on unauthorized messages with bindings!=full + headerValue = Integer.toString(RET_401_MSG.length()); + } + respHeader[0]= headerKey; + respHeader[1]= headerValue; + + if (!(OAConfiguration.BINDUNG_FULL.equals(originBinding) && OAConfiguration.LOGINTYPE_STATELESS.equals(loginType) && headerKey.equalsIgnoreCase("WWW-Authenticate") && headerValue.startsWith("Basic realm=\""))) { + respHeaders.add(respHeader); + if (INTERNAL_DEBUG) Logger.debug("Resp header " + headerKey + ": " + headerValue); + } else { + Logger.debug("Resp header ---REMOVED--- " + headerKey + ": " + headerValue); + } + if (isTransferEncodingChunkedHeader(headerKey, headerValue) || "content-length".equalsIgnoreCase(headerKey)) { + respHeaders.remove(respHeader); + Logger.debug("Resp header " + headerKey + " REMOVED"); + } + + i++; + } + + + String headerValue; + String respHeader[] = new String[2]; + + //write out all Responseheaders + for (Iterator iter = respHeaders.iterator(); iter.hasNext();) { + respHeader = (String[]) iter.next(); + headerKey = respHeader[0]; + headerValue = respHeader[1]; + resp.addHeader(headerKey, headerValue); + } + + //Logger.debug(">>>> Copy Content"); + //Logger.debug(" from ()" + conn.getURL()); + //Logger.debug(" to (" + req.getRemoteAddr() + ":"+ ") " +req.getRequestURL()); + + // read response stream + Logger.debug("Resp from " + conn.getURL().toString() + ": status " + conn.getResponseCode()); + // Load content unless the server lets us know that the content is NOT MODIFIED... + if (conn.getResponseCode()!=HttpURLConnection.HTTP_NOT_MODIFIED ) { + BufferedInputStream respIn = new BufferedInputStream(conn.getInputStream()); + //Logger.debug("Got Inputstream"); + BufferedOutputStream respOut = new BufferedOutputStream(resp.getOutputStream()); + //Logger.debug("Got Outputstream"); + + byte [] buffer = new byte[4096]; + if (respOut != null) { + int bytesRead; + while ((bytesRead = respIn.read(buffer)) >= 0) { + if (conn.getResponseCode()!=HttpURLConnection.HTTP_UNAUTHORIZED) respOut.write(buffer, 0, bytesRead); + } + } else { + while (respIn.read(buffer) >= 0); + } + + + /* + int ch; + StringBuffer strBuf = new StringBuffer(""); + while ((ch = respIn.read()) >= 0) { + if (conn.getResponseCode()!=HttpURLConnection.HTTP_UNAUTHORIZED) respOut.write(ch); + strBuf.append((char)ch); + } + Logger.debug("Resp Content:"); + if (strBuf.toString().length()>500) + Logger.debug(strBuf.toString().substring(0,500)); + else + Logger.debug(strBuf.toString()); + */ + + + if (conn.getResponseCode()==HttpURLConnection.HTTP_UNAUTHORIZED) { + respOut.write(RET_401_MSG.getBytes()); + } + respOut.flush(); + respOut.close(); + respIn.close(); + if (conn.getResponseCode()==HttpURLConnection.HTTP_UNAUTHORIZED) { + Logger.debug("Found 401 UNAUTHORIZED..."); + cb.disconnect(conn); + return conn.getResponseCode(); + } + } else { + //if (conn.getResponseCode()==HttpURLConnection.HTTP_NOT_MODIFIED) + Logger.debug("Found 304 NOT MODIFIED..."); + } + + cb.disconnect(conn); + Logger.debug("Request done"); + + return conn.getResponseCode(); +} + +/** + * Gets the current amount of the login try at the online application + * + * @param req the HttpServletRequest + * @return the number off the current login try + */ +private int getLoginTry(HttpServletRequest req) { + String oa_loginTry = (String) req.getSession().getAttribute(ATT_OA_LOGINTRY); + int loginTry = 1; + if (oa_loginTry!=null) loginTry = Integer.parseInt(oa_loginTry)+1; + return loginTry; +} +/** + * Determines whether a HTTP header is a basic authentication header of the kind "Authorization: Basic ..." + * + * @param headerKey header name + * @param headerValue header value + * @return true for a basic authentication header + */ +private boolean isBasicAuthenticationHeader(String headerKey, String headerValue) { + if (!"authorization".equalsIgnoreCase(headerKey)) + return false; + if (headerValue.length() < "basic".length()) + return false; + String authenticationSchema = headerValue.substring(0, "basic".length()); + return "basic".equalsIgnoreCase(authenticationSchema); +} +/** + * Determines whether a basic authentication header of the kind "Authorization: Basic ..." + * is included in a HTTP request + * @param req HTTP request + * @return true for a basic authentication header provided + */ +private boolean isBasicAuthenticationHeaderProvided(HttpServletRequest req) { + for (Enumeration enu = req.getHeaderNames(); enu.hasMoreElements();) { + String headerKey = (String) enu.nextElement(); + String headerValue = req.getHeader(headerKey); + if (isBasicAuthenticationHeader(headerKey, headerValue)) + return true; + } + return false; +} +/** + * Determines whether a HTTP header is "Transfer-encoding" header with value containing "chunked" + * + * @param headerKey header name + * @param headerValue header value + * @return true for a "Transfer-encoding: chunked" header + */ +private boolean isTransferEncodingChunkedHeader(String headerKey, String headerValue) { + if (!"transfer-encoding".equalsIgnoreCase(headerKey)) + return false; + return headerValue.indexOf("chunked") >= 0 || headerValue.indexOf("Chunked") >= 0 || headerValue.indexOf("CHUNKED") >= 0; +} + +/** + * Calls the web application initializer. + * + * @see javax.servlet.Servlet#init(ServletConfig) + */ +public void init(ServletConfig servletConfig) throws ServletException { + super.init(servletConfig); + try { + MOAIDProxyInitializer.initialize(); + Logger.info(MOAIDMessageProvider.getInstance().getMessage("proxy.00", null)); + } + catch (Exception ex) { + Logger.fatal(MOAIDMessageProvider.getInstance().getMessage("proxy.06", null), ex); + throw new ServletException(ex); + } +} + +/** + * Handles an error. <br> + * <ul> + * <li>Logs the error</li> + * <li>Places error message and exception thrown into the request + * as request attributes (to be used by <code>"/errorpage-proxy.jsp"</code>)</li> + * <li>Sets HTTP status 500 (internal server error)</li> + * </ul> + * + * @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) { + + + 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"); + } + + //forward this to errorpage-proxy.jsp where the HTML error page is generated + ServletContext context = getServletContext(); + RequestDispatcher dispatcher = context.getRequestDispatcher("/errorpage-proxy.jsp"); + try { + dispatcher.forward(req, resp); + } catch (ServletException e) { + Logger.error(e); + } catch (IOException e) { + Logger.error(e); + } + +} + + +// * taken from iaik.utils.util.copyStream: +/** + * Reads all data (until EOF is reached) from the given source to the + * destination stream. If the destination stream is null, all data is dropped. + * It uses the given buffer to read data and forward it. If the buffer is + * null, this method allocates a buffer. + * + * @param source The stream providing the data. + * @param destination The stream that takes the data. If this is null, all + * data from source will be read and discarded. + * @param buffer The buffer to use for forwarding. If it is null, the method + * allocates a buffer. + * @exception IOException If reading from the source or writing to the + * destination fails. + */ +private static void copyStream(InputStream source, OutputStream destination, byte[] buffer, String method) throws IOException { + if (source == null) { + throw new NullPointerException("Argument \"source\" must not be null."); + } + if (buffer == null) { + buffer = new byte[4096]; + } + + if (destination != null) { + int bytesRead; + while ((bytesRead = source.read(buffer)) >= 0) { + destination.write(buffer, 0, bytesRead); + //if (method.equalsIgnoreCase("POST")) Logger.debug(buffer.toString()); + } + } else { + while (source.read(buffer) >= 0); + } +} + + +} |