mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Matthew Swift
21.04.2013 c3fd5d709ffdbb6d5a1609388b7bcaacda00c8b9
Partial fix for OPENDJ-694: Implement HTTP BASIC authentication

* implement a new HttpServletContextFactory which allows authentication modules to pass in pre-authenticated LDAP connection to lower Rest2LDAP layers for use when performing LDAP operations.
1 files added
178 ■■■■■ changed files
opendj3/opendj-rest2ldap-servlet/src/main/java/org/forgerock/opendj/rest2ldap/servlet/Rest2LDAPContextFactory.java 178 ●●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap-servlet/src/main/java/org/forgerock/opendj/rest2ldap/servlet/Rest2LDAPContextFactory.java
New file
@@ -0,0 +1,178 @@
/*
 * The contents of this file are subject to the terms of the Common Development and
 * Distribution License (the License). You may not use this file except in compliance with the
 * License.
 *
 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
 * specific language governing permission and limitations under the License.
 *
 * When distributing Covered Software, include this CDDL Header Notice in each file and include
 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
 * Header, with the fields enclosed by brackets [] replaced by your own identifying
 * information: "Portions copyright [year] [name of copyright owner]".
 *
 * Copyright 2012 ForgeRock AS.
 */
package org.forgerock.opendj.rest2ldap.servlet;
import javax.servlet.http.HttpServletRequest;
import org.forgerock.json.resource.Context;
import org.forgerock.json.resource.InternalServerErrorException;
import org.forgerock.json.resource.ResourceException;
import org.forgerock.json.resource.RootContext;
import org.forgerock.json.resource.SecurityContext;
import org.forgerock.json.resource.servlet.HttpServletContextFactory;
import org.forgerock.json.resource.servlet.SecurityContextFactory;
import org.forgerock.opendj.ldap.Connection;
import org.forgerock.opendj.rest2ldap.AuthenticatedConnectionContext;
/**
 * An HTTP servlet context factory which will create a {@link Context} chain
 * comprising of a {@linkn SecurityContext} and optionally an
 * {@link AuthenticatedConnectionContext}.
 * <p>
 * This class provides integration between Rest2LDAP HTTP Servlets and the
 * {@link Rest2LDAPAuthnFilter}, by providing a mechanism allowing the filter to
 * pass a pre-authenticated LDAP connection through to the underlying Rest2LDAP
 * implementation for use when performing subsequent LDAP operations. The
 * following code illustrates how an authentication Servlet filter can populate
 * the attributes:
 *
 * <pre>
 * public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
 *     // Authenticate the user.
 *     String username = getUserName(request);
 *     String password = getPassword(request);
 *     final Connection connection = getLDAPConnection();
 *
 *     // Publish the authenticated connection.
 *     try {
 *         connection.bind(username, password.toCharArray());
 *         request.setAttribute(ATTRIBUTE_AUTHN_CONNECTION, connection);
 *     } catch (ErrorResultException e) {
 *         // Fail the HTTP request.
 *         response.setStatus(...);
 *         return;
 *     }
 *
 *     // Invoke the rest of the filter chain and then release the LDAP connection once
 *     // processing has completed. Note that this assumes that the filter chain is
 *     // processes requests synchronous.
 *     try {
 *         chain.doFilter(request, response);
 *     } finally {
 *         connection.close();
 *     }
 * }
 * </pre>
 */
public final class Rest2LDAPContextFactory implements HttpServletContextFactory {
    /**
     * The name of the HTTP Servlet Request attribute where this factory expects
     * to find the authenticated user's authentication ID. The name of this
     * attribute is {@code org.forgerock.security.authcid} and it MUST contain a
     * {@code String} if it is present.
     *
     * @see AuthenticatedConnectionContext
     */
    public static final String ATTRIBUTE_AUTHN_CONNECTION =
            "org.forgerock.opendj.rest2ldap.authn-connection";
    // Singleton instance.
    private static final Rest2LDAPContextFactory INSTANCE = new Rest2LDAPContextFactory();
    /**
     * Returns the singleton context factory which can be used for obtaining
     * context information from a HTTP servlet request.
     * <p>
     * This method is named {@code getHttpServletContextFactory} so that it can
     * easily be used for
     * {@link org.forgerock.json.resource.servlet.HttpServlet#getHttpServletContextFactory
     * configuring} JSON Resource Servlets.
     *
     * @return The singleton context factory.
     */
    public static Rest2LDAPContextFactory getHttpServletContextFactory() {
        return INSTANCE;
    }
    private Rest2LDAPContextFactory() {
        // Prevent instantiation.
    }
    /**
     * Creates a new {@link Context} chain comprising of the provided parent
     * context(s), a {@link SecurityContext} obtained using a
     * {@link SecurityContextFactory} , and optionally a
     * {@code AuthenticatedConnectionContext}. The authenticated connection will
     * be obtained from the {@link #ATTRIBUTE_AUTHN_CONNECTION} attribute
     * contained in the provided HTTP servlet request. If the attribute is not
     * present then the {@code AuthenticatedConnectionContext} will not be
     * created.
     *
     * @param parent
     *            The parent context.
     * @param request
     *            The HTTP servlet request from which the security and
     *            authenticated connection attributes should be obtained.
     * @return A new {@link Context} chain comprising of the provided parent
     *         context(s), a {@link SecurityContext} obtained using a
     *         {@link SecurityContextFactory} , and optionally a
     *         {@code AuthenticatedConnectionContext}.
     * @throws ResourceException
     *             If one of the attributes was present but had the wrong type.
     */
    public Context createContext(final Context parent, final HttpServletRequest request)
            throws ResourceException {
        // First get the security context.
        final Context securityContext =
                SecurityContextFactory.getHttpServletContextFactory()
                        .createContext(parent, request);
        // Now append the pre-authenticated connection context if required.
        final Connection connection;
        try {
            connection = (Connection) request.getAttribute(ATTRIBUTE_AUTHN_CONNECTION);
        } catch (final ClassCastException e) {
            throw new InternalServerErrorException(
                    "The rest2ldap authenticated connection context could not be "
                            + "created because the connection attribute, "
                            + ATTRIBUTE_AUTHN_CONNECTION + ", contained in the HTTP "
                            + "servlet request did not have the correct type", e);
        }
        if (connection != null) {
            return new AuthenticatedConnectionContext(securityContext, connection);
        } else {
            return securityContext;
        }
    }
    /**
     * Creates a new {@link Context} chain comprising of a {@link RootContext},
     * a {@link SecurityContext} obtained using a {@link SecurityContextFactory}
     * , and optionally a {@code AuthenticatedConnectionContext}. The
     * authenticated connection will be obtained from the
     * {@link #ATTRIBUTE_AUTHN_CONNECTION} attribute contained in the provided
     * HTTP servlet request. If the attribute is not present then the
     * {@code AuthenticatedConnectionContext} will not be created.
     *
     * @param request
     *            The HTTP servlet request from which the security and
     *            authenticated connection attributes should be obtained.
     * @return A new {@link Context} chain comprising of a {@link RootContext},
     *         a {@link SecurityContext} obtained using a
     *         {@link SecurityContextFactory} , and optionally a
     *         {@code AuthenticatedConnectionContext}.
     * @throws ResourceException
     *             If one of the attributes was present but had the wrong type.
     */
    @Override
    public Context createContext(final HttpServletRequest request) throws ResourceException {
        final Context securityContext =
                SecurityContextFactory.getHttpServletContextFactory().createContext(request);
        return createContext(securityContext, request);
    }
}