diff options
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.java | 537 |
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); - } -} - -} |