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/11 01:28:51 UTC
svn commit: r1566895 [1/2] - in /jackrabbit/oak/trunk: ./ oak-auth-external/
oak-auth-external/src/ oak-auth-external/src/main/
oak-auth-external/src/main/java/ oak-auth-external/src/main/java/org/
oak-auth-external/src/main/java/org/apache/ oak-auth-e...
Author: tripod
Date: Tue Feb 11 00:28:49 2014
New Revision: 1566895
URL: http://svn.apache.org/r1566895
Log:
Moving external login module to own bundle
Added:
jackrabbit/oak/trunk/oak-auth-external/
jackrabbit/oak/trunk/oak-auth-external/README.md
jackrabbit/oak/trunk/oak-auth-external/pom.xml (with props)
jackrabbit/oak/trunk/oak-auth-external/src/
jackrabbit/oak/trunk/oak-auth-external/src/main/
jackrabbit/oak/trunk/oak-auth-external/src/main/java/
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalGroup.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentity.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityException.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityProvider.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityProviderManager.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityRef.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalUser.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncContext.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncException.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncHandler.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncManager.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfig.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalIDPManagerImpl.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncManagerImpl.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/package-info.java
jackrabbit/oak/trunk/oak-auth-external/src/test/
jackrabbit/oak/trunk/oak-auth-external/src/test/java/
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTest.java
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTestBase.java
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/TestIdentityProvider.java
jackrabbit/oak/trunk/oak-auth-external/src/test/resources/
jackrabbit/oak/trunk/oak-auth-external/src/test/resources/META-INF/
jackrabbit/oak/trunk/oak-auth-external/src/test/resources/META-INF/services/
jackrabbit/oak/trunk/oak-auth-external/src/test/resources/META-INF/services/org.apache.jackrabbit.mk.test.MicroKernelFixture
jackrabbit/oak/trunk/oak-auth-external/src/test/resources/logback-test.xml
jackrabbit/oak/trunk/oak-auth-external/src/test/resources/logging.properties
Removed:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/
Modified:
jackrabbit/oak/trunk/oak-auth-ldap/README.md
jackrabbit/oak/trunk/oak-auth-ldap/pom.xml
jackrabbit/oak/trunk/oak-core/pom.xml
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/SecurityProviderImpl.java
jackrabbit/oak/trunk/pom.xml
Added: jackrabbit/oak/trunk/oak-auth-external/README.md
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/README.md?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/README.md (added)
+++ jackrabbit/oak/trunk/oak-auth-external/README.md Tue Feb 11 00:28:49 2014
@@ -0,0 +1,25 @@
+Oak External Authentication Support
+===================================
+
+License
+-------
+
+(see the top-level [LICENSE.txt](../LICENSE.txt) for full license details)
+
+Collective work: Copyright 2012 The Apache Software Foundation.
+
+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.
+
Added: jackrabbit/oak/trunk/oak-auth-external/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/pom.xml?rev=1566895&view=auto
==============================================================================
Binary file - no diff available.
Propchange: jackrabbit/oak/trunk/oak-auth-external/pom.xml
------------------------------------------------------------------------------
svn:mime-type = application/xml
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalGroup.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalGroup.java?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalGroup.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalGroup.java Tue Feb 11 00:28:49 2014
@@ -0,0 +1,24 @@
+/*
+ * 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;
+
+/**
+ * ExternalGroup defines a group that is provided by an external system.
+ */
+public interface ExternalGroup extends ExternalIdentity {
+
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentity.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentity.java?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentity.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentity.java Tue Feb 11 00:28:49 2014
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+import java.security.Principal;
+import java.util.Map;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * {@code ExternalIdentity} defines an identity provided by an external system.
+ */
+public interface ExternalIdentity {
+
+ /**
+ * Returns the id of this identity as used in the external system.
+ * @return the external id.
+ */
+ @Nonnull
+ ExternalIdentityRef getExternalId();
+
+ /**
+ * Returns the local id of this identity as it would be used in this repository. This usually corresponds to
+ * {@link org.apache.jackrabbit.api.security.user.Authorizable#getID()}
+ *
+ * @return the internal id.
+ */
+ @Nonnull
+ String getId();
+
+ /**
+ * Returns the principal name of this identity. This usually corresponds to
+ * {@link org.apache.jackrabbit.api.security.user.Authorizable#getPrincipal()}.{@link java.security.Principal#getName()}
+ * @return the principal name
+ */
+ @Nonnull
+ String getPrincipalName();
+
+ /**
+ * Returns the desired intermediate relative path of the authorizable to be created. For example, one could map
+ * an external hierarchy into the local users and groups hierarchy.
+ *
+ * @return the intermediate path or {@code null} or empty.
+ */
+ @CheckForNull
+ String getIntermediatePath();
+
+ /**
+ * Returns an iterable of the declared groups of this external identity.
+ * @return the declared groups
+ */
+ @Nonnull
+ Iterable<? extends ExternalIdentityRef> getGroups();
+
+ /**
+ * Returns a map of properties of this external identity.
+ * @return the properties
+ */
+ @Nonnull
+ Map<String, ?> getProperties();
+
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityException.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityException.java?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityException.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityException.java Tue Feb 11 00:28:49 2014
@@ -0,0 +1,38 @@
+/*
+ * 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;
+
+/**
+ * {@code ExternalIdentityException} is used to notify about errors when dealing with external identities.
+ */
+public class ExternalIdentityException extends Exception {
+
+ public ExternalIdentityException() {
+ }
+
+ public ExternalIdentityException(String message) {
+ super(message);
+ }
+
+ public ExternalIdentityException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ExternalIdentityException(Throwable cause) {
+ super(cause);
+ }
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityProvider.java?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityProvider.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityProvider.java Tue Feb 11 00:28:49 2014
@@ -0,0 +1,81 @@
+/*
+ * 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;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.jcr.Credentials;
+import javax.security.auth.login.LoginException;
+
+/**
+ * {@code ExternalIdentityProvider} defines an interface to an external system that provides users and groups that
+ * can be synced with local ones.
+ */
+public interface ExternalIdentityProvider {
+
+ /**
+ * Returns the name of this provider.
+ * @return the provider name.
+ */
+ @Nonnull
+ String getName();
+
+ /**
+ * Returns the identity for the given reference or {@code null} if it does not exist. The provider should check if
+ * the {@link ExternalIdentityRef#getProviderName() provider name} matches his own name or is {@code null} and
+ * should not return a foreign identity.
+ *
+ * @param ref the reference
+ * @return an identity or {@code null}
+ *
+ * @throws ExternalIdentityException if an error occurs.
+ */
+ @CheckForNull
+ ExternalIdentity getIdentity(@Nonnull ExternalIdentityRef ref) throws ExternalIdentityException;
+
+ /**
+ * Returns the user for the given (local) id. if the user does not exist {@code null} is returned.
+ * @param userId the user id.
+ * @return the user or {@code null}
+ *
+ * @throws ExternalIdentityException if an error occurs.
+ */
+ @CheckForNull
+ ExternalUser getUser(@Nonnull String userId) throws ExternalIdentityException;
+
+ /**
+ * Authenticates the user represented by the given credentials and returns it. If the user does not exist in this
+ * provider, {@code null} is returned. If the authentication fails, a LoginException is thrown.
+ *
+ * @param credentials the credentials
+ * @return the user or {@code null}
+ * @throws ExternalIdentityException if an error occurs
+ * @throws javax.security.auth.login.LoginException if the user could not be authenticated
+ */
+ @CheckForNull
+ ExternalUser authenticate(@Nonnull Credentials credentials) throws ExternalIdentityException, LoginException;
+
+ /**
+ * Returns the group for the given (local) group name. if the group does not exist {@code null} is returned.
+ * @param name the group name
+ * @return the group or {@code null}
+ *
+ * @throws ExternalIdentityException if an error occurs.
+ */
+ @CheckForNull
+ ExternalGroup getGroup(@Nonnull String name) throws ExternalIdentityException;
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityProviderManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityProviderManager.java?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityProviderManager.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityProviderManager.java Tue Feb 11 00:28:49 2014
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * The external identity provider management.
+ *
+ * The default manager is registered as OSGi service and can also be retrieved via
+ * {@link org.apache.jackrabbit.oak.spi.security.SecurityProvider#getConfiguration(Class)}
+ */
+public interface ExternalIdentityProviderManager {
+
+ /**
+ * Returns the registered identity provider with the given name.
+ * @param name the provider name
+ * @return the registered provider or {@code null}
+ */
+ @CheckForNull
+ ExternalIdentityProvider getProvider(@Nonnull String name);
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityRef.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityRef.java?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityRef.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityRef.java Tue Feb 11 00:28:49 2014
@@ -0,0 +1,121 @@
+/*
+ * 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;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.util.Text;
+
+/**
+ * {@code ExternalIdentityRef} defines a reference to an external identity.
+ */
+public class ExternalIdentityRef {
+
+ private final String id;
+
+ private final String providerName;
+
+ private final String string;
+
+ /**
+ * Creates a new external identity ref with the given id and provider name
+ * @param id the id of the identity.
+ * @param providerName the name of the identity provider
+ */
+ public ExternalIdentityRef(@Nonnull String id, @CheckForNull String providerName) {
+ this.id = id;
+ this.providerName = providerName;
+
+ StringBuilder b = new StringBuilder();
+ b.append(Text.escape(id));
+ if (providerName != null && providerName.length() > 0) {
+ b.append('@').append(Text.escape(providerName));
+ }
+ string = b.toString();
+ }
+
+ /**
+ * Returns the name of the identity provider.
+ * @return the name of the identity provider.
+ */
+ @CheckForNull
+ public String getProviderName() {
+ return providerName;
+ }
+
+ /**
+ * Returns the id of the external identity. for example the DN of an LDAP user.
+ * @return the id
+ */
+ @Nonnull
+ public String getId() {
+ return id;
+ }
+
+ /**
+ * Returns a string representation of this external identity reference
+ * @return a string representation.
+ */
+ @Nonnull
+ public String getString() {
+ return string;
+ }
+
+ /**
+ * Creates an external identity reference from a string representation.
+ * @param str the string
+ * @return the reference
+ */
+ public static ExternalIdentityRef fromString(@Nonnull String str) {
+ int idx = str.indexOf('@');
+ if (idx < 0) {
+ return new ExternalIdentityRef(Text.unescape(str), null);
+ } else {
+ return new ExternalIdentityRef(
+ Text.unescape(str.substring(0, idx)),
+ Text.unescape(str.substring(idx+1))
+ );
+ }
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder("ExternalIdentityRef{");
+ sb.append("id='").append(id).append('\'');
+ sb.append(", providerName='").append(providerName).append('\'');
+ sb.append('}');
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ ExternalIdentityRef that = (ExternalIdentityRef) o;
+
+ if (!string.equals(that.string)) return false;
+
+ return true;
+ }
+
+ @Override
+ public int hashCode() {
+ return string.hashCode();
+ }
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalUser.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalUser.java?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalUser.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalUser.java Tue Feb 11 00:28:49 2014
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+import javax.annotation.CheckForNull;
+
+/**
+ * ExternalUser defines a user provided by an external system.
+ */
+public interface ExternalUser extends ExternalIdentity {
+
+ /**
+ * Returns the plaintext password of this user if available. This is usually only the case when the
+ * external user is accessible during a login call.
+ *
+ * @return the password.
+ */
+ @CheckForNull
+ String getPassword();
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncContext.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncContext.java?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncContext.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncContext.java Tue Feb 11 00:28:49 2014
@@ -0,0 +1,42 @@
+/*
+ * 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;
+
+import javax.annotation.Nonnull;
+
+/**
+ * {@code SyncContext} is used as scope for sync operations. Implementations are free to associate any resources with
+ * the sync context. The sync context must not be accessed concurrently and must be closed after use.
+ */
+public interface SyncContext {
+
+ /**
+ * Synchronizes an external identity with the repository based on the respective configuration.
+ *
+ * @param identity the identity to sync.
+ * @return {@code true} if the given identity was synced; {@code false} if for no change.
+ * @throws SyncException if an error occurrs
+ */
+ boolean sync(@Nonnull ExternalIdentity identity) throws SyncException;
+
+ /**
+ * Closes this context and releases any resources bound to it. Note that an implementation must not commit the
+ * {@link org.apache.jackrabbit.oak.api.Root} passed during the creation call. This is the responsibility of the
+ * application.
+ */
+ void close();
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncException.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncException.java?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncException.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncException.java Tue Feb 11 00:28:49 2014
@@ -0,0 +1,35 @@
+/*
+ * 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;
+
+/**
+ * SyncException... TODO
+ */
+public class SyncException extends Exception {
+
+ public SyncException(String s) {
+ super(s);
+ }
+
+ public SyncException(Throwable throwable) {
+ super(throwable);
+ }
+
+ public SyncException(String s, Throwable throwable) {
+ super(s, throwable);
+ }
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncHandler.java?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncHandler.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncHandler.java Tue Feb 11 00:28:49 2014
@@ -0,0 +1,58 @@
+/*
+ * 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;
+
+import javax.annotation.Nonnull;
+
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.oak.api.Root;
+
+/**
+ * SyncHandler is used to sync users and groups from an {@link ExternalIdentityProvider}.
+ * The synchronization performed within the scope of a {@link SyncContext} which is acquired during the
+ * {@link #createContext(ExternalIdentityProvider, org.apache.jackrabbit.api.security.user.UserManager, org.apache.jackrabbit.oak.api.Root)} call.
+ *
+ * The exact configuration is managed by the sync handler instance. The system may contain several sync handler
+ * implementations with different configurations. those are managed by the {@link SyncManager}.
+ *
+ * @see org.apache.jackrabbit.oak.spi.security.authentication.external.SyncContext
+ * @see org.apache.jackrabbit.oak.spi.security.authentication.external.SyncManager
+ */
+public interface SyncHandler {
+
+ /**
+ * Returns the name of this sync handler.
+ * @return sync handler name
+ */
+ @Nonnull
+ String getName();
+
+ /**
+ * Initializes a sync context which is used to start the sync operations.
+ *
+ * @param idp the external identity provider used for syncing
+ * @param userManager user manager for managing authorizables
+ * @param root root of the current tree
+ * @return the sync context
+ * @throws SyncException if an error occurs
+ */
+ @Nonnull
+ SyncContext createContext(@Nonnull ExternalIdentityProvider idp,
+ @Nonnull UserManager userManager,
+ @Nonnull Root root) throws SyncException;
+
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncManager.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncManager.java?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncManager.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncManager.java Tue Feb 11 00:28:49 2014
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * The external identity synchronization management.
+ *
+ * The default manager is registered as OSGi service and can also be retrieved via
+ * {@link org.apache.jackrabbit.oak.spi.security.SecurityProvider#getConfiguration(Class)}
+ */
+public interface SyncManager {
+
+ /**
+ * Returns the sync handler with the given name.
+ * @param name the name of the sync handler or {@code null}
+ * @return the sync handler
+ */
+ @CheckForNull
+ SyncHandler getSyncHandler(@Nonnull String name);
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfig.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfig.java?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfig.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfig.java Tue Feb 11 00:28:49 2014
@@ -0,0 +1,485 @@
+/*
+ * 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.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+
+/**
+ * {@code DefaultSyncConfig} defines how users and groups from an external source are synced into the repository using
+ * the {@link DefaultSyncHandler}.
+ */
+@Component(
+ label = "Apache Jackrabbit Oak Default Sync Handler",
+ name = "org.apache.jackrabbit.oak.spi.security.authentication.external.impl.DefaultSyncHandler",
+ configurationFactory = true,
+ metatype = true,
+ ds = false
+)
+public class DefaultSyncConfig {
+
+ /**
+ * @see #getName()
+ */
+ public static final String PARAM_NAME_DEFAULT = "default";
+
+ /**
+ * @see #getName()
+ */
+ @Property(
+ label = "Sync Handler Name",
+ description = "Name of this sync configuration. This is used to reference this handler by the login modules.",
+ value = PARAM_NAME_DEFAULT
+ )
+ public static final String PARAM_NAME = "handler.name";
+
+ /**
+ * @see DefaultSyncConfig.User#getExpirationTime()
+ */
+ public static final long PARAM_USER_EXPIRATION_TIME_DEFAULT = 3600*1000;
+
+ /**
+ * @see DefaultSyncConfig.User#getExpirationTime()
+ */
+ @Property(
+ label = "User Expiration Time",
+ description = "Duration in milliseconds until a synced user gets expired.",
+ longValue = PARAM_USER_EXPIRATION_TIME_DEFAULT
+ )
+ public static final String PARAM_USER_EXPIRATION_TIME = "user.expirationTime";
+
+ /**
+ * @see DefaultSyncConfig.User#getAutoMembership()
+ */
+ public static final String[] PARAM_USER_AUTO_MEMBERSHIP_DEFAULT = {};
+
+ /**
+ * @see DefaultSyncConfig.User#getAutoMembership()
+ */
+ @Property(
+ label = "User auto membership",
+ description = "List of groups that a synced user is added to automatically",
+ value = {},
+ cardinality = Integer.MAX_VALUE
+ )
+ public static final String PARAM_USER_AUTO_MEMBERSHIP = "user.autoMembership";
+
+ /**
+ * @see DefaultSyncConfig.User#getPropertyMapping()
+ */
+ public static final String[] PARAM_USER_PROPERTY_MAPPING_DEFAULT = {"rep:fullname=cn"};
+
+ /**
+ * @see DefaultSyncConfig.User#getPropertyMapping()
+ */
+ @Property(
+ label = "User property mapping",
+ description = "List mapping definition of local properties from external ones. eg: 'profile/email=mail'." +
+ "Use double quotes for fixed values. eg: 'profile/nt:primaryType=\"nt:unstructured\"",
+ value = {"rep:fullname=cn"},
+ cardinality = Integer.MAX_VALUE
+ )
+ public static final String PARAM_USER_PROPERTY_MAPPING = "user.propertyMapping";
+
+ /**
+ * @see DefaultSyncConfig.User#getPathPrefix()
+ */
+ public static final String PARAM_USER_PATH_PREFIX_DEFAULT = "";
+
+ /**
+ * @see DefaultSyncConfig.User#getPathPrefix()
+ */
+ @Property(
+ label = "User Path Prefix",
+ description = "The path prefix used when creating new users.",
+ value = PARAM_USER_PATH_PREFIX_DEFAULT
+ )
+ public static final String PARAM_USER_PATH_PREFIX = "user.pathPrefix";
+
+ /**
+ * @see DefaultSyncConfig.User#getMembershipExpirationTime()
+ */
+ public static final long PARAM_USER_MEMBERSHIP_EXPIRATION_TIME_DEFAULT = 3600*1000;
+
+ /**
+ * @see DefaultSyncConfig.User#getMembershipExpirationTime()
+ */
+ @Property(
+ label = "User Membership Expiration",
+ description = "Time in milliseconds after which membership expires.",
+ longValue = PARAM_USER_MEMBERSHIP_EXPIRATION_TIME_DEFAULT
+ )
+ public static final String PARAM_USER_MEMBERSHIP_EXPIRATION_TIME = "user.membershipExpTime";
+
+ /**
+ * @see User#getMembershipNestingDepth()
+ */
+ public static final int PARAM_USER_MEMBERSHIP_NESTING_DEPTH_DEFAULT = 0;
+
+ /**
+ * @see User#getMembershipNestingDepth()
+ */
+ @Property(
+ label = "User membership nesting depth",
+ description = "Returns the maximum depth of group nesting when membership relations are synced. " +
+ "A value of 0 effectively disables group membership lookup. A value of 1 only adds the direct " +
+ "groups of a user. This value has no effect when syncing individual groups only when syncing a " +
+ "users membership ancestry.",
+ intValue = PARAM_USER_MEMBERSHIP_NESTING_DEPTH_DEFAULT
+ )
+ public static final String PARAM_USER_MEMBERSHIP_NESTING_DEPTH = "user.membershipNestingDepth";
+
+ /**
+ * @see DefaultSyncConfig.Group#getExpirationTime()
+ */
+ public static final long PARAM_GROUP_EXPIRATION_TIME_DEFAULT = 24*3600*1000;
+
+ /**
+ * @see DefaultSyncConfig.Group#getExpirationTime()
+ */
+ @Property(
+ label = "Group Expiration Time",
+ description = "Duration in milliseconds until a synced group expires.",
+ longValue = PARAM_GROUP_EXPIRATION_TIME_DEFAULT
+ )
+ public static final String PARAM_GROUP_EXPIRATION_TIME = "group.expirationTime";
+
+ /**
+ * @see DefaultSyncConfig.Group#getAutoMembership()
+ */
+ public static final String[] PARAM_GROUP_AUTO_MEMBERSHIP_DEFAULT = {};
+
+ /**
+ * @see DefaultSyncConfig.Group#getAutoMembership()
+ */
+ @Property(
+ label = "Group auto membership",
+ description = "List of groups that a synced group is added to automatically",
+ value = {},
+ cardinality = Integer.MAX_VALUE
+ )
+ public static final String PARAM_GROUP_AUTO_MEMBERSHIP = "group.autoMembership";
+
+ /**
+ * @see DefaultSyncConfig.Group#getPropertyMapping()
+ */
+ public static final String[] PARAM_GROUP_PROPERTY_MAPPING_DEFAULT = {};
+
+ /**
+ * @see DefaultSyncConfig.Group#getPropertyMapping()
+ */
+ @Property(
+ label = "Group property mapping",
+ description = "List mapping definition of local properties from external ones.",
+ value = {},
+ cardinality = Integer.MAX_VALUE
+ )
+ public static final String PARAM_GROUP_PROPERTY_MAPPING = "group.propertyMapping";
+
+ /**
+ * @see DefaultSyncConfig.Group#getPathPrefix()
+ */
+ public static final String PARAM_GROUP_PATH_PREFIX_DEFAULT = "";
+
+ /**
+ * @see DefaultSyncConfig.Group#getPathPrefix()
+ */
+ @Property(
+ label = "Group Path Prefix",
+ description = "The path prefix used when creating new groups.",
+ value = PARAM_GROUP_PATH_PREFIX_DEFAULT
+ )
+ public static final String PARAM_GROUP_PATH_PREFIX = "group.pathPrefix";
+
+ /**
+ * Base config class for users and groups
+ */
+ public abstract static class Authorizable {
+
+ private long expirationTime;
+
+ private Set<String> autoMembership;
+
+ private Map<String, String> propertyMapping;
+
+ private String pathPrefix;
+
+ /**
+ * Returns the duration in milliseconds until a synced authorizable gets expired. An expired authorizable will
+ * be re-synced.
+ * @return the expiration time in milliseconds.
+ */
+ public long getExpirationTime() {
+ return expirationTime;
+ }
+
+ /**
+ * Sets the expiration time.
+ * @param expirationTime time in milliseconds.
+ * @return {@code this}
+ * @see #getExpirationTime()
+ */
+ @Nonnull
+ public Authorizable setExpirationTime(long expirationTime) {
+ this.expirationTime = expirationTime;
+ return this;
+ }
+
+ /**
+ * Defines the set of group names that are automatically added to synced authorizable.
+ * @return set of group names.
+ */
+ @Nonnull
+ public Set<String> getAutoMembership() {
+ return autoMembership;
+ }
+
+ /**
+ * Sets the auto membership
+ * @param autoMembership the membership
+ * @return {@code this}
+ * @see #getAutoMembership()
+ */
+ @Nonnull
+ public Authorizable setAutoMembership(String ... autoMembership) {
+ this.autoMembership = new HashSet<String>(Arrays.asList(autoMembership));
+ return this;
+ }
+
+ /**
+ * Defines the mapping of internal property names from external values. Only the external properties defined as
+ * keys of this map are synced with the mapped internal properties. note that the property names can be relative
+ * paths. the intermediate nodes will be created accordingly.
+ *
+ * Example:
+ * <xmp>
+ * {
+ * "rep:fullname": "cn",
+ * "country", "c",
+ * "profile/email": "mail",
+ * "profile/givenName": "cn"
+ * }
+ * </xmp>
+ *
+ * The implicit properties like userid, groupname, password must not be mapped.
+ *
+ * @return the property mapping where the keys are the local property names and the values the external ones.
+ */
+ @Nonnull
+ public Map<String, String> getPropertyMapping() {
+ return propertyMapping;
+ }
+
+ /**
+ * Sets the property mapping.
+ * @param propertyMapping the mapping
+ * @return {@code this}
+ * @see #getPropertyMapping()
+ */
+ @Nonnull
+ public Authorizable setPropertyMapping(Map<String, String> propertyMapping) {
+ this.propertyMapping = propertyMapping;
+ return this;
+ }
+
+ /**
+ * Defines the authorizables intermediate path prefix that is used when creating new authorizables. This prefix
+ * is always prepended to the path provided by the {@link org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentity}.
+ * @return the intermediate path prefix.
+ */
+ @Nonnull
+ public String getPathPrefix() {
+ return pathPrefix;
+ }
+
+ /**
+ * Sets the path prefix.
+ * @param pathPrefix the path prefix.
+ * @return {@code this}
+ * @see #getPathPrefix()
+ */
+ @Nonnull
+ public Authorizable setPathPrefix(String pathPrefix) {
+ this.pathPrefix = pathPrefix == null ? "" : pathPrefix;
+ return this;
+ }
+ }
+
+ /**
+ * User specific config.
+ */
+ public static class User extends Authorizable {
+
+ private long membershipExpirationTime;
+
+ private long membershipNestingDepth;
+
+ /**
+ * Returns the duration in milliseconds until the group membership of a user is expired. If the
+ * membership information is expired it is re-synced according to the maximum nesting depth.
+ * Note that the membership is the groups an authorizable is member of, not the list of members of a group.
+ * Also note, that the group membership expiration time can be higher than the user expiration time itself and
+ * that value has no effect when syncing individual groups only when syncing a users membership ancestry.
+ *
+ * @return the expiration time in milliseconds.
+ */
+ public long getMembershipExpirationTime() {
+ return membershipExpirationTime;
+ }
+
+ /**
+ * Sets the membership expiration time
+ * @param membershipExpirationTime the time in milliseconds.
+ * @return {@code this}
+ * @see #getMembershipExpirationTime()
+ */
+ @Nonnull
+ public User setMembershipExpirationTime(long membershipExpirationTime) {
+ this.membershipExpirationTime = membershipExpirationTime;
+ return this;
+ }
+
+ /**
+ * Returns the maximum depth of group nesting when membership relations are synced. A value of 0 effectively
+ * disables group membership lookup. A value of 1 only adds the direct groups of a user. This value has no effect
+ * when syncing individual groups only when syncing a users membership ancestry.
+ * @return the group nesting depth
+ */
+ public long getMembershipNestingDepth() {
+ return membershipNestingDepth;
+ }
+
+ /**
+ * Sets the group nesting depth.
+ * @param membershipNestingDepth the depth.
+ * @return {@code this}
+ * @see #getMembershipNestingDepth()
+ */
+ @Nonnull
+ public User setMembershipNestingDepth(long membershipNestingDepth) {
+ this.membershipNestingDepth = membershipNestingDepth;
+ return this;
+ }
+
+ }
+
+ /**
+ * Group specific config
+ */
+ public static class Group extends Authorizable {
+
+ }
+
+ /**
+ * Creates a new LDAP provider configuration based on the properties store in the given parameters.
+ * @param params the configuration parameters.
+ * @return the config
+ */
+ public static DefaultSyncConfig of(ConfigurationParameters params) {
+ DefaultSyncConfig cfg = new DefaultSyncConfig()
+ .setName(params.getConfigValue(PARAM_NAME, PARAM_NAME_DEFAULT));
+
+ cfg.user()
+ .setMembershipExpirationTime(params.getConfigValue(PARAM_USER_MEMBERSHIP_EXPIRATION_TIME, PARAM_USER_MEMBERSHIP_EXPIRATION_TIME_DEFAULT))
+ .setMembershipNestingDepth(params.getConfigValue(PARAM_USER_MEMBERSHIP_NESTING_DEPTH, PARAM_USER_MEMBERSHIP_NESTING_DEPTH_DEFAULT))
+ .setExpirationTime(params.getConfigValue(PARAM_USER_EXPIRATION_TIME, PARAM_USER_EXPIRATION_TIME_DEFAULT))
+ .setPathPrefix(params.getConfigValue(PARAM_USER_PATH_PREFIX, PARAM_USER_PATH_PREFIX_DEFAULT))
+ .setAutoMembership(params.getConfigValue(PARAM_USER_AUTO_MEMBERSHIP, PARAM_USER_AUTO_MEMBERSHIP_DEFAULT))
+ .setPropertyMapping(createMapping(
+ params.getConfigValue(PARAM_USER_PROPERTY_MAPPING, PARAM_USER_PROPERTY_MAPPING_DEFAULT)));
+
+ cfg.group()
+ .setExpirationTime(params.getConfigValue(PARAM_GROUP_EXPIRATION_TIME, PARAM_GROUP_EXPIRATION_TIME_DEFAULT))
+ .setPathPrefix(params.getConfigValue(PARAM_GROUP_PATH_PREFIX, PARAM_GROUP_PATH_PREFIX_DEFAULT))
+ .setAutoMembership(params.getConfigValue(PARAM_GROUP_AUTO_MEMBERSHIP, PARAM_GROUP_AUTO_MEMBERSHIP_DEFAULT))
+ .setPropertyMapping(createMapping(
+ params.getConfigValue(PARAM_GROUP_PROPERTY_MAPPING, PARAM_GROUP_PROPERTY_MAPPING_DEFAULT)));
+
+ return cfg;
+ }
+
+ /**
+ * Creates a new property mapping map from a list of patterns.
+ * @param patterns the patterns
+ * @return the mapping map
+ */
+ private static Map<String, String> createMapping(String[] patterns) {
+ Map<String, String> mapping = new HashMap<String, String>();
+ for (String pattern: patterns) {
+ int idx = pattern.indexOf('=');
+ if (idx > 0) {
+ String relPath = pattern.substring(0, idx).trim();
+ String value = pattern.substring(idx+1).trim();
+ mapping.put(relPath, value);
+ }
+ }
+ return mapping;
+ }
+
+ private String name = PARAM_NAME_DEFAULT;
+
+ private final User user = new User();
+
+ private final Group group = new Group();
+
+ /**
+ * Configures the name of this configuration
+ * @return the name
+ */
+ @Nonnull
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Sets the name
+ * @param name the name
+ * @return {@code this}
+ * @see #getName()
+ */
+ public DefaultSyncConfig setName(@Nonnull String name) {
+ this.name = name;
+ return this;
+ }
+
+ /**
+ * Returns the sync configuration for users.
+ * @return the user sync configuration.
+ */
+ public User user() {
+ return user;
+ }
+
+ /**
+ * Returns the sync configuration for groups.
+ * @return the group sync configuration.
+ */
+ public Group group() {
+ return group;
+ }
+
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.java?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.java Tue Feb 11 00:28:49 2014
@@ -0,0 +1,310 @@
+/*
+ * 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.security.Principal;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.ValueFormatException;
+
+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.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl;
+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.apache.jackrabbit.oak.spi.security.authentication.external.SyncContext;
+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.principal.PrincipalImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@code DefaultSyncHandler} implements an sync handler that synchronizes users and groups from an external identity
+ * provider with the repository users.
+ * <p/>
+ * Please refer to {@link DefaultSyncConfig} for configuration options.
+ */
+@Component(
+ // note that the metatype information is generated from DefaultSyncConfig
+ policy = ConfigurationPolicy.REQUIRE
+)
+@Service
+public class DefaultSyncHandler implements SyncHandler {
+
+ /**
+ * logger instance
+ */
+ private static final Logger log = LoggerFactory.getLogger(DefaultSyncHandler.class);
+
+ /**
+ * internal configuration
+ */
+ private DefaultSyncConfig config;
+
+ /**
+ * Default constructor for OSGi
+ */
+ public DefaultSyncHandler() {
+ }
+
+ /**
+ * Constructor for non-OSGi cases.
+ *
+ * @param config the configuration
+ */
+ public DefaultSyncHandler(DefaultSyncConfig config) {
+ this.config = config;
+ }
+
+ @Activate
+ private void activate(Map<String, Object> properties) {
+ ConfigurationParameters cfg = ConfigurationParameters.of(properties);
+ config = DefaultSyncConfig.of(cfg);
+ }
+
+ @Nonnull
+ @Override
+ public String getName() {
+ return config.getName();
+ }
+
+ @Nonnull
+ @Override
+ public SyncContext createContext(@Nonnull ExternalIdentityProvider idp, @Nonnull UserManager userManager, @Nonnull Root root) throws SyncException {
+ return new ContextImpl(idp, userManager, root);
+ }
+
+ private class ContextImpl implements SyncContext {
+
+ private final ExternalIdentityProvider idp;
+
+ private final UserManager userManager;
+
+ private final Root root;
+
+ private final ValueFactory valueFactory;
+
+ private ContextImpl(ExternalIdentityProvider idp, UserManager userManager, Root root) {
+ this.idp = idp;
+ this.userManager = userManager;
+ this.root = root;
+ valueFactory = new ValueFactoryImpl(root, NamePathMapper.DEFAULT);
+ }
+
+ @Override
+ public void close() {
+ // nothing to do
+ }
+
+ @Override
+ public boolean sync(@Nonnull ExternalIdentity identity) throws SyncException {
+ try {
+ if (identity instanceof ExternalUser) {
+ User user = getUser(identity);
+ if (user == null) {
+ createUser((ExternalUser) identity);
+ } else {
+ updateUser((ExternalUser) identity, user);
+ }
+ return true;
+ } else if (identity instanceof ExternalGroup) {
+ // todo
+ return false;
+
+ } else {
+ throw new IllegalArgumentException("identity must be user or group but was: " + identity);
+ }
+ } catch (RepositoryException e) {
+ throw new SyncException(e);
+ } catch (ExternalIdentityException e) {
+ throw new SyncException(e);
+ }
+ }
+
+ @CheckForNull
+ private User getUser(@Nonnull ExternalIdentity externalUser) throws RepositoryException {
+ Authorizable authorizable = userManager.getAuthorizable(externalUser.getId());
+ if (authorizable == null) {
+ authorizable = userManager.getAuthorizable(externalUser.getPrincipalName());
+ }
+ if (authorizable == null) {
+ return null;
+ } else if (authorizable instanceof User) {
+ return (User) authorizable;
+ } else {
+ // TODO: deal with colliding authorizable that is group.
+ log.warn("unexpected authorizable: {}", authorizable);
+ return null;
+ }
+ }
+
+ @CheckForNull
+ private User createUser(ExternalUser externalUser)
+ throws RepositoryException, SyncException, ExternalIdentityException {
+ String password = externalUser.getPassword(); // todo: make configurable
+ Principal principal = new PrincipalImpl(externalUser.getPrincipalName());
+ User user = userManager.createUser(
+ externalUser.getId(),
+ password,
+ principal,
+ concatPaths(config.user().getPathPrefix(), externalUser.getIntermediatePath())
+ );
+ syncAuthorizable(externalUser, user);
+ return user;
+ }
+
+ @CheckForNull
+ private Group createGroup(ExternalGroup externalGroup)
+ throws RepositoryException, SyncException, ExternalIdentityException {
+ Principal principal = new PrincipalImpl(externalGroup.getPrincipalName());
+ Group group = userManager.createGroup(
+ externalGroup.getId(),
+ principal,
+ concatPaths(config.user().getPathPrefix(), externalGroup.getIntermediatePath()));
+ syncAuthorizable(externalGroup, group);
+ return group;
+ }
+
+ private void updateUser(ExternalUser externalUser, User user)
+ throws RepositoryException, SyncException, ExternalIdentityException {
+ syncAuthorizable(externalUser, user);
+ }
+
+ private void syncAuthorizable(ExternalIdentity externalUser, Authorizable authorizable)
+ throws RepositoryException, SyncException, ExternalIdentityException {
+ for (ExternalIdentityRef externalGroupRef : externalUser.getGroups()) {
+ ExternalIdentity id = idp.getIdentity(externalGroupRef);
+ if (id instanceof ExternalGroup) {
+ ExternalGroup externalGroup = (ExternalGroup) id;
+ String groupId = externalGroup.getId();
+ Group group;
+ Authorizable a = userManager.getAuthorizable(groupId);
+ if (a == null) {
+ group = createGroup(externalGroup);
+ } else {
+ group = (a.isGroup()) ? (Group) a : null;
+ }
+
+ if (group != null) {
+ group.addMember(authorizable);
+ } else {
+ log.debug("No such group " + groupId + "; Ignoring group membership.");
+ }
+ }
+ }
+
+ Map<String, ?> properties = externalUser.getProperties();
+ for (String key : properties.keySet()) {
+ Object prop = properties.get(key);
+ if (prop instanceof Collection) {
+ Value[] values = createValues((Collection) prop);
+ if (values != null) {
+ authorizable.setProperty(key, values);
+ }
+ } else {
+ Value value = createValue(prop);
+ if (value != null) {
+ authorizable.setProperty(key, value);
+ }
+ }
+ }
+ }
+
+ @CheckForNull
+ private Value createValue(Object propValue) throws ValueFormatException {
+ int type = getType(propValue);
+ if (type == PropertyType.UNDEFINED) {
+ return null;
+ } else {
+ return valueFactory.createValue(propValue.toString(), type);
+ }
+ }
+
+ @CheckForNull
+ private Value[] createValues(Collection<?> propValues) throws ValueFormatException {
+ List<Value> values = new ArrayList<Value>();
+ for (Object obj : propValues) {
+ Value v = createValue(obj);
+ if (v != null) {
+ values.add(v);
+ }
+ }
+ return values.toArray(new Value[values.size()]);
+ }
+
+ private int getType(Object propValue) {
+ // TODO: add proper type detection
+ if (propValue == null) {
+ return PropertyType.UNDEFINED;
+ } else {
+ return PropertyType.STRING;
+ }
+ }
+
+ }
+
+ /**
+ * Robust relative path concatenation.
+ * @param paths relative paths
+ * @return the concatenated path
+ */
+ private static String concatPaths(String ... paths) {
+ StringBuilder result = new StringBuilder();
+ for (String path: paths) {
+ if (path != null && !path.isEmpty()) {
+ int i0 = 0;
+ int i1 = path.length();
+ while (i0 < i1 && path.charAt(i0) == '/') {
+ i0++;
+ }
+ while (i1 > i0 && path.charAt(i1-1) == '/') {
+ i1--;
+ }
+ if (i1 > i0) {
+ if (result.length() > 0) {
+ result.append('/');
+ }
+ result.append(path.substring(i0, i1));
+ }
+ }
+ }
+ return result.length() == 0 ? null : result.toString();
+ }
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalIDPManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalIDPManagerImpl.java?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalIDPManagerImpl.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalIDPManagerImpl.java Tue Feb 11 00:28:49 2014
@@ -0,0 +1,76 @@
+/*
+ * 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 javax.annotation.Nonnull;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.osgi.OsgiWhiteboard;
+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.whiteboard.AbstractServiceTracker;
+import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
+import org.osgi.service.component.ComponentContext;
+
+/**
+ * {@code ExternalIDPManagerImpl} is used to manage registered external identity provider. This class automatically
+ * tracks the IDPs that are registered via OSGi but can also be used in non-OSGi environments by manually adding and
+ * removing the providers.
+ */
+@Component(immediate = true)
+@Service
+public class ExternalIDPManagerImpl extends AbstractServiceTracker<ExternalIdentityProvider> implements ExternalIdentityProviderManager {
+
+ /**
+ * Default constructor used by OSGi
+ */
+ public ExternalIDPManagerImpl() {
+ super(ExternalIdentityProvider.class);
+ }
+
+ /**
+ * Constructor used by non OSGi
+ * @param whiteboard the whiteboard
+ */
+ public ExternalIDPManagerImpl(Whiteboard whiteboard) {
+ super(ExternalIdentityProvider.class);
+ start(whiteboard);
+ }
+
+ @Activate
+ private void activate(ComponentContext ctx) {
+ start(new OsgiWhiteboard(ctx.getBundleContext()));
+ }
+
+ @Deactivate
+ private void deactivate() {
+ stop();
+ }
+
+ @Override
+ public ExternalIdentityProvider getProvider(@Nonnull String name) {
+ for (ExternalIdentityProvider provider: getServices()) {
+ if (name.equals(provider.getName())) {
+ return provider;
+ }
+ }
+ return null;
+ }
+}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java?rev=1566895&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java Tue Feb 11 00:28:49 2014
@@ -0,0 +1,253 @@
+/*
+ * 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.security.Principal;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+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.AuthInfoImpl;
+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.SyncContext;
+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.SyncManager;
+import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
+import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils;
+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);
+
+ /**
+ * 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";
+
+ /**
+ * 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 configured sync handler as specified by the {@link #PARAM_SYNC_HANDLER_NAME}
+ */
+ private SyncHandler syncHandler;
+
+ /**
+ * The external user as resolved in the login call.
+ */
+ private ExternalUser externalUser;
+
+ /**
+ * Login credentials
+ */
+ private Credentials credentials;
+
+ /**
+ * 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);
+ }
+
+ Whiteboard whiteboard = getSecurityProvider().getConfiguration(Whiteboard.class);
+
+ 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 = WhiteboardUtils.getService(whiteboard, ExternalIdentityProviderManager.class);
+ if (idpMgr == null) {
+ log.error("External login module needs IDPManager. Will not be used for login.");
+ } else {
+ idp = idpMgr.getProvider(idpName);
+ if (idp == null) {
+ log.error("No IDP found with name {}. Will not be used for login.", idpName);
+ }
+ }
+ }
+
+ String syncHandlerName = options.getConfigValue(PARAM_SYNC_HANDLER_NAME, "");
+ if (syncHandlerName.length() == 0) {
+ log.error("External login module needs SyncHandler name. Will not be used for login.");
+ } else {
+ SyncManager syncMgr = WhiteboardUtils.getService(whiteboard, SyncManager.class);
+ if (syncMgr == null) {
+ log.error("External login module needs SyncManager. Will not be used for login.");
+ } else {
+ syncHandler = syncMgr.getSyncHandler(syncHandlerName);
+ if (syncHandler == null) {
+ log.error("No SyncHandler found with name {}. Will not be used for login.", syncHandlerName);
+ }
+ }
+ }
+ }
+
+ @Override
+ public boolean login() throws LoginException {
+ if (idp == null || syncHandler == null) {
+ return false;
+ }
+
+ credentials = getCredentials();
+ if (credentials == null) {
+ log.debug("No credentials found for external login module. ignoring.");
+ return false;
+ }
+
+ try {
+ externalUser = idp.authenticate(credentials);
+ if (externalUser != null) {
+ if (log.isDebugEnabled()) {
+ log.debug("IDP {} returned valid user {}", idp.getName(), externalUser);
+ }
+
+ //noinspection unchecked
+ sharedState.put(SHARED_KEY_CREDENTIALS, credentials);
+
+ //noinspection unchecked
+ sharedState.put(SHARED_KEY_LOGIN_NAME, externalUser.getId());
+
+ return true;
+ } else {
+ if (log.isDebugEnabled()) {
+ if (credentials instanceof SimpleCredentials) {
+ log.debug("IDP {} returned null for simple creds of {}", idp.getName(), ((SimpleCredentials) credentials).getUserID());
+ } else {
+ log.debug("IDP {} returned null for {}", idp.getName(), credentials);
+ }
+ }
+ }
+ } catch (ExternalIdentityException e) {
+ log.error("Error while authenticating credentials {} with {}: {}", new Object[]{
+ credentials, idp.getName(), e.toString()});
+ return false;
+ } catch (LoginException e) {
+ if (log.isDebugEnabled()) {
+ log.debug("IDP {} throws login exception for {}", idp.getName(), credentials);
+ }
+ throw e;
+ }
+ 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 || syncHandler == null) {
+ return false;
+ }
+
+ SyncContext context = null;
+ try {
+ Root root = getRoot();
+ UserManager userManager = getUserManager();
+ if (root == null || userManager == null) {
+ throw new LoginException("Cannot synchronize user.");
+ }
+ context = syncHandler.createContext(idp, userManager, root);
+ context.sync(externalUser);
+ root.commit();
+
+ Set<? extends Principal> principals = getPrincipals(externalUser.getId());
+ if (!principals.isEmpty()) {
+ if (!subject.isReadOnly()) {
+ subject.getPrincipals().addAll(principals);
+ subject.getPublicCredentials().add(credentials);
+ setAuthInfo(new AuthInfoImpl(externalUser.getId(), null, principals), subject);
+ } else {
+ log.debug("Could not add information to read only subject {}", subject);
+ }
+ return true;
+ }
+ return false;
+ } catch (SyncException e) {
+ throw new LoginException("User synchronization failed: " + e);
+ } catch (CommitFailedException e) {
+ throw new LoginException("User synchronization failed: " + e);
+ } finally {
+ if (context != null) {
+ context.close();
+ }
+ }
+ }
+
+ @Override
+ protected void clearState() {
+ super.clearState();
+ externalUser = null;
+ credentials = null;
+ }
+}
\ No newline at end of file