You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2009/10/15 16:09:39 UTC

svn commit: r825501 - in /sling/trunk/bundles/engine: ./ src/main/java/org/apache/sling/engine/auth/ src/main/java/org/apache/sling/engine/impl/auth/

Author: fmeschbe
Date: Thu Oct 15 14:09:38 2009
New Revision: 825501

URL: http://svn.apache.org/viewvc?rev=825501&view=rev
Log:
SLING-1155 Provide Authenticator.logout method and define new interface for
authentication handlers to support logging out

Added:
    sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/AuthenticationHandler2.java   (with props)
    sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/AuthenticationHandlerHolder.java   (with props)
    sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/LogoutServlet.java   (with props)
Modified:
    sling/trunk/bundles/engine/pom.xml
    sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/AuthenticationHandler.java
    sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/Authenticator.java
    sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/LoginServlet.java
    sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/SlingAuthenticator.java

Modified: sling/trunk/bundles/engine/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/pom.xml?rev=825501&r1=825500&r2=825501&view=diff
==============================================================================
--- sling/trunk/bundles/engine/pom.xml (original)
+++ sling/trunk/bundles/engine/pom.xml Thu Oct 15 14:09:38 2009
@@ -55,9 +55,9 @@
                 <configuration>
                     <instructions>
                         <Export-Package>
-                            org.apache.sling.engine;
-                            org.apache.sling.engine.auth;
-                            org.apache.sling.engine.servlets;version=${pom.version}
+                            org.apache.sling.engine;version=2.0.6,
+                            org.apache.sling.engine.auth;version=2.1,
+                            org.apache.sling.engine.servlets;version=2.0.6
                         </Export-Package>
                         <Private-Package>
                             org.apache.sling.engine.impl,

Modified: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/AuthenticationHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/AuthenticationHandler.java?rev=825501&r1=825500&r2=825501&view=diff
==============================================================================
--- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/AuthenticationHandler.java (original)
+++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/AuthenticationHandler.java Thu Oct 15 14:09:38 2009
@@ -31,11 +31,18 @@
 public interface AuthenticationHandler {
 
     /**
+     * The name under which an implementation of this interface must be
+     * registered to be used as an authentication handler.
+     * @since 2.1
+     */
+    static final String SERVICE_NAME = "org.apache.sling.engine.auth.AuthenticationHandler";
+
+    /**
      * An authentication handler is associated with url paths. If the handler is
      * not configured with a path, it is regarded as inactive. If the handler
      * should be used for all requests, the path should be '/'.
      */
-    String PATH_PROPERTY = "path";
+    static final String PATH_PROPERTY = "path";
 
     /**
      * Extracts credential data from the request if at all contained.
@@ -71,7 +78,7 @@
      * attribute. If the service is registered with multiple path values, the
      * value of the <code>path</code> request attribute may be used to implement
      * specific handling.
-     * 
+     *
      * @param request The request object containing the information for the
      *            authentication.
      * @param response The response object which may be used to send the
@@ -100,7 +107,7 @@
      * attribute. If the service is registered with multiple path values, the
      * value of the <code>path</code> request attribute may be used to implement
      * specific handling.
-     * 
+     *
      * @param request The request object.
      * @param response The response object to which to send the request.
      * @return <code>true</code> if the handler is able to end an authentication

Added: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/AuthenticationHandler2.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/AuthenticationHandler2.java?rev=825501&view=auto
==============================================================================
--- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/AuthenticationHandler2.java (added)
+++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/AuthenticationHandler2.java Thu Oct 15 14:09:38 2009
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.engine.auth;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * The <code>AuthenticationHandler</code> interface defines the service API used
+ * by the authentication implementation to support plugin various ways of
+ * extracting credentials from the request.
+ * <p>
+ * Authentication handlers implementing this interface should still be
+ * registered with the {@link AuthenticationHandler#SERVICE authentication
+ * handler service name}. Internally, the
+ * {@link Authenticator#logout(HttpServletRequest, HttpServletResponse)} method
+ * will identify the authentication handler appropriately.
+ *
+ * @since 2.1
+ */
+public interface AuthenticationHandler2 extends AuthenticationHandler {
+
+    /**
+     * Drops any credential and authentication details from the request and asks
+     * the client to do the same.
+     *
+     * @param request The request object.
+     * @param response The response object to which to send the request.
+     * @throws IOException If an error occurrs asking the client to drop any
+     *             authentication traces.
+     * @since 2.1
+     */
+    void dropAuthentication(HttpServletRequest request,
+            HttpServletResponse response) throws IOException;
+
+}

Propchange: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/AuthenticationHandler2.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/AuthenticationHandler2.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Modified: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/Authenticator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/Authenticator.java?rev=825501&r1=825500&r2=825501&view=diff
==============================================================================
--- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/Authenticator.java (original)
+++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/auth/Authenticator.java Thu Oct 15 14:09:38 2009
@@ -31,7 +31,7 @@
  * This interface is not intended to be implemented by applications but may be
  * used to initiate the authentication process form a request processing servlet
  * or script.
- * 
+ *
  * @since 2.0.4
  */
 public interface Authenticator {
@@ -49,13 +49,34 @@
      * <p>
      * After this method has finished, request processing should be terminated
      * and the response be considered committed and finished.
-     * 
+     *
      * @param request The object representing the client request.
      * @param response The object representing the response to the client.
      * @throws NoAuthenticationHandlerException If no authentication handler
      *             claims responsibility to authenticate the request.
      * @throws IllegalStateException If the response has already been committed.
      */
-    public void login(HttpServletRequest request, HttpServletResponse response);
+    void login(HttpServletRequest request, HttpServletResponse response);
 
+    /**
+     * Finds an {@link AuthenticationHandler2} for the given request and call
+     * its
+     * {@link AuthenticationHandler2#dropAuthentication(HttpServletRequest, HttpServletResponse)}
+     * method to drop authentication credentials for the client to logout from
+     * Sling.
+     * <p>
+     * This method must be called on an uncommitted response since the
+     * implementation may want to reset the response to restart the
+     * authentication process with a clean response. If the response is already
+     * committed an <code>IllegalStateException</code> is thrown.
+     * <p>
+     * After this method has finished, request processing should be terminated
+     * and the response be considered committed and finished.
+     *
+     * @param request The object representing the client request.
+     * @param response The object representing the response to the client.
+     * @throws IllegalStateException If the response has already been committed.
+     * @since 2.1
+     */
+    void logout(HttpServletRequest request, HttpServletResponse response);
 }

Added: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/AuthenticationHandlerHolder.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/AuthenticationHandlerHolder.java?rev=825501&view=auto
==============================================================================
--- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/AuthenticationHandlerHolder.java (added)
+++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/AuthenticationHandlerHolder.java Thu Oct 15 14:09:38 2009
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.engine.impl.auth;
+
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.engine.RequestUtil;
+import org.apache.sling.engine.auth.AuthenticationHandler;
+import org.apache.sling.engine.auth.AuthenticationHandler2;
+import org.apache.sling.engine.auth.AuthenticationInfo;
+
+/**
+ * The <code>AuthenticationHandlerHolder</code> class represents an
+ * authentication handler service in the internal data structure of the
+ * {@link SlingAuthenticator}.
+ *
+ * @since 2.1
+ */
+final class AuthenticationHandlerHolder implements AuthenticationHandler2,
+        Comparable<AuthenticationHandlerHolder> {
+
+    // full path of the service registration
+    private final String fullPath;
+
+    // file path part of the service registration full path
+    final String path;
+
+    // host element of the service registration full path
+    final String host;
+
+    // protocol element of the service registration full path
+    final String protocol;
+
+    // the actual authentication handler
+    private final AuthenticationHandler handler;
+
+    AuthenticationHandlerHolder(final String fullPath,
+            final AuthenticationHandler handler) {
+
+        String path = fullPath;
+        String host = "";
+        String protocol = "";
+
+        // check for protocol prefix in the full path
+        if (path.startsWith("http://") || path.startsWith("https://")) {
+            int idxProtocolEnd = path.indexOf("://");
+            protocol = path.substring(0, idxProtocolEnd);
+            path = path.substring(idxProtocolEnd + 1);
+        }
+
+        // check for host prefix in the full path
+        if (path.startsWith("//")) {
+            int idxHostEnd = path.indexOf("/", 2);
+            idxHostEnd = idxHostEnd == -1 ? path.length() : idxHostEnd;
+
+            if (path.length() > 2) {
+                host = path.substring(2, idxHostEnd);
+                if (idxHostEnd < path.length()) {
+                    path = path.substring(idxHostEnd);
+                } else {
+                    path = "/";
+                }
+            } else {
+                path = "/";
+            }
+        }
+
+        // assign the fields
+        this.fullPath = fullPath;
+        this.path = path;
+        this.host = host;
+        this.protocol = protocol;
+        this.handler = handler;
+    }
+
+    public AuthenticationInfo authenticate(HttpServletRequest request,
+            HttpServletResponse response) {
+
+        final Object oldPathAttr = setPath(request);
+        try {
+            return handler.authenticate(request, response);
+        } finally {
+            resetPath(request, oldPathAttr);
+        }
+
+    }
+
+    public boolean requestAuthentication(HttpServletRequest request,
+            HttpServletResponse response) throws IOException {
+        final Object oldPathAttr = setPath(request);
+        try {
+            return handler.requestAuthentication(request, response);
+        } finally {
+            resetPath(request, oldPathAttr);
+        }
+    }
+
+    public void dropAuthentication(HttpServletRequest request,
+            HttpServletResponse response) throws IOException {
+
+        if (handler instanceof AuthenticationHandler2) {
+            final Object oldPathAttr = setPath(request);
+            try {
+                final AuthenticationHandler2 handler2 = (AuthenticationHandler2) handler;
+                handler2.dropAuthentication(request, response);
+            } finally {
+                resetPath(request, oldPathAttr);
+            }
+        }
+    }
+
+    public int compareTo(AuthenticationHandlerHolder other) {
+        return other.path.compareTo(path);
+    }
+
+    private Object setPath(final HttpServletRequest request) {
+        return RequestUtil.setRequestAttribute(request,
+            AuthenticationHandler.PATH_PROPERTY, fullPath);
+    }
+
+    private void resetPath(final HttpServletRequest request, Object oldValue) {
+        RequestUtil.setRequestAttribute(request,
+            AuthenticationHandler.PATH_PROPERTY, oldValue);
+    }
+}
\ No newline at end of file

Propchange: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/AuthenticationHandlerHolder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/AuthenticationHandlerHolder.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Modified: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/LoginServlet.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/LoginServlet.java?rev=825501&r1=825500&r2=825501&view=diff
==============================================================================
--- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/LoginServlet.java (original)
+++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/LoginServlet.java Thu Oct 15 14:09:38 2009
@@ -31,12 +31,11 @@
 import org.slf4j.LoggerFactory;
 
 /**
- * The <code>LoginServlet</code> lets the Authenticator
- * do the login.
- * 
+ * The <code>LoginServlet</code> lets the Authenticator do the login.
+ *
  * @scr.component metatype="no"
  * @scr.service interface="javax.servlet.Servlet"
- * @scr.property name="service.description" value="HTTP Header Login Servlet"
+ * @scr.property name="service.description" value="Authenticator Login Servlet"
  * @scr.property name="service.vendor" value="The Apache Software Foundation"
  * @scr.property name="sling.servlet.methods" values.0="GET" values.1="POST"
  */
@@ -51,15 +50,36 @@
     /** @scr.reference cardinality="0..1" policy="dynamic" */
     private Authenticator authenticator;
 
-    /** The servlet is registered on this path, and the authenticator allows
-     *  any requests to that path, without authentication
-     *  @scr.property name="sling.servlet.paths" */
+    /**
+     * The servlet is registered on this path, and the authenticator allows any
+     * requests to that path, without authentication
+     *
+     * @scr.property name="sling.servlet.paths"
+     */
     public static final String LOGIN_SERVLET_PATH = "/system/sling/login";
 
     @Override
-    protected void doGet(SlingHttpServletRequest request,
+    protected void service(SlingHttpServletRequest request,
             SlingHttpServletResponse response) throws IOException {
 
+        // if the request is logged in and the resource is not set (such
+        // as when requesting /system/sling/login from the browser with the
+        // browser sending credentials) or the resource is set to the login
+        // servlet as a result of authenticating after providing credentials
+        // through the login servlet), redirect to root now assuming we are
+        // authenticated.
+        if (request.getAuthType() != null) {
+            final String resourcePath = request.getParameter("resource");
+            if (isSelf(resourcePath)) {
+                String redirectTarget = request.getContextPath() + "/";
+                log.warn(
+                    "doGet: Redirecting to {} to prevent login loop for resource {}",
+                    redirectTarget, resourcePath);
+                response.sendRedirect(redirectTarget);
+                return;
+            }
+        }
+
         Authenticator authenticator = this.authenticator;
         if (authenticator != null) {
             try {
@@ -72,17 +92,25 @@
                 log.error("doGet: No AuthenticationHandler to login registered");
             }
         } else {
-            log.error("doGet: Authenticator service missing, cannot request authentication");
+            log.error("doGet: Authenticator service missing, cannot login");
         }
 
         // fall back to forbid access
         response.sendError(HttpServletResponse.SC_FORBIDDEN, "Cannot login");
     }
 
-    @Override
-    protected void doPost(SlingHttpServletRequest request,
-            SlingHttpServletResponse response) throws IOException {
-        response.sendRedirect(request.getRequestURI());
-    }
+    private boolean isSelf(final String resourcePath) {
+        // no resource, assume self
+        if (resourcePath == null) {
+            return true;
+        }
 
+        // login servlet is addressed
+        if (resourcePath.startsWith(LOGIN_SERVLET_PATH)) {
+            return true;
+        }
+
+        // not a prefix
+        return false;
+    }
 }

Added: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/LogoutServlet.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/LogoutServlet.java?rev=825501&view=auto
==============================================================================
--- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/LogoutServlet.java (added)
+++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/LogoutServlet.java Thu Oct 15 14:09:38 2009
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.engine.impl.auth;
+
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.servlets.SlingAllMethodsServlet;
+import org.apache.sling.engine.auth.Authenticator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * The <code>LogoutServlet</code> lets the Authenticator
+ * do the logout.
+ *
+ * @scr.component metatype="no"
+ * @scr.service interface="javax.servlet.Servlet"
+ * @scr.property name="service.description" value="Authenticator Logout Servlet"
+ * @scr.property name="service.vendor" value="The Apache Software Foundation"
+ * @scr.property name="sling.servlet.methods" values.0="GET" values.1="POST"
+ *
+ * @since 2.1
+ */
+public class LogoutServlet extends SlingAllMethodsServlet {
+
+    /** serialization UID */
+    private static final long serialVersionUID = -1L;
+
+    /** default log */
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    /** @scr.reference cardinality="0..1" policy="dynamic" */
+    private Authenticator authenticator;
+
+    /** The servlet is registered on this path.
+     *  @scr.property name="sling.servlet.paths" */
+    public static final String LOGIN_SERVLET_PATH = "/system/sling/logout";
+
+    @Override
+    protected void service(SlingHttpServletRequest request,
+            SlingHttpServletResponse response) {
+
+        Authenticator authenticator = this.authenticator;
+        if (authenticator != null) {
+            try {
+                authenticator.logout(request, response);
+                return;
+            } catch (IllegalStateException ise) {
+                log.error("service: Response already committed, cannot logout");
+                return;
+            }
+        }
+
+        log.error("service: Authenticator service missing, cannot logout");
+
+        // well, we don't really have something to say here, do we ?
+        response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+    }
+}

Propchange: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/LogoutServlet.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/LogoutServlet.java
------------------------------------------------------------------------------
    svn:keywords = Author Date Id Revision Rev Url

Modified: sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/SlingAuthenticator.java
URL: http://svn.apache.org/viewvc/sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/SlingAuthenticator.java?rev=825501&r1=825500&r2=825501&view=diff
==============================================================================
--- sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/SlingAuthenticator.java (original)
+++ sling/trunk/bundles/engine/src/main/java/org/apache/sling/engine/impl/auth/SlingAuthenticator.java Thu Oct 15 14:09:38 2009
@@ -20,8 +20,7 @@
 
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
+import java.util.Arrays;
 import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.Hashtable;
@@ -40,7 +39,6 @@
 
 import org.apache.sling.commons.osgi.OsgiUtil;
 import org.apache.sling.engine.EngineConstants;
-import org.apache.sling.engine.RequestUtil;
 import org.apache.sling.engine.auth.AuthenticationHandler;
 import org.apache.sling.engine.auth.AuthenticationInfo;
 import org.apache.sling.engine.auth.Authenticator;
@@ -122,7 +120,7 @@
 
     private int authHandlerTrackerCount;
 
-    private Map<String, Map<String, AuthenticationHandlerInfo[]>> authHandlerCache;
+    private Map<String, Map<String, AuthenticationHandlerHolder[]>> authHandlerCache;
 
     /** The name of the impersonation parameter */
     private String sudoParameterName;
@@ -255,24 +253,21 @@
             throw new IllegalStateException("Response already committed");
         }
 
-        AuthenticationHandlerInfo[] handlerInfos = findApplicableAuthenticationHandlers(request);
+        AuthenticationHandlerHolder[] handlerInfos = findApplicableAuthenticationHandlers(request);
         boolean done = false;
         for (int i = 0; !done && i < handlerInfos.length; i++) {
             if ( request.getPathInfo().startsWith(handlerInfos[i].path) ) {
                 log.debug(
-                    "requestAuthentication: requesting authentication using handler: {}",
+                    "login: requesting authentication using handler: {}",
                     handlerInfos[i]);
 
-                Object oldPathAttr = RequestUtil.setRequestAttribute(request, AuthenticationHandler.PATH_PROPERTY, handlerInfos[i].fullPath);
                 try {
-                    done = handlerInfos[i].handler.requestAuthentication(request, response);
+                    done = handlerInfos[i].requestAuthentication(request, response);
                 } catch (IOException ioe) {
                     log.error(
-                        "requestAuthentication: Failed sending authentication request through handler "
+                        "login: Failed sending authentication request through handler "
                             + handlerInfos[i] + ", access forbidden", ioe);
                     done = true;
-                } finally {
-                    RequestUtil.setRequestAttribute(request, AuthenticationHandler.PATH_PROPERTY, oldPathAttr);
                 }
             }
         }
@@ -280,12 +275,43 @@
         // no handler could send an authentication request, throw
         if (!done) {
             log.info(
-                "requestAuthentication: No handler for request ({} handlers available)",
+                "login: No handler for request ({} handlers available)",
                 handlerInfos.length);
             throw new NoAuthenticationHandlerException();
         }
     }
 
+    /**
+     * Logs out the user calling all applicable
+     * {@link org.apache.sling.engine.auth.AuthenticationHandler2}
+     * authentication handlers.
+     *
+     * @since 2.1
+     */
+    public void logout(HttpServletRequest request, HttpServletResponse response) {
+
+        // ensure the response is not committed yet
+        if (response.isCommitted()) {
+            throw new IllegalStateException("Response already committed");
+        }
+
+        AuthenticationHandlerHolder[] handlerInfos = findApplicableAuthenticationHandlers(request);
+        for (int i = 0; i < handlerInfos.length; i++) {
+            if (request.getPathInfo().startsWith(handlerInfos[i].path)) {
+                log.debug("logout: dropping authentication using handler: {}",
+                    handlerInfos[i]);
+
+                try {
+                    handlerInfos[i].dropAuthentication(request, response);
+                } catch (IOException ioe) {
+                    log.error(
+                        "logout: Failed dropping authentication through handler "
+                            + handlerInfos[i], ioe);
+                }
+            }
+        }
+    }
+
     // ----------- ManagedService interface -----------------------------------
 
     @SuppressWarnings("unchecked")
@@ -335,13 +361,13 @@
         return repo;
     }
 
-    private static Map<String,Map<String, AuthenticationHandlerInfo[]>> EMPTY_PROTOCOL_MAP = new HashMap<String, Map<String,AuthenticationHandlerInfo[]>>();
-    private static AuthenticationHandlerInfo[] EMPTY_INFO = new AuthenticationHandlerInfo[0];
+    private static Map<String,Map<String, AuthenticationHandlerHolder[]>> EMPTY_PROTOCOL_MAP = new HashMap<String, Map<String,AuthenticationHandlerHolder[]>>();
+    private static AuthenticationHandlerHolder[] EMPTY_INFO = new AuthenticationHandlerHolder[0];
 
-    private AuthenticationHandlerInfo[] findApplicableAuthenticationHandlers(HttpServletRequest request) {
-         Map<String, Map<String, AuthenticationHandlerInfo[]>> byProtocolMap = getAuthenticationHandlers();
+    private AuthenticationHandlerHolder[] findApplicableAuthenticationHandlers(HttpServletRequest request) {
+         Map<String, Map<String, AuthenticationHandlerHolder[]>> byProtocolMap = getAuthenticationHandlers();
 
-         Map<String, AuthenticationHandlerInfo[]> byHostMap = byProtocolMap.get(request.getScheme());
+         Map<String, AuthenticationHandlerHolder[]> byHostMap = byProtocolMap.get(request.getScheme());
          if (byHostMap == null) {
             byHostMap = byProtocolMap.get("");
          }
@@ -349,7 +375,7 @@
          String hostname = request.getServerName() +
             (request.getServerPort() != 80 && request.getServerPort() != 443 ? ":" + request.getServerPort() : "");
 
-         AuthenticationHandlerInfo[] infos = null;
+         AuthenticationHandlerHolder[] infos = null;
          if ( byHostMap != null ) {
              infos = byHostMap.get(hostname);
              if (infos == null) {
@@ -363,14 +389,14 @@
          return EMPTY_INFO;
     }
 
-    private Map<String, Map<String, AuthenticationHandlerInfo[]>> getAuthenticationHandlers() {
+    private Map<String, Map<String, AuthenticationHandlerHolder[]>> getAuthenticationHandlers() {
         if (authHandlerCache == null
             || authHandlerTrackerCount < authHandlerTracker.getTrackingCount()) {
             final ServiceReference[] services = authHandlerTracker.getServiceReferences();
             if ( services == null || services.length == 0 ) {
                 this.authHandlerCache = EMPTY_PROTOCOL_MAP;
             } else {
-                final Map<String, Map<String, List<AuthenticationHandlerInfo>>> byProtocolMap = new HashMap<String, Map<String,List<AuthenticationHandlerInfo>>>();
+                final Map<String, Map<String, List<AuthenticationHandlerHolder>>> byProtocolMap = new HashMap<String, Map<String,List<AuthenticationHandlerHolder>>>();
                 int regPathCount = 0;
 
                 for (int i = 0; i < services.length; i++) {
@@ -381,48 +407,21 @@
 
                         for(int m = 0; m < paths.length; m++) {
                             if ( paths[m] != null && paths[m].length() > 0 ) {
-                                String fullPath = paths[m];
-                                String path = fullPath;
-                                String host = "";
-                                String protocol = "";
-
-                                if(path.startsWith("http://") || path.startsWith("https://")) {
-                                    int idxProtocolEnd = path.indexOf("://");
-                                    protocol = path.substring(0,idxProtocolEnd);
-                                    path = path.substring(idxProtocolEnd + 1);
-                                }
-
-                                if (path.startsWith("//")) {
-                                    int idxHostEnd = path.indexOf("/",2);
-                                    idxHostEnd = idxHostEnd == -1 ? path.length() : idxHostEnd;
-
-                                    if(path.length() > 2) {
-                                        host = path.substring(2,idxHostEnd);
-                                        if(idxHostEnd < path.length()) {
-                                            path = path.substring(idxHostEnd);
-                                        } else {
-                                            path="/";
-                                        }
-                                    } else {
-                                        path="/";
-                                    }
-                                }
-
-                                AuthenticationHandlerInfo newInfo = new AuthenticationHandlerInfo(fullPath, path, host, protocol, handler);
+                                final AuthenticationHandlerHolder holder = new AuthenticationHandlerHolder(paths[m], handler);
 
-                                Map<String, List<AuthenticationHandlerInfo>> byHostMap = byProtocolMap.get(protocol);
+                                Map<String, List<AuthenticationHandlerHolder>> byHostMap = byProtocolMap.get(holder.protocol);
                                 if(byHostMap == null) {
-                                    byHostMap = new HashMap<String, List<AuthenticationHandlerInfo>>();
-                                    byProtocolMap.put(protocol, byHostMap);
+                                    byHostMap = new HashMap<String, List<AuthenticationHandlerHolder>>();
+                                    byProtocolMap.put(holder.protocol, byHostMap);
                                 }
 
-                                List<AuthenticationHandlerInfo> byPathList = byHostMap.get(host);
+                                List<AuthenticationHandlerHolder> byPathList = byHostMap.get(holder.host);
                                 if(byPathList == null) {
-                                    byPathList = new ArrayList<AuthenticationHandlerInfo>();
-                                    byHostMap.put(host, byPathList);
+                                    byPathList = new ArrayList<AuthenticationHandlerHolder>();
+                                    byHostMap.put(holder.host, byPathList);
                                 }
 
-                                byPathList.add(newInfo);
+                                byPathList.add(holder);
                                 regPathCount++;
                             }
                         }
@@ -431,25 +430,21 @@
                 if ( regPathCount == 0 ) {
                     authHandlerCache = EMPTY_PROTOCOL_MAP;
                 } else {
-                    authHandlerCache = new HashMap<String, Map<String,AuthenticationHandlerInfo[]>>();
+                    authHandlerCache = new HashMap<String, Map<String,AuthenticationHandlerHolder[]>>();
 
-                    for(Map.Entry<String, Map<String,List<AuthenticationHandlerInfo>>> protocolEntry : byProtocolMap.entrySet()) {
-                        Map<String,List<AuthenticationHandlerInfo>> hostMap = protocolEntry.getValue();
+                    for(Map.Entry<String, Map<String,List<AuthenticationHandlerHolder>>> protocolEntry : byProtocolMap.entrySet()) {
+                        Map<String,List<AuthenticationHandlerHolder>> hostMap = protocolEntry.getValue();
 
-                        Map<String, AuthenticationHandlerInfo[]> finalHostMap = authHandlerCache.get(protocolEntry.getKey());
+                        Map<String, AuthenticationHandlerHolder[]> finalHostMap = authHandlerCache.get(protocolEntry.getKey());
                         if(finalHostMap == null) {
-                            finalHostMap = new HashMap<String, AuthenticationHandlerInfo[]>();
+                            finalHostMap = new HashMap<String, AuthenticationHandlerHolder[]>();
                             authHandlerCache.put(protocolEntry.getKey(), finalHostMap);
                         }
 
-                        for(Map.Entry<String,List<AuthenticationHandlerInfo>> hostEntry : hostMap.entrySet()) {
-                            List<AuthenticationHandlerInfo> pathList = hostEntry.getValue();
-
-                            Collections.sort(pathList, AuthenticationHandlerInfoComparator.SINGLETON);
-
-                            final AuthenticationHandlerInfo[] authInfos =
-                                pathList.toArray(new AuthenticationHandlerInfo[pathList.size()]);
-
+                        for (Map.Entry<String, List<AuthenticationHandlerHolder>> hostEntry : hostMap.entrySet()) {
+                            final List<AuthenticationHandlerHolder> pathList = hostEntry.getValue();
+                            final AuthenticationHandlerHolder[] authInfos = pathList.toArray(new AuthenticationHandlerHolder[pathList.size()]);
+                            Arrays.sort(authInfos);
                             finalHostMap.put(hostEntry.getKey(), authInfos);
                         }
                     }
@@ -471,21 +466,13 @@
             pathInfo = "/";
         }
 
-        AuthenticationHandlerInfo[] local = findApplicableAuthenticationHandlers(request);
+        AuthenticationHandlerHolder[] local = findApplicableAuthenticationHandlers(request);
         for (int i = 0; i < local.length; i++) {
             if ( pathInfo.startsWith(local[i].path) ) {
-                Object oldPathAttr = RequestUtil.setRequestAttribute(request,
-                    AuthenticationHandler.PATH_PROPERTY, local[i].fullPath);
-                try {
-                    final AuthenticationInfo authInfo = local[i].handler.authenticate(
-                        request, response);
-                    if (authInfo != null) {
-                        return authInfo;
-                    }
-                } finally {
-                    RequestUtil.setRequestAttribute(request,
-                        AuthenticationHandler.PATH_PROPERTY, oldPathAttr);
-
+                final AuthenticationInfo authInfo = local[i].authenticate(
+                    request, response);
+                if (authInfo != null) {
+                    return authInfo;
                 }
             }
         }
@@ -698,35 +685,4 @@
         // return the session
         return session;
     }
-
-    protected static final class AuthenticationHandlerInfo {
-        public final String fullPath;
-        public final String path;
-        public final String host;
-        public final String protocol;
-        public final AuthenticationHandler handler;
-
-        public AuthenticationHandlerInfo(final String fullPath, final String p, final String host, final String protocol, final AuthenticationHandler h) {
-            this.fullPath = fullPath;
-            this.path = p;
-            this.host = host;
-            this.protocol = protocol;
-            this.handler = h;
-        }
-    }
-
-    protected static final class AuthenticationHandlerInfoComparator implements Comparator<AuthenticationHandlerInfo> {
-
-        public static final AuthenticationHandlerInfoComparator SINGLETON = new AuthenticationHandlerInfoComparator();
-        /**
-         * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
-         */
-        public int compare(AuthenticationHandlerInfo arg0,
-                AuthenticationHandlerInfo arg1) {
-            return arg0.path.compareTo(arg1.path) * -1;
-        }
-
-    }
-
-
 }