Return-Path: Delivered-To: apmail-sling-commits-archive@www.apache.org Received: (qmail 24418 invoked from network); 3 Dec 2009 14:37:02 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 3 Dec 2009 14:37:02 -0000 Received: (qmail 16278 invoked by uid 500); 3 Dec 2009 14:37:02 -0000 Delivered-To: apmail-sling-commits-archive@sling.apache.org Received: (qmail 16226 invoked by uid 500); 3 Dec 2009 14:37:02 -0000 Mailing-List: contact commits-help@sling.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@sling.apache.org Delivered-To: mailing list commits@sling.apache.org Received: (qmail 16217 invoked by uid 99); 3 Dec 2009 14:37:02 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 03 Dec 2009 14:37:02 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 03 Dec 2009 14:36:59 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 3220523889D2; Thu, 3 Dec 2009 14:36:38 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r886796 - in /sling/trunk/bundles/extensions/httpauth/src/main: java/org/apache/sling/httpauth/impl/AuthorizationHeaderAuthenticationHandler.java resources/org/apache/sling/httpauth/impl/LoginFormTemplate.html Date: Thu, 03 Dec 2009 14:36:38 -0000 To: commits@sling.apache.org From: fmeschbe@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20091203143638.3220523889D2@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org Author: fmeschbe Date: Thu Dec 3 14:36:37 2009 New Revision: 886796 URL: http://svn.apache.org/viewvc?rev=886796&view=rev Log: SLING-1220 Fix interaction between authentication handler and login form to convey invalid credentials with a 403 status code instead of just resending the login form with a status code of 200. Further fixes included: * only send login request once (duplicate reference in the form) * properly identify logged-in request (don't use AuthType since there is at least one servlet container, which returns a non-null value even if the servlet container does not authenticate the request) Modified: sling/trunk/bundles/extensions/httpauth/src/main/java/org/apache/sling/httpauth/impl/AuthorizationHeaderAuthenticationHandler.java sling/trunk/bundles/extensions/httpauth/src/main/resources/org/apache/sling/httpauth/impl/LoginFormTemplate.html Modified: sling/trunk/bundles/extensions/httpauth/src/main/java/org/apache/sling/httpauth/impl/AuthorizationHeaderAuthenticationHandler.java URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/httpauth/src/main/java/org/apache/sling/httpauth/impl/AuthorizationHeaderAuthenticationHandler.java?rev=886796&r1=886795&r2=886796&view=diff ============================================================================== --- sling/trunk/bundles/extensions/httpauth/src/main/java/org/apache/sling/httpauth/impl/AuthorizationHeaderAuthenticationHandler.java (original) +++ sling/trunk/bundles/extensions/httpauth/src/main/java/org/apache/sling/httpauth/impl/AuthorizationHeaderAuthenticationHandler.java Thu Dec 3 14:36:37 2009 @@ -32,6 +32,7 @@ import org.apache.sling.engine.auth.AuthenticationHandler; import org.apache.sling.engine.auth.AuthenticationInfo; import org.osgi.service.component.ComponentContext; +import org.osgi.service.http.HttpContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,7 +41,7 @@ * the authorization steps based on the Authorization header of the HTTP * request. This authenticator should eventually support both BASIC and DIGEST * authentication methods. - * + * * @scr.component immediate="false" label="%auth.http.name" * description="%auth.http.description" * @scr.property name="service.description" @@ -62,7 +63,7 @@ * in the {@link #authenticate(HttpServletRequest, HttpServletResponse)} * method if no credentials are present in the request (value is * "sling:authRequestLogin"). - * + * * @see #authenticate(HttpServletRequest, HttpServletResponse) */ static final String REQUEST_LOGIN_PARAMETER = "sling:authRequestLogin"; @@ -131,7 +132,7 @@ * the request may be for an included servlet, in which case the values for * some URI specific values are contained in javax.servlet.include.* request * attributes. - * + * * @param request The request object containing the information for the * authentication. * @param response The response object which may be used to send the @@ -162,7 +163,7 @@ /** * Sends back the form to log into the system. - * + * * @param request The request object * @param response The response object to which to send the request * @return true is always returned by this handler @@ -176,30 +177,55 @@ // reset the response response.reset(); - response.setStatus(HttpServletResponse.SC_OK); + response.setHeader("Cache-Control", "no-cache"); - String form = getLoginForm(); + if (isLoginRequested(request)) { - if (form != null) { - - form = replaceVariables(form, "@@contextPath@@", - request.getContextPath(), "/"); - form = replaceVariables(form, "@@authType@@", - request.getAuthType(), ""); - form = replaceVariables(form, "@@user@@", - request.getRemoteUser(), ""); - - response.setContentType("text/html"); - response.setCharacterEncoding("UTF-8"); - response.getWriter().print(form); + // this is the ajax request for authentication which failed, we + // send back a 403/FORBIDDEN here to indicate failure + // Resoning: + // - using 401 would technically be correct but the browsers + // intercept these even for ajax requests. so sending 403 + // indicates wrong credentials but allows processing without + // browser intervention + // - setting status only instead of using sendError prevents + // any error handling scripts from kicking in (and + // potentially modifying the result) + response.setStatus(HttpServletResponse.SC_FORBIDDEN); } else { - - // have no form, so just send 401/UNATHORIZED for simple login - sendUnauthorized(response); - + + response.setStatus(HttpServletResponse.SC_OK); + + String form = getLoginForm(); + + if (form != null) { + + form = replaceVariables( + form, + "@@loggedIn@@", + String.valueOf(request.getAttribute(HttpContext.AUTHENTICATION_TYPE) != null), + "false"); + form = replaceVariables(form, "@@contextPath@@", + request.getContextPath(), "/"); + form = replaceVariables(form, "@@authType@@", + request.getAuthType(), ""); + form = replaceVariables(form, "@@user@@", + request.getRemoteUser(), ""); + + response.setContentType("text/html"); + response.setCharacterEncoding("UTF-8"); + response.getWriter().print(form); + + } else { + + // have no form, so just send 401/UNATHORIZED for simple login + sendUnauthorized(response); + + } + } - + } else { log.error("requestAuthentication: Response is committed, cannot request authentication"); @@ -210,6 +236,14 @@ } /** + * Returns true if the {@link #REQUEST_LOGIN_PARAMETER} parameter is set in + * the request. + */ + private boolean isLoginRequested(HttpServletRequest request) { + return request.getParameter(REQUEST_LOGIN_PARAMETER) != null; + } + + /** * If the {@link #REQUEST_LOGIN_PARAMETER} parameter is set this method * sends status 401 (Unauthorized) with a * WWW-Authenticate requesting standard HTTP header @@ -220,7 +254,7 @@ * false is returned if the request parameter is not set, if * the response is already committed or if an error occurred sending the * status response. The latter two situations are logged as errors. - * + * * @param request The request object * @param response The response object to which to send the request * @return true if the 401/UNAUTHORIZED method has successfully @@ -232,7 +266,7 @@ // presume 401/UNAUTHORIZED has not been sent boolean authenticationForced = false; - if (request.getParameter(REQUEST_LOGIN_PARAMETER) != null) { + if (isLoginRequested(request)) { if (!response.isCommitted()) { @@ -243,25 +277,25 @@ log.error("forceAuthentication: Response is committed, cannot request authentication"); } - + } else { - + log.debug( "forceAuthentication: Not forcing authentication because request parameter {} is not set", REQUEST_LOGIN_PARAMETER); - + } // true if 401/UNAUTHORIZED has been sent, false otherwise return authenticationForced; } - + /** * Sends status 401 (Unauthorized) with a * WWW-Authenticate requesting standard HTTP header * authentication with the Basic scheme and the configured * realm name. - * + * * @param response The response object to which to send the request * @return true if the 401/UNAUTHORIZED method has successfully * been sent. @@ -406,12 +440,12 @@ } } - + } else { - + log.error("getLoginForm: Cannot access login form template at " + LOGIN_FORM_TEMPLATE); - + } } @@ -422,7 +456,7 @@ * Replaces all occurrences in the template of the * key (a regular expression) by the value or * defaultValue. - * + * * @param template The template to replace occurences of key * @param key The regular expression of the key to replace * @param value The replacement value Modified: sling/trunk/bundles/extensions/httpauth/src/main/resources/org/apache/sling/httpauth/impl/LoginFormTemplate.html URL: http://svn.apache.org/viewvc/sling/trunk/bundles/extensions/httpauth/src/main/resources/org/apache/sling/httpauth/impl/LoginFormTemplate.html?rev=886796&r1=886795&r2=886796&view=diff ============================================================================== --- sling/trunk/bundles/extensions/httpauth/src/main/resources/org/apache/sling/httpauth/impl/LoginFormTemplate.html (original) +++ sling/trunk/bundles/extensions/httpauth/src/main/resources/org/apache/sling/httpauth/impl/LoginFormTemplate.html Thu Dec 3 14:36:37 2009 @@ -58,7 +58,7 @@