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

Matthew Swift
22.01.2013 f3612b1aa023f12906a71cb12c6ca1cae12aa5dd
Partial fix for OPENDJ-694: Implement HTTP BASIC authentication

* make authorization policy configuration more user friendly and explicit.
1 files added
5 files modified
149 ■■■■ changed files
opendj3/opendj-rest2ldap-servlet/src/main/java/org/forgerock/opendj/rest2ldap/servlet/Rest2LDAPConnectionFactoryProvider.java 11 ●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap-servlet/src/main/webapp/opendj-rest2ldap-servlet.json 23 ●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AuthorizationPolicy.java 42 ●●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Config.java 30 ●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Context.java 8 ●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LDAP.java 35 ●●●● patch | view | raw | blame | history
opendj3/opendj-rest2ldap-servlet/src/main/java/org/forgerock/opendj/rest2ldap/servlet/Rest2LDAPConnectionFactoryProvider.java
@@ -28,6 +28,7 @@
import org.forgerock.json.resource.ConnectionFactory;
import org.forgerock.json.resource.Resources;
import org.forgerock.json.resource.Router;
import org.forgerock.opendj.rest2ldap.AuthorizationPolicy;
import org.forgerock.opendj.rest2ldap.Rest2LDAP;
import org.forgerock.opendj.rest2ldap.Rest2LDAP.Builder;
@@ -77,8 +78,13 @@
            final JsonValue configuration = new JsonValue(content);
            // Parse the authorization configuration.
            final AuthorizationPolicy authzPolicy =
                    configuration.get("servlet").get("authorizationPolicy").required().asEnum(
                            AuthorizationPolicy.class);
            final String proxyAuthzTemplate =
                    configuration.get("servlet").get("proxyAuthzIdTemplate").asString();
            // Parse the connection factory if present.
            final String ldapFactoryName =
                    configuration.get("servlet").get("ldapConnectionFactory").asString();
            final org.forgerock.opendj.ldap.ConnectionFactory ldapFactory;
@@ -96,8 +102,9 @@
            for (final String mappingUrl : mappings.keys()) {
                final JsonValue mapping = mappings.get(mappingUrl);
                final CollectionResourceProvider provider =
                        Rest2LDAP.builder().connectionFactory(ldapFactory).useProxiedAuthorization(
                                proxyAuthzTemplate).configureMapping(mapping).build();
                        Rest2LDAP.builder().connectionFactory(ldapFactory).authorizationPolicy(
                                authzPolicy).proxyAuthzIdTemplate(proxyAuthzTemplate)
                                .configureMapping(mapping).build();
                router.addRoute(mappingUrl, provider);
            }
            return Resources.newInternalConnectionFactory(router);
opendj3/opendj-rest2ldap-servlet/src/main/webapp/opendj-rest2ldap-servlet.json
@@ -100,19 +100,32 @@
    "servlet" : {
        // The connection factory which will be used for performing LDAP
        // operations. Pre-authenticated connections passed through from the
        // authentication filter see "reuseAuthenticatedConnection") will be
        // authentication filter (see "reuseAuthenticatedConnection") will be
        // used in preference to this factory. Specifically, a connection
        // factory does not need to be configured if a connection will always
        // be passed on from the filter, which may not always be the case
        // if the filter is configured to use HTTP sessions.
        "ldapConnectionFactory" : "root",
        
        // The AuthzID template which will be used for proxied authorization. If
        // no template is specified then proxied authorization will be disabled.
        // Specifies how LDAP authorization should be performed. The method
        // must be one of:
        //
        // "none"        - use connections acquired from the LDAP connection
        //                 factory. Don't use proxied authorization, and don't
        //                 use cached pre-authenticated connections,
        // "reuse"       - use the connection obtained during LDAP
        //                 authentication. If no connection was passed through
        //                 the authorization will fail,
        // "proxy"       - use proxied authorization with an authorization ID
        //                 derived from the "proxyAuthzIdTemplate". Proxied
        //                 authorization will only be used if there is no
        //                 pre-authenticated connection available.
        "authorizationPolicy" : "none",
        // The AuthzID template which will be used for proxied authorization.
        // The template should contain fields which are expected to be found in
        // the security context create during authentication, e.g. "dn" and "id".
        // "proxyAuthzIdTemplate" : "dn:{dn}",
        "proxyAuthzIdTemplate" : "dn:{dn}",
        
        // The REST APIs and their LDAP attribute mappings.
        "mappings" : {
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/AuthorizationPolicy.java
New file
@@ -0,0 +1,42 @@
/*
 * 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 2013 ForgeRock AS.
 */
package org.forgerock.opendj.rest2ldap;
/**
 * The policy which should be for performing authorization.
 */
public enum AuthorizationPolicy {
    /**
     * Use connections acquired from the LDAP connection factory. Don't use
     * proxied authorization, and don't use cached pre-authenticated
     * connections.
     */
    NONE,
    /**
     * Use the connection obtained during LDAP authentication. If no connection
     * was passed through the authorization will fail.
     */
    REUSE,
    /**
     * Use proxied authorization with an authorization ID derived from the
     * proxied authorization ID template. Proxied authorization will only be
     * used if there is no pre-authenticated connection available.
     */
    PROXY;
}
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Config.java
@@ -25,14 +25,17 @@
final class Config {
    private final ConnectionFactory factory;
    private final DecodeOptions options;
    private final AuthorizationPolicy authzPolicy;
    private final AuthzIdTemplate proxiedAuthzTemplate;
    private final ReadOnUpdatePolicy readOnUpdatePolicy;
    private final Schema schema;
    Config(final ConnectionFactory factory, final ReadOnUpdatePolicy readOnUpdatePolicy,
            final AuthzIdTemplate proxiedAuthzTemplate, final Schema schema) {
            final AuthorizationPolicy authzPolicy, final AuthzIdTemplate proxiedAuthzTemplate,
            final Schema schema) {
        this.factory = factory;
        this.readOnUpdatePolicy = readOnUpdatePolicy;
        this.authzPolicy = authzPolicy;
        this.proxiedAuthzTemplate = proxiedAuthzTemplate;
        this.schema = schema;
        this.options = new DecodeOptions().setSchema(schema);
@@ -61,12 +64,22 @@
    }
    /**
     * Returns the authorization policy which should be used for performing LDAP
     * operations.
     *
     * @return The authorization policy which should be used for performing LDAP
     *         operations.
     */
    AuthorizationPolicy getAuthorizationPolicy() {
        return authzPolicy;
    }
    /**
     * Returns the authorization ID template which should be used when proxied
     * authorization is enabled.
     *
     * @return The authorization ID template which should be used when proxied
     *         authorization is enabled, or {@code null} if proxied
     *         authorization is disabled.
     *         authorization is enabled.
     */
    AuthzIdTemplate getProxiedAuthorizationTemplate() {
        return proxiedAuthzTemplate;
@@ -93,15 +106,4 @@
    Schema schema() {
        return schema;
    }
    /**
     * Returns {@code true} if the proxied authorization should be used for
     * authorizing LDAP requests.
     *
     * @return {@code true} if the proxied authorization should be used for
     *         authorizing LDAP requests.
     */
    boolean useProxiedAuthorization() {
        return proxiedAuthzTemplate != null;
    }
}
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Context.java
@@ -205,7 +205,10 @@
    Context(final Config config, final ServerContext context) {
        this.config = config;
        this.context = context;
        if (context.containsContext(AuthenticatedConnectionContext.class)) {
        // Re-use the pre-authenticated connection if available and the authorization policy allows.
        if (config.getAuthorizationPolicy() != AuthorizationPolicy.NONE
                && context.containsContext(AuthenticatedConnectionContext.class)) {
            final Connection connection =
                    context.asContext(AuthenticatedConnectionContext.class).getConnection();
            this.preAuthenticatedConnection = connection != null ? wrap(connection) : null;
@@ -265,7 +268,8 @@
         * cached connection since cached connections are supposed to have been
         * pre-authenticated and therefore do not require proxied authorization.
         */
        if (preAuthenticatedConnection == null && config.useProxiedAuthorization()) {
        if (preAuthenticatedConnection == null
                && config.getAuthorizationPolicy() == AuthorizationPolicy.PROXY) {
            if (context.containsContext(SecurityContext.class)) {
                try {
                    final SecurityContext securityContext =
opendj3/opendj-rest2ldap/src/main/java/org/forgerock/opendj/rest2ldap/Rest2LDAP.java
@@ -71,6 +71,7 @@
        private ConnectionFactory factory;
        private MVCCStrategy mvccStrategy;
        private NameStrategy nameStrategy;
        private AuthorizationPolicy authzPolicy = AuthorizationPolicy.NONE;
        private AuthzIdTemplate proxiedAuthzTemplate;
        private ReadOnUpdatePolicy readOnUpdatePolicy = CONTROLS;
        private AttributeMapper rootMapper;
@@ -105,13 +106,30 @@
            if (rootMapper == null) {
                throw new IllegalStateException("No mappings provided");
            }
            if (proxiedAuthzTemplate != null && factory == null) {
                throw new IllegalStateException(
                        "No connection factory specified for use with proxied authorization");
            switch (authzPolicy) {
            case NONE:
                if (factory == null) {
                    throw new IllegalStateException(
                            "A connection factory must be specified when the authorization policy is 'none'");
                }
                break;
            case PROXY:
                if (proxiedAuthzTemplate == null) {
                    throw new IllegalStateException(
                            "Proxied authorization enabled but no template defined");
                }
                if (factory == null) {
                    throw new IllegalStateException(
                            "A connection factory must be specified when using proxied authorization");
                }
                break;
            case REUSE:
                // This is always ok.
                break;
            }
            return new LDAPCollectionResourceProvider(baseDN, rootMapper, nameStrategy,
                    mvccStrategy, new Config(factory, readOnUpdatePolicy, proxiedAuthzTemplate,
                            schema), additionalLDAPAttributes);
                    mvccStrategy, new Config(factory, readOnUpdatePolicy, authzPolicy,
                            proxiedAuthzTemplate, schema), additionalLDAPAttributes);
        }
        /**
@@ -302,7 +320,12 @@
            return useEtagAttribute(ad(attribute));
        }
        public Builder useProxiedAuthorization(final String template) {
        public Builder authorizationPolicy(final AuthorizationPolicy policy) {
            this.authzPolicy = ensureNotNull(policy);
            return this;
        }
        public Builder proxyAuthzIdTemplate(final String template) {
            this.proxiedAuthzTemplate = template != null ? new AuthzIdTemplate(template) : null;
            return this;
        }