diff options
Diffstat (limited to 'id.server/src/at/gv/egovernment/moa/id/proxy')
-rw-r--r-- | id.server/src/at/gv/egovernment/moa/id/proxy/servlet/ProxyServlet.java | 817 |
1 files changed, 624 insertions, 193 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 index f82ad93ed..50b07eeb4 100644 --- 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 @@ -3,14 +3,19 @@ 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.net.URLEncoder; 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; @@ -29,9 +34,9 @@ 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.config.proxy.ProxyConfigurationProvider; import at.gv.egovernment.moa.id.data.AuthenticationData; import at.gv.egovernment.moa.id.data.CookieManager; import at.gv.egovernment.moa.id.proxy.ConnectionBuilder; @@ -69,8 +74,26 @@ public class ProxyServlet extends HttpServlet { 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 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) @@ -81,13 +104,26 @@ public class ProxyServlet extends HttpServlet { try { if (req.getParameter(PARAM_SAMLARTIFACT) != null && req.getParameter(PARAM_TARGET) != null) { + //boolean basicauth = + + //if ((!binding full) && (!isBasicAuthenticationHeaderProvided(req))) { + + // browserRequest(); + + //} else { + // check if SAML Artifact was already used in this session (in case of page reload) HttpSession session = req.getSession(); - if(null != session && req.getParameter(PARAM_SAMLARTIFACT).equals(session.getAttribute(ATT_SAML_ARTIFACT))) { - tunnelRequest(req, resp); + if (null != session && req.getParameter(PARAM_SAMLARTIFACT).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); @@ -99,7 +135,7 @@ public class ProxyServlet extends HttpServlet { handleError(ex.getMessage(), ex, req, resp); } } - + /** * Login to online application at first call of servlet for a user session.<br/> * <ul> @@ -120,114 +156,134 @@ public class ProxyServlet extends HttpServlet { */ 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; - 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); - } - - 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(); + HttpSession session = req.getSession(); + String samlArtifact = ""; 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 }); - } catch (NotAllowedException e) { - throw new ProxyException("proxy.15", new Object[] { }); - } - - // setup SSLSocketFactory for communication with the online application + String publicURLPrefix = ""; + String realURLPrefix = ""; 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); - } - } + String urlRequested = req.getRequestURL().toString(); + OAConfiguration oaConf = null; + String loginType = ""; + String binding = "full"; + + if (session.getAttribute(ATT_BROWSERREQU)==null) { + + 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; + 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); + } + + // 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(); + 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 }); + } 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(); + binding = oaConf.getBinding(); + 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 { - // 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); - session.setAttribute(ATT_SAML_ARTIFACT, samlArtifact); - Logger.debug("moa-id-proxy: HTTPSession angelegt"); - } - - + int respcode = 0; + // tunnel request to the online application - int respcode = - tunnelRequest( - req, - resp, - loginHeaders, - loginParameters, - publicURLPrefix, - realURLPrefix, - ssf); + respcode = tunnelRequest(req, resp, loginHeaders, loginParameters, publicURLPrefix, realURLPrefix, ssf, binding); 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 }); +// if ((! OAConfiguration.BINDUNG_FULL.equals(binding)) && oaConf.getLoginType().equals(OAConfiguration.LOGINTYPE_STATELESS)) { +// //user has to fill out login-dialog +// respcode = browserRequest(req, resp, publicURLPrefix, realURLPrefix); +// } +// if (respcode == 401) { +// Logger.debug("Got 401, trying again"); +// respcode = tunnelRequest(req, resp, loginHeaders, loginParameters, publicURLPrefix, realURLPrefix, ssf, binding); +// if (respcode == 401) +// throw new ProxyException("proxy.12", new Object[] { realURLPrefix }); +// } + 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); } @@ -241,13 +297,13 @@ public class ProxyServlet extends HttpServlet { */ private void tunnelRequest(HttpServletRequest req, HttpServletResponse resp) throws ProxyException, IOException { - Logger.debug("Tunnel request (stateless)"); + //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 sesssion is automatically created when forwarded 1st time to errorpage-proxy.jsp (with the handleError method) + //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); @@ -256,17 +312,21 @@ public class ProxyServlet extends HttpServlet { 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); - 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}); - } + int respcode = tunnelRequest(req, resp, loginHeaders, loginParameters, publicURLPrefix, realURLPrefix, ssf, binding); + // Handle all requests after the except the first one + //if (respcode == 401) { + //Logger.debug("Got 401, trying again"); + //respcode = tunnelRequest(req, resp, loginHeaders, loginParameters, publicURLPrefix, realURLPrefix, ssf, binding); + //if (respcode == 401) + // throw new ProxyException("proxy.12", new Object[] { realURLPrefix}); + //} + // #tries to login exceeded + if (respcode == -401) + throw new ProxyException("proxy.16", new Object[] {realURLPrefix, Integer.toString(MAX_OA_LOGINTRY)}); } /** @@ -283,76 +343,213 @@ public class ProxyServlet extends HttpServlet { * @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) +private int tunnelRequest(HttpServletRequest req, HttpServletResponse resp, Map loginHeaders, Map loginParameters, String publicURLPrefix, String realURLPrefix, SSLSocketFactory ssf, String binding) throws IOException { + String browserUserID = ""; + String browserPassword = ""; + if (INTERNAL_DEBUG && !binding.equals("")) Logger.debug("Binding: " + binding); + // 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) ); + 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); + //Logger.debug("Analyzing authorization-header from browser: " + headerKeyValue + "gives UN:PW=" + browserUserID + ":" + browserPassword ); + } + if (headerKeyValue.substring(0,9).equalsIgnoreCase("Negotiate")) { + //Logger.debug("Analyzing authorization-header from browser: Found NTLM Aut.: " + headerKeyValue + "gives UN:PW=" + browserUserID + ":" + browserPassword ); + } + } + else + { + headers.put(headerKey, headerKeyValue); } - 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)); + String authorizationvalue=""; + if (req.getSession().getAttribute(ATT_OA_AUTHORIZATION_HEADER)==null) { + + //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); + } + } + } + + +/* // collect parameters from request Map parameters = new HashMap(); - for (Enumeration enum = req.getParameterNames(); enum.hasMoreElements();) { - String paramName = (String) enum.nextElement(); + for (Enumeration enu = req.getParameterNames(); enu.hasMoreElements();) { + String paramName = (String) enu.nextElement(); + Logger.debug("Req Parameter-put: " + paramName); 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(); + Logger.debug("Req Login-Parameter-put: " + paramName); parameters.put(paramName, loginParameters.get(paramName)); } } - headers.remove("content-length"); + //Folgende Zeile ergibt fehlerhaftes Verhalten! + //headers.remove("content-length"); + //30.06.2005 wegen Fehler 411 bei Webdav parameters.remove(PARAM_SAMLARTIFACT); parameters.remove(PARAM_TARGET); - + */ + ConnectionBuilder cb = ConnectionBuilderFactory.getConnectionBuilder(publicURLPrefix); + //HttpURLConnection conn = cb.buildConnection(req, publicURLPrefix, realURLPrefix, ssf, parameters); HttpURLConnection conn = cb.buildConnection(req, publicURLPrefix, realURLPrefix, ssf, parameters); + //Set Cookies... - String cookieString = CookieManager.getInstance().getCookie(req.getSession().getId()); + /* + 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")) + { + //If we get Cookies from Client, we put them through 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); - } + Logger.debug("*** Saving old Cookie: " + headerValue); + } + } + cookieString = CookieManager.getInstance().getCookie(req.getSession().getId()); + headers.put("Cookie", cookieString); + Logger.debug("*** Put header 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 LogStr = "Req header " + headerKey + ": " + headers.get(headerKey); + if (isBasicAuthenticationHeader(headerKey, headerValue)) { String credentials = headerValue.substring(6); - String userIDPassword = new String(Base64Utils.decode(credentials, false)); - Logger.debug(":UserID:Password: :" + userIDPassword + ":"); + 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); + //if (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; + //StringWriter sb = new StringWriter(); + 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); } + //PrintWriter reqOut = new PrintWriter(conn.getOutputStream()); + //reqOut.write(sb.toString()); + //Logger.debug("Req P: (L="+ Integer.toString(sb.toString().length()) +") " + sb.toString()); + //reqOut.flush(); + //reqOut.close(); } + + /* // Write out parameters into output stream of URLConnection. // On GET request, do not send parameters in any case, // otherwise HttpURLConnection would send a POST. @@ -361,7 +558,8 @@ private int tunnelRequest(HttpServletRequest req, HttpServletResponse resp, Map 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)); + //String value = URLEncoder.encode((String) parameters.get(paramname)); + String value = (String) parameters.get(paramname); if (firstParam) firstParam = false; else @@ -373,68 +571,136 @@ private int tunnelRequest(HttpServletRequest req, HttpServletResponse resp, Map } PrintWriter reqOut = new PrintWriter(conn.getOutputStream()); reqOut.write(sb.toString()); + Logger.debug("Req P: " + sb.toString()); reqOut.flush(); reqOut.close(); } + */ + + // 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 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++; + // check login tries + if (conn.getResponseCode()==HttpURLConnection.HTTP_UNAUTHORIZED) { + String oa_loginTry = (String) req.getSession().getAttribute(ATT_OA_LOGINTRY); + int loginTry = 1; + if (oa_loginTry!=null) loginTry = Integer.parseInt(oa_loginTry)+1; + 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); + //conn.disconnect(); + return -401; + } } - conn.disconnect(); - return conn.getResponseCode(); + + + + if (conn.getResponseCode()==HttpURLConnection.HTTP_UNAUTHORIZED && OAConfiguration.BINDUNG_FULL.equals(binding)) { + Logger.debug("Found 401 UNAUTHORIZED, leaving..."); + /* + 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++; + } + */ + cb.disconnect(conn); + //conn.disconnect(); + return conn.getResponseCode(); } + + resp.setStatus(conn.getResponseCode()); 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. - Map respHeaders = new HashMap(); + //Map respHeaders = new HashMap(); überschreibt headerzeilen + 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); - respHeaders.put(headerKey, headerValue); + // Ü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(binding)) headerValue = "Basic realm=\"Bitte Passwort eingeben\""; + if (OAConfiguration.BINDUNG_NONE.equals(binding)) headerValue = "Basic realm=\"Bitte Benutzername und Passwort eingeben\""; + } + // if (!headerKey.equalsIgnoreCase("set-cookie")){ + //respHeaders.put(headerKey, headerValue); + 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(binding) && 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); + } + // }else{ + // Logger.debug("Resp header ---REMOVED--- " + 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()); - } + CookieManager cm = CookieManager.getInstance(); + if (headerKey.equalsIgnoreCase("set-cookie")) + { + //cm.saveCookie(req.getSession().getId(), headerValue); + //Logger.debug("*** Saving 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) { @@ -442,9 +708,43 @@ private int tunnelRequest(HttpServletRequest req, HttpServletResponse resp, Map Logger.debug("Resp header " + transferEncodingKey + " REMOVED"); } + String headerValue; + String respHeader[] = new String[2]; + + /* //Get a Hash-Map of all 401-set-cookies HashMap cookies401 = CookieManager.getInstance().get401(req.getSession().getId()); + for (Iterator iter = respHeaders.iterator(); iter.hasNext();) + { + respHeader = (String[]) iter.next(); + headerKey = respHeader[0]; + headerValue = respHeader[1]; + + 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); + Logger.debug("*** Saving 401 'Set-Cookie' from ResponseHeaders: " + headerValue); + } + } + } + */ + + //write out all Responseheaders != "set-cookie" + for (Iterator iter = respHeaders.iterator(); iter.hasNext();) { + respHeader = (String[]) iter.next(); + headerKey = respHeader[0]; + headerValue = respHeader[1]; + // if (!headerKey.equalsIgnoreCase("Set-Cookie")) + resp.addHeader(headerKey, headerValue); + } + + /* for (Iterator iter = respHeaders.keySet().iterator(); iter.hasNext();) { headerKey = (String) iter.next(); @@ -456,47 +756,96 @@ private int tunnelRequest(HttpServletRequest req, HttpServletResponse resp, Map { // If we dont already have a Set-Cookie-Value for THAT Cookie we create one... CookieManager.getInstance().add401(req.getSession().getId(), headerValue); + Logger.debug("Saving 401 'Set-Cookie' from ResponseHeaders: " + headerValue); } } } - + //write out all Responseheaders != "set-cookie" for (Iterator iter = respHeaders.keySet().iterator(); iter.hasNext();) { headerKey = (String) iter.next(); + //PeterD if (!headerKey.equalsIgnoreCase("Set-Cookie")) - resp.addHeader(headerKey, (String) respHeaders.get(headerKey)); + 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); + Logger.debug("Resp header Set-Cookie: " + element); } + + //Delete all "Set-Cookie" - Values CookieManager.getInstance().clear401(req.getSession().getId()); + */ + + + //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) - { + if (conn.getResponseCode()!=HttpURLConnection.HTTP_NOT_MODIFIED ) { BufferedInputStream respIn = new BufferedInputStream(conn.getInputStream()); - Logger.debug("Got Inputstream"); + //Logger.debug("Got Inputstream"); BufferedOutputStream respOut = new BufferedOutputStream(resp.getOutputStream()); - Logger.debug("Got Outputstream"); + //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; - while ((ch = respIn.read()) >= 0) - respOut.write(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(); - } - else - Logger.debug("Found 304 NOT MODIFIED..."); - conn.disconnect(); - Logger.debug("Request done"); + if (conn.getResponseCode()==HttpURLConnection.HTTP_UNAUTHORIZED) { + Logger.debug("Found 401 UNAUTHORIZED..."); + cb.disconnect(conn); + //conn.disconnect(); + return conn.getResponseCode(); + } + } else { + //if (conn.getResponseCode()==HttpURLConnection.HTTP_NOT_MODIFIED) + Logger.debug("Found 304 NOT MODIFIED..."); + } + //conn.disconnect(); + cb.disconnect(conn); + Logger.debug("Request done"); return conn.getResponseCode(); } @@ -516,6 +865,21 @@ private boolean isBasicAuthenticationHeader(String headerKey, String headerValue 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 @@ -574,7 +938,7 @@ protected void handleError( //req.setAttribute("ExceptionThrown", exceptionThrown); } - //forward this to errorpage-proxy.jsp wher the HTML error page is generated + //forward this to errorpage-proxy.jsp where the HTML error page is generated ServletContext context = getServletContext(); RequestDispatcher dispatcher = context.getRequestDispatcher("/errorpage-proxy.jsp"); try { @@ -587,4 +951,71 @@ protected void handleError( } + +/** + * Prepares the session and necessary response-header for the login dialog request + * This method returns the response code 200 to avoid 401 proceeding. + * @param req HTTP request + * @param resp HTTP response + * @param publicURLPrefix prefix of request URL to be substituted for the <code>realURLPrefix</code> + */ +/* +private int browserRequest(HttpServletRequest req, HttpServletResponse resp, String publicURLPrefix, String realURLPrefix) +{ + //Preparing Browser Request + String host=""; + Logger.debug("OA Browser-Request for user login dialog"); + try { + URL turl = new URL(realURLPrefix); + host = turl.getHost(); + } catch (MalformedURLException e) { + Logger.error(e); + } + + + resp.addHeader("WWW-Authenticate", "Basic realm=\"" + host + "\""); + resp.setStatus(401); + + HttpSession session = req.getSession(); + session.setAttribute(ATT_BROWSERREQU, "inProgress"); + + return 200; +} +*/ + +// * 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); + } +} + + } |