Authentication has been edited by Felix Meschberger (Apr 26, 2009).

(View changes)

Content:

Authentication

This page is about how requests are authenticated in Sling. The process of authenticating client requests takes two steps: The first step extracts the credentials from the request and the second step tries to login to the JCR repository 1 . The former of these steps is extensible by providing AuthenticationHandler services, while the latter is coded into the SlingAuthenticator class.

But before getting to much into the details, lets step back and look at the various actors in the authentication game.

The SlingMaingServlet which is the main entry point into the Sling system for all request processing is registered with the OSGi HTTP Service. The servlet is registered together with a customized implementation of the OSGi HttpContext class. The HttpContext interface defines a handleSecurity method which is intended to authenticate the request. This method is implemented in Sling to use the SlingAuthenticator class which in turn uses AuthenticationHandler services to extract credentials from the request and login to the repository.

This sounds all very nice, but how is this linked together ? Lets look at the processing steps from the point a request is sent to a Sling system to the moment the request is finally entering the SlingMainServlet.service method:

1. Select registered servlet or resource First the HTTP Service implementation is analyzing the request URL to find a match for a servlet or resource registered with the HTTP Service. In the case of the Sling standalone application, the HTTP Service is implemented by a bundle which uses the Jetty Servlet container for the low level HTTP server functionality.
2. Call HttpContext.handleSecurity Now the HTTP Service implementation has to call the handleSecurity method of the HttpContext object with which the servlet or resource has been registered. This method returns true if the request should be serviced. If this method returns false the HTTP Service implementation terminates the request sending back any response which has been prepared by the handleSecurity method. Note, that the handleSecurity method must prepare the failure response sent to the client, the HTTP Service adds nothing here. If the handleSecurity method is successful, it must add two (or three) request attributes described below.
3. Call Servlet.service or spool resource After the handleSecurity method has succeeded, the HTTP Service either calls the Servlet.service method or sends back the requested resource depending on whether a servlet or a resource has been selected in the first step.

The important thing to note here is, that at the time the handleSecurity method is called, the SlingMainServlet is not yet in control of the request. So any functionality added by the SlingMainServlet, notably the SlingHttpServletRequest and SlingHttpServletResponse objects are not available to the implementation of the handleSecurity method.

HttpContext.handleSecurity

The HttpContext.handleSecurity method is implemented by the SlingMainServlet because this servlet implements the HttpContext interface itself. The handleSecurity method simply calls SlingAuthenticator.authenticate method and returns the result of this call. If the call fails, an error is logged and false is returned to not handle the request.

SlingAuthenticator

The SlingAuthenticator class is an internal class of the org.apache.sling.engine bundle, which also has the SlingMainServlet. In fact the single instance of this class is managed by the SlingMainServlet. The SlingAuthenticator class has the following basic features:

  • The authenticate method selects an AuthenticationHandler service appropriate for the request and calls the AuthenticationHandler.authenticate method to extract the credentials from the request. If no credentials could be extracted, the SlingAuthenticator.authenticate method can either admit the request as an anonymous request or request authentication from the client by calling its own login method.
  • The login method, which implements the login method of the Authenticator interface also selects an AuthenticationHandler service appropriate for the request. But this time, the AuthenticationHandler.requestAuthentication method is called, which is intended to send back to the client a response leading the client to provide credentials. This may be a HTML form or it may be a plain 401/UNAUTHORIZED response status to start HTTP authentication.
  • Maintains an internal list of AuthenticationHandler services. This list is consulted to forward the authenticate and login methods to the appropriate AuthenticationHandler

The authenticate method gets credentials from the AuthenticationHandler and logs into the JCR repository using those credentials. If the login is successful, the SlingAuthenticator sets the following request attributes:

Attribute Description
javax.jcr.Session The JCR Session. This attribute is used by the SlingMainServlet to create the ResourceResolver to be provided in the SlingHttpServletRequest.getResourceResolver method.
org.osgi.service.http.authentication.remote.user The user ID of the JCR Session. This attribute is used by the HTTP Service implementation to implement the HttpServletRequest.getRemoteUser method.
org.osgi.service.http.authentication.type The authentication type defined by the AuthenticationHandler. This attribute is used by the HTTP Service implementation to implement the HttpServletRequest.getAuthType method.

NOTE: Do NOT use the javax.jcr.Session request attribute in your Sling applications. This attribute must be considered an implementation specific to convey the JCR Session to the SlingMainServlet. In future versions of the Sling Engine bundle, this request attribute may not be present anymore. To get the JCR Session for the current request adapt the request's resource resolver to a JCR Session:

Session session = request.getResourceResolver().adaptTo(Session.class);

Hint: If you want to know whether a request is authenticated or not, you can inspect the result of the HttpServletRequest.getAuthType method: If this method returns null the request is not authenticated.

AuthenticationHandler

The AuthenticationHandler interface the defines the service API which may be implemented by authentication handlers registered as OSGi services. The AuthenticationHandler services have a single required service registration property which is used to identify requests to which the AuthenticationHandler service is applicable:

path One or more (array or vector) string values indicating the request URLs to which the AuthenticationHandler is applicable.

Each path may be an absolute URL, an URL with just the host/port and path or just a plain absolute path:

URL part Scheme Host/Port Path
Absolute URL must match must match request URL path is prefixed with the path
Host/Port with Path ignored must match request URL path is prefixed with the path
Path ignored ignored request URL path is prefixed with the path

When looking for an AuthenticationHandler the authentication handler is selected whose path is the longest match on the request URL. If the service is registered with Scheme and Host/Port, these must exactly match for the service to be eligible.

Authenticator

The Authenticator interface has been introduced in Rev. 768396 to implement SLING-938 (Refine initiaition of the authentication process). This interface allows SLING applications and error handlers to request the initiation of authentication.

org.apache.sling.engine.auth.Authenticator
/**
 * The <code>Authenticator</code> interface defines the service interface of the
 * authenticator used by the Sling engine. This service provides a method to
 * find an {...@link AuthenticationHandler} and call its
 * {...@link AuthenticationHandler#requestAuthentication(HttpServletRequest, HttpServletResponse)}
 * method.
 * <p>
 * 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 {

    /**
     * Finds an {...@link AuthenticationHandler} for the given request and call its
     * {...@link AuthenticationHandler#requestAuthentication(HttpServletRequest, HttpServletResponse)}
     * method to initiate an authentication process with the client.
     * <p>
     * This method must be called on an uncommitted response since the
     * implementation may want to reset the response to start 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 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);

}

This interface is implemented by the SlingAuthenticator class which is also registered under this service interface. The SlingAuthenticator implementation in fact already has an implementation of this method, which finds an AuthenticationHandler for the request and calls its requestAuthentication method.

The login method has three possible exit states:

Exit State Description
Normal An AuthenticationHandler could be selected to which the login request could be forwarded.
NoAuthenticationHandlerException No AuthenticationHandler could be selected to forward the login request to. In this case, the caller can proceed as appropriate. For example a servlet, which should just login a user may send back a 403/FORBIDDEN status because login is not possible. Or a 404/NOT FOUND handler, which tried to login as a fallback, may continue and send back the regular 404/NOT FOUND response.
IllegalStateException The response has already been committed and the login request cannot be processed. Normally to request login, the current response must be reset and a new response has to be prepared. This is only possible if the request has not yet been committed.

Footnotes
Reference Notes
1 Currently the credentials are always verified by trying to login to the JCR repository. Once an ResourceResolverFactory API has been added, the process of logging in is actualy replaced by a process of requesting a ResourceResolver from the ResourceResolverFactory

Reply via email to