You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by tr...@apache.org on 2014/02/10 23:57:49 UTC

svn commit: r1566804 - in /jackrabbit/oak/trunk: ./ oak-auth-ldap/ oak-auth-ldap/src/ oak-auth-ldap/src/main/ oak-auth-ldap/src/main/java/ oak-auth-ldap/src/main/java/org/ oak-auth-ldap/src/main/java/org/apache/ oak-auth-ldap/src/main/java/org/apache/j...

Author: tripod
Date: Mon Feb 10 22:57:48 2014
New Revision: 1566804

URL: http://svn.apache.org/r1566804
Log:
OAK-516 Create LdapLoginModule based on ExternalLoginModule

- create new bundle for auth-ldap

Added:
    jackrabbit/oak/trunk/oak-auth-ldap/
    jackrabbit/oak/trunk/oak-auth-ldap/README.md
    jackrabbit/oak/trunk/oak-auth-ldap/pom.xml
    jackrabbit/oak/trunk/oak-auth-ldap/src/
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapGroup.java
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapIdentity.java
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapIdentityProvider.java
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapProviderConfig.java
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapSettings.java
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapUser.java
    jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/package-info.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.java
Removed:
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapGroup.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapIdentity.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapIdentityProvider.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapLoginModule.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapProviderConfig.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapSettings.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapUser.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/package-info.java
    jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModule.java
Modified:
    jackrabbit/oak/trunk/oak-core/pom.xml
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapLoginTestBase.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTest.java
    jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestLoginModule.java
    jackrabbit/oak/trunk/pom.xml

Added: jackrabbit/oak/trunk/oak-auth-ldap/README.md
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-ldap/README.md?rev=1566804&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-ldap/README.md (added)
+++ jackrabbit/oak/trunk/oak-auth-ldap/README.md Mon Feb 10 22:57:48 2014
@@ -0,0 +1,2 @@
+Oak LDAP Authentication Support
+===============================

Added: jackrabbit/oak/trunk/oak-auth-ldap/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-ldap/pom.xml?rev=1566804&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-ldap/pom.xml (added)
+++ jackrabbit/oak/trunk/oak-auth-ldap/pom.xml Mon Feb 10 22:57:48 2014
@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+   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.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd ">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.jackrabbit</groupId>
+        <artifactId>oak-parent</artifactId>
+        <version>0.16-SNAPSHOT</version>
+        <relativePath>../oak-parent/pom.xml</relativePath>
+    </parent>
+
+    <artifactId>oak-auth-ldap</artifactId>
+    <name>Oak LDAP Authentication Support</name>
+    <packaging>bundle</packaging>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <Import-Package>
+                            !antlr.*,
+                            !org.dom4j.*,
+                            !org.apache.mina.*,
+                            !org.xmlpull.v1,
+                            *
+                        </Import-Package>
+                        <Embed-Dependency>
+                            api-all,commons-pool,commons-lang
+                        </Embed-Dependency>
+                    </instructions>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-scr-plugin</artifactId>
+            </plugin>
+        </plugins>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.apache.rat</groupId>
+                    <artifactId>apache-rat-plugin</artifactId>
+                    <configuration>
+                        <excludes/>
+                    </configuration>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+
+    <dependencies>
+        <!-- embedded apache directory client and dependencies-->
+        <dependency>
+            <groupId>org.apache.directory.api</groupId>
+            <artifactId>api-all</artifactId>
+            <version>1.0.0-M20</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-pool</groupId>
+            <artifactId>commons-pool</artifactId>
+            <version>1.6</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+            <version>2.6</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- Optional OSGi dependencies, used only when running within OSGi -->
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.jaas</artifactId>
+            <version>0.0.1-R1560269</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>biz.aQute.bnd</groupId>
+            <artifactId>bndlib</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>oak-core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>oak-commons</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>1.5</version>
+        </dependency>
+
+        <!-- JCR and Jackrabbit dependencies -->
+        <dependency>
+            <groupId>javax.jcr</groupId>
+            <artifactId>jcr</artifactId>
+            <version>2.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>jackrabbit-api</artifactId>
+            <version>${jackrabbit.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.jackrabbit</groupId>
+            <artifactId>jackrabbit-jcr-commons</artifactId>
+            <version>${jackrabbit.version}</version>
+        </dependency>
+
+        <!-- Logging -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+
+        <!-- Findbugs annotations -->
+        <dependency>
+            <groupId>com.google.code.findbugs</groupId>
+            <artifactId>jsr305</artifactId>
+            <version>2.0.0</version>
+            <scope>provided</scope>
+        </dependency>
+
+        <!-- Test Dependencies -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+            <version>1.3.158</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>jul-to-slf4j</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>ch.qos.logback</groupId>
+            <artifactId>logback-classic</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.directory.server</groupId>
+            <artifactId>apacheds-server-unit</artifactId>
+            <version>1.5.5</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+</project>

Added: jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapGroup.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapGroup.java?rev=1566804&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapGroup.java (added)
+++ jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapGroup.java Mon Feb 10 22:57:48 2014
@@ -0,0 +1,27 @@
+/*
+ * 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.jackrabbit.oak.security.authentication.ldap.impl;
+
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalGroup;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityRef;
+
+public class LdapGroup extends LdapIdentity implements ExternalGroup {
+
+    public LdapGroup(LdapIdentityProvider provider, ExternalIdentityRef ref, String id) {
+        super(provider, ref, id);
+    }
+}

Added: jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapIdentity.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapIdentity.java?rev=1566804&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapIdentity.java (added)
+++ jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapIdentity.java Mon Feb 10 22:57:48 2014
@@ -0,0 +1,102 @@
+/*
+ * 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.jackrabbit.oak.security.authentication.ldap.impl;
+
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalGroup;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentity;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityRef;
+import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
+
+/**
+ * Implements an identity that is provided by the {@link LdapIdentityProvider}.
+ */
+public abstract class LdapIdentity implements ExternalIdentity {
+
+    private final LdapIdentityProvider provider;
+
+    private final ExternalIdentityRef ref;
+
+    private final String id;
+
+    private final Map<String, Object> properties = new HashMap<String, Object>();
+
+    protected LdapIdentity(LdapIdentityProvider provider, ExternalIdentityRef ref, String id) {
+        this.provider = provider;
+        this.ref = ref;
+        this.id = id;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Nonnull
+    @Override
+    public ExternalIdentityRef getExternalId() {
+        return ref;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Nonnull
+    @Override
+    public String getId() {
+        return id;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getIntermediatePath() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Nonnull
+    @Override
+    public Iterable<? extends ExternalGroup> getGroups() {
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Nonnull
+    @Override
+    public Map<String, Object> getProperties() {
+        return properties;
+    }
+
+    private Principal principal;
+    @Override
+    public Principal getPrincipal() {
+        if (principal == null) {
+            principal = new PrincipalImpl(getId());
+        }
+        return principal;
+    }
+
+}

Added: jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapIdentityProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapIdentityProvider.java?rev=1566804&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapIdentityProvider.java (added)
+++ jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapIdentityProvider.java Mon Feb 10 22:57:48 2014
@@ -0,0 +1,273 @@
+/*************************************************************************
+ *
+ * ADOBE CONFIDENTIAL
+ * ___________________
+ *
+ *  Copyright ${today.year} Adobe Systems Incorporated
+ *  All Rights Reserved.
+ *
+ * NOTICE:  All information contained herein is, and remains
+ * the property of Adobe Systems Incorporated and its suppliers,
+ * if any.  The intellectual and technical concepts contained
+ * herein are proprietary to Adobe Systems Incorporated and its
+ * suppliers and are protected by trade secret or copyright law.
+ * Dissemination of this information or reproduction of this material
+ * is strictly forbidden unless prior written permission is obtained
+ * from Adobe Systems Incorporated.
+ **************************************************************************/
+package org.apache.jackrabbit.oak.security.authentication.ldap.impl;
+
+import java.io.IOException;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.jcr.Credentials;
+import javax.security.auth.login.LoginException;
+
+import org.apache.directory.api.ldap.model.cursor.CursorException;
+import org.apache.directory.api.ldap.model.cursor.SearchCursor;
+import org.apache.directory.api.ldap.model.entry.Attribute;
+import org.apache.directory.api.ldap.model.entry.Entry;
+import org.apache.directory.api.ldap.model.exception.LdapException;
+import org.apache.directory.api.ldap.model.exception.LdapInvalidAttributeValueException;
+import org.apache.directory.api.ldap.model.message.Response;
+import org.apache.directory.api.ldap.model.message.SearchRequest;
+import org.apache.directory.api.ldap.model.message.SearchRequestImpl;
+import org.apache.directory.api.ldap.model.message.SearchResultEntry;
+import org.apache.directory.api.ldap.model.message.SearchScope;
+import org.apache.directory.ldap.client.api.LdapConnection;
+import org.apache.directory.ldap.client.api.LdapNetworkConnection;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalGroup;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentity;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityException;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityProvider;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityRef;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalUser;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@code LdapIdentityProvider} implements an external identity provider that reads users and groups from an ldap
+ * source.
+ *
+ * Please refer to {@link LdapProviderConfig} for configuration options.
+ */
+@Component(
+        // note that the metatype information is generated from LdapProviderConfig
+        policy = ConfigurationPolicy.REQUIRE
+)
+@Service
+public class LdapIdentityProvider implements ExternalIdentityProvider {
+
+    /**
+     * default logger
+     */
+    private static final Logger log = LoggerFactory.getLogger(LdapIdentityProvider.class);
+
+    /**
+     * internal configuration
+     */
+    private LdapProviderConfig config;
+
+    /**
+     * Default constructor for OSGi
+     */
+    public LdapIdentityProvider() {
+    }
+
+    /**
+     * Constructor for non-OSGi cases.
+     * @param config the configuration
+     */
+    public LdapIdentityProvider(LdapProviderConfig config) {
+        this.config = config;
+    }
+
+    @Activate
+    private void activate(Map<String, Object> properties) {
+        ConfigurationParameters cfg = ConfigurationParameters.of(properties);
+        config = LdapProviderConfig.of(cfg);
+        log.error("***** activate {}: {}", this, properties);
+    }
+
+    @Nonnull
+    @Override
+    public String getName() {
+        return config.getName();
+    }
+
+    @Override
+    public ExternalIdentity getIdentity(@Nonnull ExternalIdentityRef ref) throws ExternalIdentityException {
+        if (!isMyRef(ref)) {
+            return null;
+        }
+
+        LdapConnection connection = connect();
+        try {
+            Entry entry = connection.lookup(ref.getId(), "*");
+            if (entry.hasObjectClass(config.getUserConfig().getObjectClasses())) {
+                return createUser(entry, null);
+            } else if (entry.hasObjectClass(config.getGroupConfig().getObjectClasses())) {
+                return createGroup(entry, null);
+            } else {
+                log.warn("referenced identity is neither user or group: {}", ref.getString());
+                return null;
+            }
+        } catch (LdapException e) {
+            log.error("Error during ldap lookup", e);
+            throw new ExternalIdentityException("Error during ldap lookup.", e);
+        } finally {
+            disconnect(connection);
+        }
+    }
+
+    @Override
+    public ExternalUser getUser(@Nonnull String userId) throws ExternalIdentityException {
+        LdapConnection connection = connect();
+        try {
+            Entry entry = getEntry(connection, config.getUserConfig(), userId);
+            if (entry != null) {
+                return createUser(entry, userId);
+            } else {
+                return null;
+            }
+        } catch (LdapException e) {
+            log.error("Error during ldap lookup", e);
+            throw new ExternalIdentityException("Error during ldap lookup.", e);
+        } catch (CursorException e) {
+            log.error("Error during ldap lookup", e);
+            throw new ExternalIdentityException("Error during ldap lookup.", e);
+        } finally {
+            disconnect(connection);
+        }
+    }
+
+    @Override
+    public ExternalGroup getGroup(@Nonnull String name) throws ExternalIdentityException {
+        LdapConnection connection = connect();
+        try {
+            Entry entry = getEntry(connection, config.getGroupConfig(), name);
+            if (entry != null) {
+                return createGroup(entry, name);
+            } else {
+                return null;
+            }
+        } catch (LdapException e) {
+            log.error("Error during ldap lookup", e);
+            throw new ExternalIdentityException("Error during ldap lookup.", e);
+        } catch (CursorException e) {
+            log.error("Error during ldap lookup", e);
+            throw new ExternalIdentityException("Error during ldap lookup.", e);
+        } finally {
+            disconnect(connection);
+        }
+    }
+
+    private Entry getEntry(LdapConnection connection, LdapProviderConfig.Identity idConfig, String id)
+            throws CursorException, LdapException {
+        String searchFilter = idConfig.getSearchFilter(id);
+
+        // Create the SearchRequest object
+        SearchRequest req = new SearchRequestImpl();
+        req.setScope(SearchScope.SUBTREE);
+        req.addAttributes("*");
+        req.setTimeLimit(config.getSearchTimeout());
+        req.setBase(idConfig.getBaseDN());
+        req.setFilter(searchFilter);
+
+        log.debug("Searching entries below {} with {}", idConfig.getBaseDN(), searchFilter);
+
+        // Process the request
+        SearchCursor searchCursor = connection.search(req);
+        while (searchCursor.next()) {
+            Response response = searchCursor.get();
+
+            // process the SearchResultEntry
+            if (response instanceof SearchResultEntry) {
+                Entry resultEntry = ((SearchResultEntry) response).getEntry();
+                if (searchCursor.next()) {
+                    log.warn("search for {} returned more than one entry. discarding additional ones.", searchFilter);
+                }
+                return resultEntry;
+            }
+        }
+        return null;
+    }
+
+    private ExternalUser createUser(Entry e, String id)
+            throws LdapInvalidAttributeValueException {
+        ExternalIdentityRef ref = new ExternalIdentityRef(e.getDn().getName(), this.getName());
+        if (id == null) {
+            id = e.get(config.getUserConfig().getIdAttribute()).getString();
+        }
+        LdapUser user = new LdapUser(this, ref, id, null);
+        Map<String, Object> props = user.getProperties();
+        for (Attribute attr: e.getAttributes()) {
+            if (attr.isHumanReadable()) {
+                props.put(attr.getId(), attr.getString());
+            }
+        }
+        return user;
+    }
+
+    private ExternalGroup createGroup(Entry e, String name)
+            throws LdapInvalidAttributeValueException {
+        ExternalIdentityRef ref = new ExternalIdentityRef(e.getDn().getName(), this.getName());
+        if (name == null) {
+            name = e.get(config.getGroupConfig().getIdAttribute()).getString();
+        }
+        LdapGroup group = new LdapGroup(this, ref, name);
+        Map<String, Object> props = group.getProperties();
+        for (Attribute attr: e.getAttributes()) {
+            if (attr.isHumanReadable()) {
+                props.put(attr.getId(), attr.getString());
+            }
+        }
+        return group;
+
+    }
+
+    private LdapConnection connect() throws ExternalIdentityException {
+        try {
+            LdapConnection connection = new LdapNetworkConnection(config.getHost(), config.getPort(), config.isUseSSL());
+            if (config.getBindDN().length() > 0) {
+                connection.bind(config.getBindDN(), config.getBindPassword());
+            } else {
+                connection.bind();
+            }
+            return connection;
+        } catch (LdapException e) {
+            log.error("Error while connecting to the ldap server.", e);
+            throw new ExternalIdentityException("Error while connecting and binding to the ldap server", e);
+        }
+    }
+
+    private void disconnect(LdapConnection connection) throws ExternalIdentityException {
+        try {
+            connection.unBind();
+        } catch (LdapException e) {
+            log.error("Error while unbinding from the ldap server.", e);
+        }
+        try {
+            connection.close();
+        } catch (IOException e) {
+            log.error("Error while disconnecting from the ldap server.", e);
+        }
+    }
+
+    @Override
+    public ExternalUser authenticate(@Nonnull Credentials credentials) throws ExternalIdentityException, LoginException {
+        return null;
+    }
+
+    private boolean isMyRef(ExternalIdentityRef ref) {
+        final String refProviderName = ref.getProviderName();
+        return refProviderName == null || refProviderName.length() == 0 || getName().equals(refProviderName);
+    }
+
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapProviderConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapProviderConfig.java?rev=1566804&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapProviderConfig.java (added)
+++ jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapProviderConfig.java Mon Feb 10 22:57:48 2014
@@ -0,0 +1,264 @@
+/*
+ * 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.jackrabbit.oak.security.authentication.ldap.impl;
+
+import javax.annotation.Nonnull;
+
+import org.apache.directory.api.ldap.model.exception.LdapInvalidDnException;
+import org.apache.directory.api.ldap.model.filter.FilterEncoder;
+import org.apache.directory.api.ldap.model.name.Dn;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+
+/**
+ * Configuration of the ldap provider.
+ */
+@Component(
+        label = "Apache Jackrabbit Oak LDAP Identity Provider",
+        name = "org.apache.jackrabbit.oak.security.authentication.ldap.impl.LdapIdentityProvider",
+        configurationFactory = true,
+        metatype = true,
+        ds = false
+)
+public class LdapProviderConfig {
+
+    public static final String PARAM_NAME_DEFAULT = "ldap";
+    @Property(
+            label = "LDAP Provider Name",
+            description = "Name of this LDAP provider configuration. This is used to reference this provider by the login modules.",
+            value = PARAM_NAME_DEFAULT
+    )
+    public static final String PARAM_NAME = "provider.name";
+
+    public static final String PARAM_LDAP_HOST_DEFAULT = "localhost";
+    @Property(
+            label = "LDAP Server Hostname",
+            description = "Hostname of the LDAP server",
+            value = PARAM_LDAP_HOST_DEFAULT
+    )
+    public static final String PARAM_LDAP_HOST = "host.name";
+
+    public static final int PARAM_LDAP_PORT_DEFAULT = 389;
+    @Property(
+            label = "LDAP Server Port",
+            description = "Port of the LDAP server",
+            intValue = PARAM_LDAP_PORT_DEFAULT
+    )
+    public static final String PARAM_LDAP_PORT = "host.port";
+
+    public static final boolean PARAM_USE_SSL_DEFAULT = false;
+    @Property(
+            label = "Use SSL",
+            description = "Indicates if an SSL connection should be used.",
+            boolValue = PARAM_USE_SSL_DEFAULT
+    )
+    public static final String PARAM_USE_SSL = "host.ssl";
+
+    public static final String PARAM_BIND_DN_DEFAULT = "";
+    @Property(
+            label = "Bind DN",
+            description = "DN of the user for authentication. Leave empty for anonymous bind.",
+            value = PARAM_BIND_DN_DEFAULT
+    )
+    public static final String PARAM_BIND_DN = "bind.dn";
+
+    public static final String PARAM_BIND_PASSWORD_DEFAULT = "";
+    @Property(
+            label = "Bind Password",
+            description = "Password of the user for authentication.",
+            passwordValue = PARAM_BIND_PASSWORD_DEFAULT
+    )
+    public static final String PARAM_BIND_PASSWORD = "bind.password";
+
+    public static final int PARAM_SEARCH_TIMEOUT_DEFAULT = 60000;
+    @Property(
+            label = "Search Timeout",
+            description = "Time in milliseconds until a search times out.",
+            intValue = PARAM_SEARCH_TIMEOUT_DEFAULT
+    )
+    public static final String PARAM_SEARCH_TIMEOUT = "search.timeout";
+
+    /**
+     * Defines the configuration of an identity.
+     */
+    public static class Identity {
+
+        private Dn baseDN;
+
+        private String[] objectClasses;
+
+        private String idAttribute;
+
+        private String extraFilter;
+
+        private String filterTemplate;
+
+        public Dn getBaseDN() {
+            return baseDN;
+        }
+
+        public void setBaseDN(String baseDN) throws LdapInvalidDnException {
+            this.baseDN = new Dn(baseDN);
+        }
+
+        public String[] getObjectClasses() {
+            return objectClasses;
+        }
+
+        public void setObjectClasses(String[] objectClasses) {
+            this.objectClasses = objectClasses;
+            filterTemplate = null;
+        }
+
+        public String getIdAttribute() {
+            return idAttribute;
+        }
+
+        public void setIdAttribute(String idAttribute) {
+            this.idAttribute = idAttribute;
+            filterTemplate = null;
+        }
+
+        public String getExtraFilter() {
+            return extraFilter;
+        }
+
+        public void setExtraFilter(String extraFilter) {
+            this.extraFilter = extraFilter;
+            filterTemplate = null;
+        }
+
+        public String getSearchFilter(String id) {
+            if (filterTemplate == null) {
+                StringBuilder filter = new StringBuilder("(&(")
+                        .append(idAttribute)
+                        .append("=%s)");
+                for (String objectClass: objectClasses) {
+                    filter.append("(objectclass=")
+                            .append(FilterEncoder.encodeFilterValue(objectClass))
+                            .append(')');
+                }
+                if (extraFilter != null && extraFilter.length() > 0) {
+                    filter.append(extraFilter);
+                }
+                filter.append(')');
+                filterTemplate = filter.toString();
+            }
+            return String.format(filterTemplate, FilterEncoder.encodeFilterValue(id));
+        }
+    }
+
+    public static LdapProviderConfig of(ConfigurationParameters params) {
+        LdapProviderConfig cfg = new LdapProviderConfig();
+        cfg.name = params.getConfigValue(PARAM_NAME, cfg.name);
+        cfg.host = params.getConfigValue(PARAM_LDAP_HOST, PARAM_LDAP_HOST_DEFAULT);
+        cfg.port = params.getConfigValue(PARAM_LDAP_PORT, PARAM_LDAP_PORT_DEFAULT);
+        cfg.useSSL = params.getConfigValue(PARAM_USE_SSL, PARAM_USE_SSL_DEFAULT);
+        cfg.bindDN = params.getConfigValue(PARAM_BIND_DN, PARAM_BIND_DN_DEFAULT);
+        cfg.bindPassword = params.getConfigValue(PARAM_BIND_PASSWORD, PARAM_BIND_PASSWORD_DEFAULT);
+        cfg.searchTimeout = params.getConfigValue(PARAM_SEARCH_TIMEOUT, PARAM_SEARCH_TIMEOUT_DEFAULT);
+        return cfg;
+    }
+
+
+    private String name = "ldap";
+    private String host = PARAM_LDAP_HOST_DEFAULT;
+    private int port = PARAM_LDAP_PORT_DEFAULT;
+    private boolean useSSL = PARAM_USE_SSL_DEFAULT;
+    private String bindDN = PARAM_BIND_DN_DEFAULT;
+    private String bindPassword = PARAM_BIND_PASSWORD_DEFAULT;
+    private int searchTimeout = PARAM_SEARCH_TIMEOUT_DEFAULT;
+
+    private final Identity userConfig = new Identity();
+    private final Identity groupConfig = new Identity();
+
+    private String groupMembershipAttribute = "uniquemember";
+
+    @Nonnull
+    public String getName() {
+        return name;
+    }
+
+    public void setName(@Nonnull String name) {
+        this.name = name;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
+
+    public boolean isUseSSL() {
+        return useSSL;
+    }
+
+    public void setUseSSL(boolean useSSL) {
+        this.useSSL = useSSL;
+    }
+
+    public String getBindDN() {
+        return bindDN;
+    }
+
+    public void setBindDN(String bindDN) {
+        this.bindDN = bindDN;
+    }
+
+    public String getBindPassword() {
+        return bindPassword;
+    }
+
+    public void setBindPassword(String bindPassword) {
+        this.bindPassword = bindPassword;
+    }
+
+    public int getSearchTimeout() {
+        return searchTimeout;
+    }
+
+    public void setSearchTimeout(int searchTimeout) {
+        this.searchTimeout = searchTimeout;
+    }
+
+    public String getGroupMembershipAttribute() {
+        return groupMembershipAttribute;
+    }
+
+    public void setGroupMembershipAttribute(String groupMembershipAttribute) {
+        this.groupMembershipAttribute = groupMembershipAttribute;
+    }
+
+    public Identity getUserConfig() {
+        return userConfig;
+    }
+
+    public Identity getGroupConfig() {
+        return groupConfig;
+    }
+}

Added: jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapSettings.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapSettings.java?rev=1566804&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapSettings.java (added)
+++ jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapSettings.java Mon Feb 10 22:57:48 2014
@@ -0,0 +1,191 @@
+/*
+ * 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.jackrabbit.oak.security.authentication.ldap.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public final class LdapSettings {
+
+    //TODO support autocreate.user.membership
+    //TODO support autocreate.path
+
+    public static final String KEY_HOST = "host";
+    public static final String KEY_PORT = "port";
+    public static final String KEY_SECURE = "secure";
+    public static final String KEY_AUTHDN = "authDn";
+    public static final String KEY_AUTHPW = "authPw";
+    public static final String KEY_SEARCHTIMEOUT = "searchTimeout";
+    public static final String KEY_USERROOT = "userRoot";
+    public static final String KEY_USERFILTER = "userFilter";
+    public static final String KEY_USERIDATTRIBUTE = "userIdAttribute";
+    public static final String KEY_GROUPROOT = "groupRoot";
+    public static final String KEY_GROUPFILTER = "groupFilter";
+    public static final String KEY_GROUPMEMBERSHIPATTRIBUTE = "groupMembershipAttribute";
+    public static final String KEY_GROUPNAMEATTRIBUTE = "groupNameAttribute";
+    public static final String KEY_AUTOCREATEPATH = "autocreate.path";
+    public static final String KEY_AUTOCREATEUSER = "autocreate.user.";
+    public static final String KEY_AUTOCREATEGROUP = "autocreate.group.";
+
+    //Connection settings
+    private String host;
+    private int port = 389;
+    private boolean secure = false;
+    private String authDn = "";
+    private String authPw = "";
+    private int searchTimeout = 60000;
+
+    //authentication settings
+    private String userRoot = "";
+    private String userFilter = "(objectclass=person)";
+    private String userIdAttribute = "uid";
+    private String groupRoot = "";
+    private String groupFilter = "(objectclass=groupOfUniqueNames)";
+    private String groupMembershipAttribute = "uniquemember";
+    private String groupNameAttribute = "cn";
+
+    //synchronization
+    private boolean splitPath = false;
+    private final Map<String, String> userAttributes = new HashMap<String, String>();
+    private final Map<String, String> groupAttributes = new HashMap<String, String>();
+
+    public LdapSettings(Map<String, ?> options) {
+        if (options.containsKey(KEY_HOST)) {
+            host = (String) options.get(KEY_HOST);
+        }
+        if (options.containsKey(KEY_PORT)) {
+            String s = (String) options.get(KEY_PORT);
+            if (s != null && s.length() > 0) {
+                port = Integer.parseInt(s);
+            }
+        }
+        if (options.containsKey(KEY_SECURE)) {
+            String s = (String) options.get(KEY_SECURE);
+            if (s != null && s.length() > 0) {
+                secure = Boolean.parseBoolean(s);
+            }
+        }
+        if (options.containsKey(KEY_AUTHDN)) {
+            authDn = (String) options.get(KEY_AUTHDN);
+        }
+        if (options.containsKey(KEY_AUTHPW)) {
+            authPw = (String) options.get(KEY_AUTHPW);
+        }
+        if (options.containsKey(KEY_SEARCHTIMEOUT)) {
+            String s = (String) options.get(KEY_SEARCHTIMEOUT);
+            if (s != null && s.length() > 0) {
+                searchTimeout = Integer.parseInt(s);
+            }
+        }
+        if (options.containsKey(KEY_USERROOT)) {
+            userRoot = (String) options.get(KEY_USERROOT);
+        }
+        if (options.containsKey(KEY_USERFILTER)) {
+            userFilter = (String) options.get(KEY_USERFILTER);
+        }
+        if (options.containsKey(KEY_USERIDATTRIBUTE)) {
+            userIdAttribute = (String) options.get(KEY_USERIDATTRIBUTE);
+        }
+        if (options.containsKey(KEY_GROUPROOT)) {
+            groupRoot = (String) options.get(KEY_GROUPROOT);
+        }
+        if (options.containsKey(KEY_GROUPFILTER)) {
+            groupFilter = (String) options.get(KEY_GROUPFILTER);
+        }
+        if (options.containsKey(KEY_GROUPMEMBERSHIPATTRIBUTE)) {
+            groupMembershipAttribute = (String) options.get(KEY_GROUPMEMBERSHIPATTRIBUTE);
+        }
+        if (options.containsKey(KEY_GROUPNAMEATTRIBUTE)) {
+            groupNameAttribute = (String) options.get(KEY_GROUPNAMEATTRIBUTE);
+        }
+        if (options.containsKey(KEY_AUTOCREATEPATH)) {
+            splitPath = "splitdn".equals(options.get(KEY_AUTOCREATEPATH));
+        }
+        for (String key : options.keySet()) {
+            if (key.startsWith(KEY_AUTOCREATEUSER)) {
+                userAttributes.put(key.substring(KEY_AUTOCREATEUSER.length()), (String) options.get(key));
+            }
+            if (key.startsWith(KEY_AUTOCREATEGROUP)) {
+                groupAttributes.put(key.substring(KEY_AUTOCREATEGROUP.length()), (String) options.get(key));
+            }
+        }
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public boolean isSecure() {
+        return secure;
+    }
+
+    public String getAuthDn() {
+        return authDn;
+    }
+
+    public String getAuthPw() {
+        return authPw;
+    }
+
+    public int getSearchTimeout() {
+        return searchTimeout;
+    }
+
+    public String getUserRoot() {
+        return userRoot;
+    }
+
+    public String getUserFilter() {
+        return userFilter;
+    }
+
+    public String getUserIdAttribute() {
+        return userIdAttribute;
+    }
+
+    public String getGroupRoot() {
+        return groupRoot;
+    }
+
+    public String getGroupFilter() {
+        return groupFilter;
+    }
+
+    public String getGroupMembershipAttribute() {
+        return groupMembershipAttribute;
+    }
+
+    public String getGroupNameAttribute() {
+        return groupNameAttribute;
+    }
+
+    public boolean isSplitPath() {
+        return splitPath;
+    }
+
+    public Map<String, String> getUserAttributes() {
+        return userAttributes;
+    }
+
+    public Map<String, String> getGroupAttributes() {
+        return groupAttributes;
+    }
+}

Added: jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapUser.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapUser.java?rev=1566804&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapUser.java (added)
+++ jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/impl/LdapUser.java Mon Feb 10 22:57:48 2014
@@ -0,0 +1,39 @@
+/*
+ * 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.jackrabbit.oak.security.authentication.ldap.impl;
+
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityRef;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalUser;
+
+public class LdapUser extends LdapIdentity implements ExternalUser {
+
+    private final String pwd;
+
+    public LdapUser(LdapIdentityProvider provider, ExternalIdentityRef ref, String id, String pwd) {
+        super(provider, ref, id);
+        this.pwd = pwd;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public String getPassword() {
+        return pwd;
+    }
+
+}

Added: jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/package-info.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/package-info.java?rev=1566804&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/package-info.java (added)
+++ jackrabbit/oak/trunk/oak-auth-ldap/src/main/java/org/apache/jackrabbit/oak/security/authentication/ldap/package-info.java Mon Feb 10 22:57:48 2014
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+@Version("0.17")
+@Export(optional = "provide:=true")
+package org.apache.jackrabbit.oak.security.authentication.ldap;
+
+import aQute.bnd.annotation.Version;
+import aQute.bnd.annotation.Export;
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/pom.xml?rev=1566804&r1=1566803&r2=1566804&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-core/pom.xml Mon Feb 10 22:57:48 2014
@@ -92,8 +92,7 @@
             <Jaas-ModuleClass>
               org.apache.jackrabbit.oak.spi.security.authentication.GuestLoginModule,
               org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl,
-              org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule,
-              org.apache.jackrabbit.oak.security.authentication.ldap.LdapLoginModule
+              org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule
             </Jaas-ModuleClass>
             <Bundle-Activator>
               org.apache.jackrabbit.oak.osgi.Activator
@@ -103,8 +102,7 @@
             </DynamicImport-Package>
             <Embed-Dependency>
               org.apache.sling.commons.osgi;inline=org/apache/sling/commons/osgi/PropertiesUtil.class,
-              json-simple;inline=true,
-              api-all
+              json-simple;inline=true
             </Embed-Dependency>
           </instructions>
         </configuration>
@@ -312,13 +310,6 @@
       <optional>true</optional>
     </dependency>
 
-      <dependency>
-          <groupId>org.apache.directory.api</groupId>
-          <artifactId>api-all</artifactId>
-          <version>1.0.0-M20</version>
-          <scope>provided</scope>
-      </dependency>
-
     <!-- Test Dependencies -->
     <dependency>
       <groupId>junit</groupId>

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java?rev=1566804&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java Mon Feb 10 22:57:48 2014
@@ -0,0 +1,230 @@
+/*
+ * 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.jackrabbit.oak.spi.security.authentication.external.impl;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import javax.jcr.Credentials;
+import javax.jcr.SimpleCredentials;
+import javax.security.auth.Subject;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.login.LoginException;
+
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+import org.apache.jackrabbit.oak.spi.security.authentication.AbstractLoginModule;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.DefaultSyncHandler;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityException;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityProvider;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityProviderManager;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalUser;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncException;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncHandler;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncMode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * ExternalLoginModule implements a LoginModule that uses and external identity provider for login.
+ */
+public class ExternalLoginModule extends AbstractLoginModule {
+
+    private static final Logger log = LoggerFactory.getLogger(ExternalLoginModule.class);
+
+    public static final SyncMode DEFAULT_SYNC_MODE = SyncMode.DEFAULT_SYNC;
+
+    private static final String PARAM_SYNC_HANDLER = "syncHandler";
+    private static final String DEFAULT_SYNC_HANDLER = DefaultSyncHandler.class.getName();
+
+    /**
+     * Name of the parameter that configures the name of the external identity provider.
+     */
+    public static final String PARAM_IDP_NAME = "idp.name";
+
+    /**
+     * Name of the parameter that configures the name of the synchronization handler.
+     */
+    public static final String PARAM_SYNC_HANDLER_NAME = "sync.handlerName";
+
+    /**
+     * Name of the parameter that configures the synchronization mode.
+     */
+    public static final String PARAM_SYNC_MODE = "sync.mode";
+
+    /**
+     * internal configuration when invoked from a factory rather than jaas
+     */
+    private ConfigurationParameters osgiConfig;
+
+    /**
+     * The external identity provider as specified by the {@link #PARAM_IDP_NAME}
+     */
+    private ExternalIdentityProvider idp;
+
+    /**
+     * The external user as resolved in the login call.
+     */
+    private ExternalUser externalUser;
+
+    /**
+     * Default constructor for the OSGIi LoginModuleFactory case and the default non-OSGi JAAS case.
+     */
+    public ExternalLoginModule() {
+    }
+
+    /**
+     * Creates a new ExternalLoginModule with the given OSGi config.
+     * @param osgiConfig the config
+     */
+    public ExternalLoginModule(ConfigurationParameters osgiConfig) {
+        this.osgiConfig = osgiConfig;
+    }
+
+    @Override
+    public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> ss, Map<String, ?> opts) {
+        super.initialize(subject, callbackHandler, ss, opts);
+
+        // merge options with osgi options if needed
+        if (osgiConfig != null) {
+            options = ConfigurationParameters.of(osgiConfig, options);
+        }
+
+        String idpName = options.getConfigValue(PARAM_IDP_NAME, "");
+        if (idpName.length() == 0) {
+            log.error("External login module needs IPD name. Will not be used for login.");
+        } else {
+            ExternalIdentityProviderManager idpMgr = getSecurityProvider().getConfiguration(ExternalIdentityProviderManager.class);
+            idp = idpMgr.getProvider(idpName);
+            if (idp == null) {
+                log.error("No IDP found with name {}. Will not be used for login.", idpName);
+            }
+        }
+    }
+
+    @Override
+    public boolean login() throws LoginException {
+        if (idp == null) {
+            return false;
+        }
+
+        Credentials credentials = getCredentials();
+        if (credentials == null) {
+            log.info("No credentials found for external login module. ignoring.");
+            return false;
+        }
+
+        try {
+            ExternalUser externalUser = idp.authenticate(credentials);
+            if (externalUser != null) {
+                log.debug("Adding Credentials to shared state.");
+                //noinspection unchecked
+                sharedState.put(SHARED_KEY_CREDENTIALS, credentials);
+
+                log.debug("Adding login name to shared state.");
+                //noinspection unchecked
+                sharedState.put(SHARED_KEY_LOGIN_NAME, externalUser.getId());
+
+                return true;
+            }
+        } catch (ExternalIdentityException e) {
+            log.error("Error while authenticating credentials {} with {}: {}", new Object[]{
+                    credentials, idp.getName(), e.toString()});
+            return false;
+        }
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return An immutable set containing only the {@link SimpleCredentials} class.
+     */
+    @Override
+    protected Set<Class> getSupportedCredentials() {
+        // todo: maybe delegate getSupportedCredentials to IDP
+        Class scClass = SimpleCredentials.class;
+        return Collections.singleton(scClass);
+    }
+
+    @Override
+    public boolean commit() throws LoginException {
+        if (externalUser == null) {
+            return false;
+        }
+
+        try {
+            SyncHandler handler = getSyncHandler();
+            Root root = getRoot();
+            UserManager userManager = getUserManager();
+            if (root == null || userManager == null) {
+                throw new LoginException("Cannot synchronize user.");
+            }
+            Object smValue = options.getConfigValue(PARAM_SYNC_MODE, null, null);
+            SyncMode syncMode;
+            if (smValue == null) {
+                syncMode = DEFAULT_SYNC_MODE;
+            } else {
+                syncMode = SyncMode.fromObject(smValue);
+            }
+            if (externalUser != null && handler.initialize(userManager, root, syncMode, options)) {
+                handler.sync(externalUser);
+                root.commit();
+                return true;
+            } else {
+                log.warn("Failed to initialize sync handler.");
+                return false;
+            }
+        } catch (SyncException e) {
+            throw new LoginException("User synchronization failed: " + e);
+        } catch (CommitFailedException e) {
+            throw new LoginException("User synchronization failed: " + e);
+        }
+    }
+
+    @Nonnull
+    protected SyncHandler getSyncHandler() throws SyncException {
+        Object syncHandler = options.getConfigValue(PARAM_SYNC_HANDLER, null, null);
+        if (syncHandler == null) {
+            return new DefaultSyncHandler();
+        } else if (syncHandler instanceof SyncHandler) {
+            return (SyncHandler) syncHandler;
+        } else {
+            try {
+                Object sh = Class.forName(syncHandler.toString()).newInstance();
+                if (sh instanceof SyncHandler) {
+                    return (SyncHandler) sh;
+                } else {
+                    throw new SyncException("Invalid SyncHandler configuration: " + sh);
+                }
+            } catch (Exception e) {
+                throw new SyncException("Error while getting SyncHandler:", e);
+            }
+        }
+    }
+
+    @Override
+    protected void clearState() {
+        super.clearState();
+        idp = null;
+        externalUser = null;
+    }
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.java?rev=1566804&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.java Mon Feb 10 22:57:48 2014
@@ -0,0 +1,114 @@
+/*
+ * 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.jackrabbit.oak.spi.security.authentication.external.impl;
+
+import java.util.Map;
+
+import javax.security.auth.spi.LoginModule;
+
+import org.apache.felix.jaas.LoginModuleFactory;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.ConfigurationPolicy;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+
+/**
+ * Implements a LoginModuleFactory that creates {@link ExternalLoginModule}s and allows to configure login modules
+ * via OSGi config.
+ */
+@Component(
+        label = "Apache Jackrabbit Oak External Login Module",
+        metatype = true,
+        policy = ConfigurationPolicy.REQUIRE,
+        configurationFactory = true
+)
+@Service
+public class ExternalLoginModuleFactory implements LoginModuleFactory {
+
+    @Property(
+            intValue = 900,
+            label = "JAAS Ranking",
+            description = "Specifying the ranking (i.e. sort order) of this login module entry. The entries are sorted " +
+                    "in a descending order (i.e. higher value ranked configurations come first)."
+    )
+    public static final String JAAS_RANKING = LoginModuleFactory.JAAS_RANKING;
+
+    @Property(
+            value = "SUFFICIENT",
+            label = "JAAS Control Flag",
+            description = "Property specifying whether or not a LoginModule is REQUIRED, REQUISITE, SUFFICIENT or " +
+                    "OPTIONAL.Refer to the JAAS configuration documentation for more details around the meaning of " +
+                    "these flags."
+    )
+    public static final String JAAS_CONTROL_FLAG = LoginModuleFactory.JAAS_CONTROL_FLAG;
+
+    @Property(
+            label = "JAAS Realm",
+            description = "The realm name (or application name) against which the LoginModule  is be registered. If no " +
+                    "realm name is provided then LoginModule is registered with a default realm as configured in " +
+                    "the Felix JAAS configuration."
+    )
+    public static final String JAAS_REALM_NAME = LoginModuleFactory.JAAS_REALM_NAME;
+
+    @Property(
+            label = "Identity Provider Name",
+            description = "Name of the identity provider (for example: 'ldap')."
+    )
+    public static final String PARAM_IDP_NAME = ExternalLoginModule.PARAM_IDP_NAME;
+
+    @Property(
+            value = "default",
+            label = "Sync Handler Name",
+            description = "Name of the sync handler."
+    )
+    public static final String PARAM_SYNC_HANDLER_NAME = ExternalLoginModule.PARAM_SYNC_HANDLER_NAME;
+
+    @Property(
+            value = "default",
+            label = "Sync Mode",
+            // TODO!!!
+            description = "a comma separated list of sync modes. allowed values: 'user','group','default','update'"
+    )
+    public static final String PARAM_SYNC_MODE = ExternalLoginModule.PARAM_SYNC_MODE;
+
+    /**
+     * default configuration for the login modules
+     */
+    private ConfigurationParameters osgiConfig;
+
+    /**
+     * Activates the LoginModuleFactory service
+     * @param properties the OSGi config
+     */
+    @Activate
+    protected void activate(Map<String, Object> properties) {
+        osgiConfig = ConfigurationParameters.of(properties);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @return a new {@link ExternalLoginModule} instance.
+     */
+    @Override
+    public LoginModule createLoginModule() {
+        return new ExternalLoginModule(osgiConfig);
+    }
+
+}
\ No newline at end of file

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapLoginTestBase.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapLoginTestBase.java?rev=1566804&r1=1566803&r2=1566804&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapLoginTestBase.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapLoginTestBase.java Mon Feb 10 22:57:48 2014
@@ -32,7 +32,7 @@ import org.apache.jackrabbit.oak.api.Aut
 import org.apache.jackrabbit.oak.api.ContentSession;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
-import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalLoginModule;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalLoginModule;
 import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncMode;
 import org.apache.jackrabbit.oak.spi.security.principal.PrincipalConfiguration;
 import org.apache.jackrabbit.oak.spi.security.principal.PrincipalProvider;

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTest.java?rev=1566804&r1=1566803&r2=1566804&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTest.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTest.java Mon Feb 10 22:57:48 2014
@@ -28,6 +28,7 @@ import org.apache.jackrabbit.api.securit
 import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.jackrabbit.oak.AbstractSecurityTest;
 import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalLoginModule;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;

Modified: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestLoginModule.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestLoginModule.java?rev=1566804&r1=1566803&r2=1566804&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestLoginModule.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestLoginModule.java Mon Feb 10 22:57:48 2014
@@ -26,6 +26,7 @@ import javax.jcr.Credentials;
 import javax.jcr.SimpleCredentials;
 import javax.security.auth.login.LoginException;
 
+import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalLoginModule;
 import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
 
 /**

Modified: jackrabbit/oak/trunk/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/pom.xml?rev=1566804&r1=1566803&r2=1566804&view=diff
==============================================================================
--- jackrabbit/oak/trunk/pom.xml (original)
+++ jackrabbit/oak/trunk/pom.xml Mon Feb 10 22:57:48 2014
@@ -49,6 +49,7 @@
     <module>oak-solr-core</module>
     <module>oak-solr-remote</module>
     <module>oak-solr-embedded</module>
+    <module>oak-auth-ldap</module>
     <module>oak-run</module>
     <module>oak-it</module>
     <!-- <module>oak-mk-perf</module> -->