aboutsummaryrefslogtreecommitdiff
path: root/id.server/src/at/gv/egovernment/moa/id/proxy/servlet/ProxyServlet.java
diff options
context:
space:
mode:
Diffstat (limited to 'id.server/src/at/gv/egovernment/moa/id/proxy/servlet/ProxyServlet.java')
-rw-r--r--id.server/src/at/gv/egovernment/moa/id/proxy/servlet/ProxyServlet.java537
1 files changed, 0 insertions, 537 deletions
diff --git a/id.server/src/at/gv/egovernment/moa/id/proxy/servlet/ProxyServlet.java b/id.server/src/at/gv/egovernment/moa/id/proxy/servlet/ProxyServlet.java
deleted file mode 100644
index 362849fb1..000000000
--- a/id.server/src/at/gv/egovernment/moa/id/proxy/servlet/ProxyServlet.java
+++ /dev/null
@@ -1,537 +0,0 @@
-package at.gv.egovernment.moa.id.proxy.servlet;
-
-import java.io.BufferedInputStream;
-import java.io.BufferedOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.net.HttpURLConnection;
-import java.net.URLEncoder;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-
-import javax.net.ssl.SSLSocketFactory;
-import javax.servlet.ServletConfig;
-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 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.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 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";
-
- /**
- * @see javax.servlet.http.HttpServlet#service(HttpServletRequest, HttpServletResponse)
- */
- protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-
- Logger.debug("getRequestURL:" + req.getRequestURL().toString());
- try {
- if (req.getParameter(PARAM_SAMLARTIFACT) != null && req.getParameter(PARAM_TARGET) != null)
- login(req, resp);
- else
- tunnelRequest(req, resp);
- }
- catch (MOAIDException ex) {
- handleError(resp, ex.toString(), ex);
- }
- catch (Throwable ex) {
- handleError(resp, ex.toString(), ex);
- }
- }
-
- /**
- * 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 {
-
- String 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
-
- // get authentication data from the MOA-ID Auth component
- AuthenticationData authData = new GetAuthenticationDataInvoker().getAuthenticationData(samlArtifact);
-
- String urlRequested = req.getRequestURL().toString();
-
- // read configuration data
- ProxyConfigurationProvider proxyConf = ProxyConfigurationProvider.getInstance();
- OAProxyParameter oaParam = proxyConf.getOnlineApplicationParameter(urlRequested);
- if (oaParam == null) {
- throw new ProxyException("proxy.02", new Object[] { urlRequested });
- }
- String publicURLPrefix = oaParam.getPublicURLPrefix();
- Logger.debug("OA: " + publicURLPrefix);
- OAConfiguration oaConf = oaParam.getOaConfiguration();
- ConnectionParameter oaConnParam = oaParam.getConnectionParameter();
- String realURLPrefix = oaConnParam.getUrl();
-
- // resolve login parameters to be forwarded to online application
- LoginParameterResolver lpr = LoginParameterResolverFactory.getLoginParameterResolver(publicURLPrefix);
- String clientIPAddress = req.getRemoteAddr();
- Map loginHeaders = null;
- Map loginParameters = null;
- try {
- if (oaConf.getAuthType().equals(OAConfiguration.PARAM_AUTH))
- loginParameters = lpr.getAuthenticationParameters(oaConf, authData, clientIPAddress);
- else
- loginHeaders = lpr.getAuthenticationHeaders(oaConf, authData, clientIPAddress);
-
- } catch (LoginParameterResolverException ex) {
- throw new ProxyException("proxy.13", new Object[] { publicURLPrefix });
- }
-
- // setup SSLSocketFactory for communication with the online application
- SSLSocketFactory ssf = null;
- if (oaConnParam.isHTTPSURL()) {
- try {
- ssf = SSLUtils.getSSLSocketFactory(proxyConf, oaConnParam);
- }
- catch (Throwable ex) {
- throw new ProxyException("proxy.05", new Object[] { oaConnParam.getUrl(), ex.toString()}, ex);
- }
- }
-
- try {
- // for stateless online application, store data in HttpSession
- String loginType = oaConf.getLoginType();
- Logger.debug("Login type: " + loginType);
- if (loginType.equals(OAConfiguration.LOGINTYPE_STATELESS)) {
- HttpSession session = req.getSession();
- 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);
- Logger.debug("moa-id-proxy: HTTPSession angelegt");
- }
-
- // tunnel request to the online application
- int respcode = tunnelRequest(req, resp, loginHeaders, loginParameters, publicURLPrefix, realURLPrefix, ssf);
- if (respcode == 401)
- {
- Logger.debug("Got 401, trying again");
-
- respcode = tunnelRequest(req, resp, loginHeaders, loginParameters, publicURLPrefix, realURLPrefix, ssf);
- if (respcode == 401)
- 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);
- 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);
- 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);
- if (respcode == 401)
- {
- Logger.debug("Got 401, trying again");
- respcode = tunnelRequest(req, resp, loginHeaders, loginParameters, publicURLPrefix, realURLPrefix, ssf);
- if (respcode == 401)
- throw new ProxyException("proxy.12", new Object[] { realURLPrefix});
- }
- }
-
-/**
- * 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)
- throws IOException {
-
- // collect headers from request
- Map headers = new HashMap();
- for (Enumeration enum = req.getHeaderNames(); enum.hasMoreElements();) {
- String headerKey = (String) enum.nextElement();
- //We ignore any Basic-Auth-Headers from the client
- if (headerKey.equalsIgnoreCase("Authorization"))
- { Logger.debug("Ignoring authorization-header from browser: " +req.getHeader(headerKey) );
- }
- else
- headers.put(headerKey, req.getHeader(headerKey));
- }
- // collect login headers, possibly overwriting headers from request
- if (loginHeaders != null) {
- for (Iterator iter = loginHeaders.keySet().iterator(); iter.hasNext();) {
- String headerKey = (String) iter.next();
- headers.put(headerKey, loginHeaders.get(headerKey));
- }
- }
- // collect parameters from request
- Map parameters = new HashMap();
- for (Enumeration enum = req.getParameterNames(); enum.hasMoreElements();) {
- String paramName = (String) enum.nextElement();
- parameters.put(paramName, req.getParameter(paramName));
- }
- // collect login parameters, possibly overwriting parameters from request
- if (loginParameters != null) {
- for (Iterator iter = loginParameters.keySet().iterator(); iter.hasNext();) {
- String paramName = (String) iter.next();
- parameters.put(paramName, loginParameters.get(paramName));
- }
- }
-
- headers.remove("content-length");
- parameters.remove(PARAM_SAMLARTIFACT);
- parameters.remove(PARAM_TARGET);
-
- ConnectionBuilder cb = ConnectionBuilderFactory.getConnectionBuilder(publicURLPrefix);
- HttpURLConnection conn = cb.buildConnection(req, publicURLPrefix, realURLPrefix, ssf, parameters);
-
- //Set Cookies...
-
- String cookieString = CookieManager.getInstance().getCookie(req.getSession().getId());
- if (cookieString!=null)
- {
- //If we get Cookies from Client, we put them throgh if they dont exist/conflict with the stored Cookies
- for (Iterator iter = headers.keySet().iterator(); iter.hasNext();) {
- String headerKey = (String) iter.next();
- String headerValue = (String) headers.get(headerKey);
- if (headerKey.equalsIgnoreCase("Cookie"))
- CookieManager.getInstance().saveOldCookies(req.getSession().getId(), headerValue);
- }
- cookieString = CookieManager.getInstance().getCookie(req.getSession().getId());
- headers.put("cookie", cookieString);
- }
-
- // 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);
- conn.setRequestProperty(headerKey, headerValue);
- Logger.debug("Req header " + headerKey + ": " + headers.get(headerKey));
- if (Logger.isDebugEnabled() && isBasicAuthenticationHeader(headerKey, headerValue)) {
- String credentials = headerValue.substring(6);
- String userIDPassword = new String(Base64Utils.decode(credentials, false));
- Logger.debug(":UserID:Password: :" + userIDPassword + ":");
- }
- }
- // 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;
- StringWriter sb = new StringWriter();
- for (Iterator iter = parameters.keySet().iterator(); iter.hasNext();) {
- String paramname = (String) iter.next();
- String value = URLEncoder.encode((String) parameters.get(paramname));
- if (firstParam)
- firstParam = false;
- else
- sb.write("&");
- sb.write(paramname);
- sb.write("=");
- sb.write(value);
- Logger.debug("Req param " + paramname + ": " + value);
- }
- PrintWriter reqOut = new PrintWriter(conn.getOutputStream());
- reqOut.write(sb.toString());
- reqOut.flush();
- reqOut.close();
- }
- // connect
- conn.connect();
-
- // Read response status and content type.
- // If the connection returns a 401 disconnect and return
- // otherwise the attempt to read data from that connection
- // will result in an error
-
- if (conn.getResponseCode()==HttpURLConnection.HTTP_UNAUTHORIZED)
- {
- Logger.debug("Found 401... searching cookies");
- String headerKey;
-
- int i = 1;
- CookieManager cm = CookieManager.getInstance();
- while ((headerKey = conn.getHeaderFieldKey(i)) != null) {
- String headerValue = conn.getHeaderField(i);
- if (headerKey.equalsIgnoreCase("set-cookie"))
- { cm.saveCookie(req.getSession().getId(), headerValue);
- cm.add401(req.getSession().getId(),headerValue);
- Logger.debug("Cookie " + headerValue);
- Logger.debug("CookieSession " + req.getSession().getId());
- }
- i++;
- }
-
- conn.disconnect();
- return conn.getResponseCode();
- }
- resp.setStatus(conn.getResponseCode());
- resp.setContentType(conn.getContentType());
-
- // 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.
- Map respHeaders = new HashMap();
- boolean chunked = false;
- String contentLengthKey = null;
- String transferEncodingKey = null;
- int i = 1;
- String headerKey;
- while ((headerKey = conn.getHeaderFieldKey(i)) != null) {
- String headerValue = conn.getHeaderField(i);
- respHeaders.put(headerKey, headerValue);
- if (isTransferEncodingChunkedHeader(headerKey, headerValue)) {
- chunked = true;
- transferEncodingKey = headerKey;
- }
- CookieManager cm = CookieManager.getInstance();
- if (headerKey.equalsIgnoreCase("set-cookie"))
- { cm.saveCookie(req.getSession().getId(), headerValue);
- Logger.debug("Cookie " + headerValue);
- Logger.debug("CookieSession " + req.getSession().getId());
- }
- if ("content-length".equalsIgnoreCase(headerKey))
- contentLengthKey = headerKey;
- Logger.debug("Resp header " + headerKey + ": " + headerValue);
- i++;
- }
- if (chunked && contentLengthKey != null) {
- respHeaders.remove(transferEncodingKey);
- Logger.debug("Resp header " + transferEncodingKey + " REMOVED");
- }
-
- //Get a Hash-Map of all 401-set-cookies
- HashMap cookies401 = CookieManager.getInstance().get401(req.getSession().getId());
-
- for (Iterator iter = respHeaders.keySet().iterator(); iter.hasNext();) {
- headerKey = (String) iter.next();
-
- if (headerKey.equalsIgnoreCase("Set-Cookie"))
- {
- String headerValue = (String) respHeaders.get(headerKey);
- Logger.debug("Found 'Set-Cookie' in ResponseHeaders: " + headerValue);
- if(!cookies401.containsKey(headerValue.substring(0, headerValue.indexOf("="))))
- {
- // If we dont already have a Set-Cookie-Value for THAT Cookie we create one...
- CookieManager.getInstance().add401(req.getSession().getId(), headerValue);
- }
- }
- }
-
- //write out all Responseheaders != "set-cookie"
- for (Iterator iter = respHeaders.keySet().iterator(); iter.hasNext();) {
- headerKey = (String) iter.next();
- if (!headerKey.equalsIgnoreCase("Set-Cookie"))
- resp.addHeader(headerKey, (String) respHeaders.get(headerKey));
- }
-
- //write out all Responseheaders = "set-cookie"
- cookies401 = CookieManager.getInstance().get401(req.getSession().getId());
- Iterator cookie_i = cookies401.values().iterator();
- while (cookie_i.hasNext()) {
- String element = (String) cookie_i.next();
- resp.addHeader("Set-Cookie", element);
- }
- //Delete all "Set-Cookie" - Values
- CookieManager.getInstance().clear401(req.getSession().getId());
-
- // 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");
- int ch;
- while ((ch = respIn.read()) >= 0)
- respOut.write(ch);
- respOut.close();
- respIn.close();
- }
- else
- Logger.debug("Found 304 NOT MODIFIED...");
- conn.disconnect();
- Logger.debug("Request done");
-
-
- return conn.getResponseCode();
-}
-/**
- * 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 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 {
- 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 in proxying the request.
- * <ul>
- * <li>Logs the error.</li>
- * <li>Outputs an HTML error page.</li>
- * </ul>
- * @param resp the HttpServletResponse
- * @param errorMessage error message to be used
- * @param ex the exception to be logged
- */
-private void handleError(HttpServletResponse resp, String errorMessage, Throwable ex) {
- Logger.error(errorMessage, ex);
- String htmlCode =
- "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">"
- + "<html><head><title>"
- + MOAIDMessageProvider.getInstance().getMessage("proxy.10", null)
- + "</title></head><body>"
- + "<h1>"
- + MOAIDMessageProvider.getInstance().getMessage("proxy.10", null)
- + "</h1>"
- + "<p>"
- + MOAIDMessageProvider.getInstance().getMessage("proxy.11", null)
- + "</p>"
- + "<p>"
- + errorMessage
- + "</p>"
- + "</body></html>";
- resp.setContentType("text/html");
- try {
- OutputStream respOut = resp.getOutputStream();
- respOut.write(htmlCode.getBytes());
- respOut.flush();
- }
- catch (IOException ioex) {
- Logger.error("", ioex);
- }
-}
-
-}