/* * 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 {@link SecurityContext} and optionally an * {@link AuthenticatedConnectionContext}. *
* 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: * *
* 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();
* }
* }
*
*/
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.
* * 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 { return createContext(new RootContext(), request); } }