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;
- }
-
- }
-
-
}