Author: tripod
Date: Fri Jun 12 23:02:14 2015
New Revision: 1685189
URL: http://svn.apache.org/r1685189
Log:
OAK-2948 Expose DefaultSyncHandler
Added:
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncConfig.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncContext.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncResultImpl.java
- copied, changed from r1685106,
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncResultImpl.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncedIdentity.java
- copied, changed from r1685106,
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncedIdentityImpl.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/package-info.java
- copied, changed from r1685106,
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncResultImpl.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfigImpl.java
- copied, changed from r1685106,
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfig.java
Removed:
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/SyncResultImpl.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncedIdentityImpl.java
Modified:
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/jmx/SyncMBeanImpl.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-ldap/src/test/java/org/apache/jackrabbit/oak/security/authentication/ldap/LdapLoginTestBase.java
Added:
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/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/basic/DefaultSyncConfig.java?rev=1685189&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncConfig.java
(added)
+++
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncConfig.java
Fri Jun 12 23:02:14 2015
@@ -0,0 +1,259 @@
+/*
+ * 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.basic;
+
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+/**
+ * {@code DefaultSyncConfig} defines how users and groups from an external
source are synced into the repository using
+ * the {@link
org.apache.jackrabbit.oak.spi.security.authentication.external.impl.DefaultSyncHandler}.
+ */
+public class DefaultSyncConfig {
+
+ private final User user = new User();
+
+ private final Group group = new Group();
+
+ private String name = "default";
+
+ /**
+ * 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.
+ */
+ @Nonnull
+ public User user() {
+ return user;
+ }
+
+ /**
+ * Returns the sync configuration for groups.
+ * @return the group sync configuration.
+ */
+ @Nonnull
+ public Group group() {
+ return group;
+ }
+
+ /**
+ * 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 == null ? Collections.<String>emptySet() :
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>();
+ for (String groupName: autoMembership) {
+ if (!groupName.trim().isEmpty()) {
+ this.autoMembership.add(groupName.trim());
+ }
+ }
+ 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 == null ? Collections.<String,
String>emptyMap() : 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 == null ? "" : pathPrefix;
+ }
+
+ /**
+ * Sets the path prefix.
+ * @param pathPrefix the path prefix.
+ * @return {@code this}
+ * @see #getPathPrefix()
+ */
+ @Nonnull
+ public Authorizable setPathPrefix(String pathPrefix) {
+ this.pathPrefix = 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 {
+
+ }
+}
\ No newline at end of file
Added:
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncContext.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncContext.java?rev=1685189&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncContext.java
(added)
+++
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncContext.java
Fri Jun 12 23:02:14 2015
@@ -0,0 +1,716 @@
+/*************************************************************************
+ * ADOBE CONFIDENTIAL
+ * ___________________
+ * <p/>
+ * Copyright ${today.year} Adobe Systems Incorporated
+ * All Rights Reserved.
+ * <p/>
+ * 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.spi.security.authentication.external.basic;
+
+import java.io.ByteArrayInputStream;
+import java.math.BigDecimal;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.jcr.Binary;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+
+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.commons.DebugTimer;
+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.SyncResult;
+import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Internal implementation of the sync context
+ */
+public class DefaultSyncContext implements SyncContext {
+
+ /**
+ * default logger
+ */
+ private static final Logger log =
LoggerFactory.getLogger(DefaultSyncContext.class);
+
+ /**
+ * Name of the {@link ExternalIdentity#getExternalId()} property of a
synchronized identity.
+ */
+ public static final String REP_EXTERNAL_ID = "rep:externalId";
+
+ /**
+ * Name of the property that stores the time when an identity was synced.
+ */
+ public static final String REP_LAST_SYNCED = "rep:lastSynced";
+
+ protected final DefaultSyncConfig config;
+
+ protected final ExternalIdentityProvider idp;
+
+ protected final UserManager userManager;
+
+ protected final ValueFactory valueFactory;
+
+ protected boolean keepMissing;
+
+ protected boolean forceUserSync;
+
+ protected boolean forceGroupSync;
+
+ // we use the same wall clock for the entire context
+ protected final long now;
+
+ protected final Value nowValue;
+
+ public DefaultSyncContext(DefaultSyncConfig config,
ExternalIdentityProvider idp, UserManager userManager, ValueFactory
valueFactory) {
+ this.config = config;
+ this.idp = idp;
+ this.userManager = userManager;
+ this.valueFactory = valueFactory;
+
+ // initialize 'now'
+ final Calendar nowCal = Calendar.getInstance();
+ this.nowValue = valueFactory.createValue(nowCal);
+ this.now = nowCal.getTimeInMillis();
+ }
+
+ /**
+ * Creates a synced identity from the given authorizable.
+ * @param auth the authorizable
+ * @return the id
+ * @throws RepositoryException if an error occurs
+ */
+ @CheckForNull
+ public static DefaultSyncedIdentity createSyncedIdentity(@Nullable
Authorizable auth) throws RepositoryException {
+ ExternalIdentityRef ref = (auth == null) ? null : getIdentityRef(auth);
+ if (ref == null) {
+ return null;
+ } else {
+ Value[] lmValues = auth.getProperty(REP_LAST_SYNCED);
+ long lastModified = -1;
+ if (lmValues != null && lmValues.length > 0) {
+ lastModified = lmValues[0].getLong();
+ }
+ return new DefaultSyncedIdentity(auth.getID(), ref,
auth.isGroup(), lastModified);
+ }
+ }
+
+ /**
+ * Retrieves the external identity ref from the authorizable
+ * @param auth the authorizable
+ * @return the ref
+ * @throws RepositoryException if an error occurs
+ */
+ @CheckForNull
+ public static ExternalIdentityRef getIdentityRef(@Nullable Authorizable
auth) throws RepositoryException {
+ if (auth == null) {
+ return null;
+ }
+ Value[] v = auth.getProperty(REP_EXTERNAL_ID);
+ if (v == null || v.length == 0) {
+ return null;
+ }
+ return ExternalIdentityRef.fromString(v[0].getString());
+ }
+
+ /**
+ * Robust relative path concatenation.
+ * @param paths relative paths
+ * @return the concatenated path
+ */
+ public static String joinPaths(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();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void close() {
+ // nothing to do
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isKeepMissing() {
+ return keepMissing;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Nonnull
+ @Override
+ public SyncContext setKeepMissing(boolean keepMissing) {
+ this.keepMissing = keepMissing;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isForceUserSync() {
+ return forceUserSync;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Nonnull
+ @Override
+ public SyncContext setForceUserSync(boolean forceUserSync) {
+ this.forceUserSync = forceUserSync;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isForceGroupSync() {
+ return forceGroupSync;
+ }
+
+ @Nonnull
+ public SyncContext setForceGroupSync(boolean forceGroupSync) {
+ this.forceGroupSync = forceGroupSync;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Nonnull
+ @Override
+ public SyncResult sync(@Nonnull ExternalIdentity identity) throws
SyncException {
+ try {
+ DebugTimer timer = new DebugTimer();
+ DefaultSyncResultImpl ret;
+ boolean created = false;
+ if (identity instanceof ExternalUser) {
+ User user = getAuthorizable(identity, User.class);
+ timer.mark("find");
+ if (user == null) {
+ user = createUser((ExternalUser) identity);
+ timer.mark("create");
+ created = true;
+ }
+ ret = syncUser((ExternalUser) identity, user);
+ timer.mark("sync");
+ } else if (identity instanceof ExternalGroup) {
+ Group group = getAuthorizable(identity, Group.class);
+ timer.mark("find");
+ if (group == null) {
+ group = createGroup((ExternalGroup) identity);
+ timer.mark("create");
+ created = true;
+ }
+ ret = syncGroup((ExternalGroup) identity, group);
+ timer.mark("sync");
+ } else {
+ throw new IllegalArgumentException("identity must be user or
group but was: " + identity);
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("sync({}) -> {} {}",
identity.getExternalId().getString(), identity.getId(), timer.getString());
+ }
+ if (created) {
+ ret.setStatus(SyncResult.Status.ADD);
+ }
+ return ret;
+ } catch (RepositoryException e) {
+ throw new SyncException(e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Nonnull
+ @Override
+ public SyncResult sync(@Nonnull String id) throws SyncException {
+ try {
+ DebugTimer timer = new DebugTimer();
+ DefaultSyncResultImpl ret;
+ // find authorizable
+ Authorizable auth = userManager.getAuthorizable(id);
+ if (auth == null) {
+ return new DefaultSyncResultImpl(new DefaultSyncedIdentity(id,
null, false, -1), SyncResult.Status.NO_SUCH_AUTHORIZABLE);
+ }
+ // check if we need to deal with this authorizable
+ ExternalIdentityRef ref = DefaultSyncContext.getIdentityRef(auth);
+ if (ref == null || !idp.getName().equals(ref.getProviderName())) {
+ return new DefaultSyncResultImpl(new DefaultSyncedIdentity(id,
null, false, -1), SyncResult.Status.FOREIGN);
+ }
+
+ if (auth instanceof Group) {
+ Group group = (Group) auth;
+ ExternalGroup external = idp.getGroup(id);
+ timer.mark("retrieve");
+ if (external == null) {
+ DefaultSyncedIdentity syncId =
DefaultSyncContext.createSyncedIdentity(auth);
+ if (group.getDeclaredMembers().hasNext()) {
+ log.info("won't remove local group with members: {}",
id);
+ ret = new DefaultSyncResultImpl(syncId,
SyncResult.Status.NOP);
+ } else if (!keepMissing) {
+ auth.remove();
+ log.debug("removing authorizable '{}' that no longer
exists on IDP {}", id, idp.getName());
+ timer.mark("remove");
+ ret = new DefaultSyncResultImpl(syncId,
SyncResult.Status.DELETE);
+ } else {
+ ret = new DefaultSyncResultImpl(syncId,
SyncResult.Status.MISSING);
+ log.info("external identity missing for {}, but purge
== false.", id);
+ }
+ } else {
+ ret = syncGroup(external, group);
+ timer.mark("sync");
+ }
+ } else {
+ ExternalUser external = idp.getUser(id);
+ timer.mark("retrieve");
+ if (external == null) {
+ DefaultSyncedIdentity syncId =
DefaultSyncContext.createSyncedIdentity(auth);
+ if (!keepMissing) {
+ auth.remove();
+ log.debug("removing authorizable '{}' that no longer
exists on IDP {}", id, idp.getName());
+ timer.mark("remove");
+ ret = new DefaultSyncResultImpl(syncId,
SyncResult.Status.DELETE);
+ } else {
+ ret = new DefaultSyncResultImpl(syncId,
SyncResult.Status.MISSING);
+ log.info("external identity missing for {}, but purge
== false.", id);
+ }
+ } else {
+ ret = syncUser(external, (User) auth);
+ timer.mark("sync");
+ }
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("sync({}) -> {} {}", id, ref.getString(),
timer.getString());
+ }
+ return ret;
+ } catch (RepositoryException e) {
+ throw new SyncException(e);
+ } catch (ExternalIdentityException e) {
+ throw new SyncException(e);
+ }
+ }
+
+ /**
+ * Retrieves the repository authorizable that corresponds to the given
external identity
+ * @param external the external identity
+ * @param type the authorizable type
+ * @return the repository authorizable or {@code null} if not found.
+ * @throws RepositoryException if an error occurs.
+ * @throws SyncException if the repository contains a colliding
authorizable with the same name.
+ */
+ @CheckForNull
+ protected <T extends Authorizable> T getAuthorizable(@Nonnull
ExternalIdentity external, Class<T> type)
+ throws RepositoryException, SyncException {
+ Authorizable authorizable =
userManager.getAuthorizable(external.getId());
+ if (authorizable == null) {
+ authorizable =
userManager.getAuthorizable(external.getPrincipalName());
+ }
+ if (authorizable == null) {
+ return null;
+ } else if (type.isInstance(authorizable)) {
+ //noinspection unchecked
+ return (T) authorizable;
+ } else {
+ log.error("Unable to process external {}: {}. Colliding
authorizable exists in repository.", type.getSimpleName(), external.getId());
+ throw new SyncException("Unexpected authorizable: " +
authorizable);
+ }
+ }
+
+ /**
+ * Creates a new repository user for the given external one.
+ * Note that this method only creates the authorizable but does not
perform any synchronization.
+ *
+ * @param externalUser the external user
+ * @return the repository user
+ * @throws RepositoryException if an error occurs
+ */
+ @Nonnull
+ protected User createUser(@Nonnull ExternalUser externalUser) throws
RepositoryException {
+ Principal principal = new
PrincipalImpl(externalUser.getPrincipalName());
+ User user = userManager.createUser(
+ externalUser.getId(),
+ null,
+ principal,
+ joinPaths(config.user().getPathPrefix(),
externalUser.getIntermediatePath())
+ );
+ user.setProperty(REP_EXTERNAL_ID,
valueFactory.createValue(externalUser.getExternalId().getString()));
+ return user;
+ }
+
+ /**
+ * Creates a new repository group for the given external one.
+ * Note that this method only creates the authorizable but does not
perform any synchronization.
+ *
+ * @param externalGroup the external group
+ * @return the repository group
+ * @throws RepositoryException if an error occurs
+ */
+ @Nonnull
+ protected Group createGroup(@Nonnull ExternalGroup externalGroup) throws
RepositoryException {
+ Principal principal = new
PrincipalImpl(externalGroup.getPrincipalName());
+ Group group = userManager.createGroup(
+ externalGroup.getId(),
+ principal,
+ joinPaths(config.group().getPathPrefix(),
externalGroup.getIntermediatePath())
+ );
+ group.setProperty(REP_EXTERNAL_ID,
valueFactory.createValue(externalGroup.getExternalId().getString()));
+ return group;
+ }
+
+ @Nonnull
+ protected DefaultSyncResultImpl syncUser(@Nonnull ExternalUser external,
@Nonnull User user) throws RepositoryException {
+ // first check if user is expired
+ if (!forceUserSync && !isExpired(user,
config.user().getExpirationTime(), "Properties")) {
+ DefaultSyncedIdentity syncId =
DefaultSyncContext.createSyncedIdentity(user);
+ return new DefaultSyncResultImpl(syncId, SyncResult.Status.NOP);
+ }
+
+ // synchronize the properties
+ syncProperties(external, user, config.user().getPropertyMapping());
+
+ // synchronize auto-group membership
+ applyMembership(user, config.user().getAutoMembership());
+
+ if (isExpired(user, config.user().getMembershipExpirationTime(),
"Membership")) {
+ // synchronize external memberships
+ syncMembership(external, user,
config.user().getMembershipNestingDepth());
+ }
+
+ // finally "touch" the sync property
+ user.setProperty(REP_LAST_SYNCED, nowValue);
+ DefaultSyncedIdentity syncId =
DefaultSyncContext.createSyncedIdentity(user);
+ return new DefaultSyncResultImpl(syncId, SyncResult.Status.UPDATE);
+ }
+
+ @Nonnull
+ protected DefaultSyncResultImpl syncGroup(@Nonnull ExternalGroup external,
@Nonnull Group group) throws RepositoryException {
+ // first check if user is expired
+ if (!forceGroupSync && !isExpired(group,
config.group().getExpirationTime(), "Properties")) {
+ DefaultSyncedIdentity syncId =
DefaultSyncContext.createSyncedIdentity(group);
+ return new DefaultSyncResultImpl(syncId, SyncResult.Status.NOP);
+ }
+
+ // synchronize the properties
+ syncProperties(external, group, config.group().getPropertyMapping());
+
+ // synchronize auto-group membership
+ applyMembership(group, config.group().getAutoMembership());
+
+ // finally "touch" the sync property
+ group.setProperty(REP_LAST_SYNCED, nowValue);
+ DefaultSyncedIdentity syncId =
DefaultSyncContext.createSyncedIdentity(group);
+ return new DefaultSyncResultImpl(syncId, SyncResult.Status.UPDATE);
+ }
+
+ /**
+ * Recursively sync the memberships of an authorizable up-to the specified
depth. If the given depth
+ * is equal or less than 0, no syncing is performed.
+ *
+ * @param external the external identity
+ * @param auth the authorizable
+ * @param depth recursion depth.
+ * @throws RepositoryException
+ */
+ protected void syncMembership(ExternalIdentity external, Authorizable
auth, long depth)
+ throws RepositoryException {
+ if (depth <= 0) {
+ return;
+ }
+ if (log.isDebugEnabled()) {
+ log.debug("Syncing membership '{}' -> '{}'",
external.getExternalId().getString(), auth.getID());
+ }
+
+ final DebugTimer timer = new DebugTimer();
+ Iterable<ExternalIdentityRef> externalGroups;
+ try {
+ externalGroups = external.getDeclaredGroups();
+ } catch (ExternalIdentityException e) {
+ log.error("Error while retrieving external declared groups for
'{}'", external.getId(), e);
+ return;
+ }
+ timer.mark("fetching");
+
+ // first get the set of the existing groups that are synced ones
+ Map<String, Group> declaredExternalGroups = new HashMap<String,
Group>();
+ Iterator<Group> grpIter = auth.declaredMemberOf();
+ while (grpIter.hasNext()) {
+ Group grp = grpIter.next();
+ if (isSameIDP(grp)) {
+ declaredExternalGroups.put(grp.getID(), grp);
+ }
+ }
+ timer.mark("reading");
+
+ for (ExternalIdentityRef ref : externalGroups) {
+ log.debug("- processing membership {}", ref.getId());
+ // get group
+ ExternalGroup extGroup;
+ try {
+ extGroup = (ExternalGroup) idp.getIdentity(ref);
+ } catch (ClassCastException e) {
+ // this should really not be the case, so catching the CCE is
ok here.
+ log.warn("External identity '{}' is not a group, but should be
one.", ref.getString());
+ continue;
+ } catch (ExternalIdentityException e) {
+ log.warn("Unable to retrieve external group '{}' from
provider.", ref.getString(), e);
+ continue;
+ }
+ if (extGroup == null) {
+ log.warn("External group for ref '{}' could not be retrieved
from provider.", ref);
+ continue;
+ }
+ log.debug("- idp returned '{}'", extGroup.getId());
+
+ Group grp;
+ try {
+ grp = (Group) userManager.getAuthorizable(extGroup.getId());
+ } catch (ClassCastException e) {
+ // this should really not be the case, so catching the CCE is
ok here.
+ log.warn("Authorizable '{}' is not a group, but should be
one.", extGroup.getId());
+ continue;
+ }
+ log.debug("- user manager returned '{}'", grp);
+
+ if (grp == null) {
+ grp = createGroup(extGroup);
+ log.debug("- created new group");
+ }
+ syncGroup(extGroup, grp);
+
+ // ensure membership
+ grp.addMember(auth);
+ log.debug("- added '{}' as member to '{}'", auth, grp);
+
+ // remember the declared group
+ declaredExternalGroups.remove(grp.getID());
+
+ // recursively apply further membership
+ if (depth > 1) {
+ log.debug("- recursively sync group membership of '{}' (depth
= {}).", grp.getID(), depth);
+ syncMembership(extGroup, grp, depth - 1);
+ } else {
+ log.debug("- group nesting level for '{}' reached",
grp.getID());
+ }
+ }
+ timer.mark("adding");
+ // remove us from the lost membership groups
+ for (Group grp: declaredExternalGroups.values()) {
+ grp.removeMember(auth);
+ log.debug("- removing member '{}' for group '{}'", auth.getID(),
grp.getID());
+ }
+ if (log.isDebugEnabled()) {
+ timer.mark("removing");
+ log.debug("syncMembership({}) {}", external.getId(),
timer.getString());
+ }
+ }
+
+ /**
+ * Ensures that the given authorizable is member of the specific groups.
Note that it does not create groups
+ * if missing, nor remove memberships of groups not in the given set.
+ * @param member the authorizable
+ * @param groups set of groups.
+ */
+ protected void applyMembership(Authorizable member, Set<String> groups)
throws RepositoryException {
+ for (String groupName: groups) {
+ Authorizable group = userManager.getAuthorizable(groupName);
+ if (group == null) {
+ log.warn("Unable to apply auto-membership to {}. No such
group: {}", member.getID(), groupName);
+ } else if (group instanceof Group) {
+ ((Group) group).addMember(member);
+ } else {
+ log.warn("Unable to apply auto-membership to {}. Authorizable
'{}' is not a group.", member.getID(), groupName);
+ }
+ }
+ }
+
+ /**
+ * Syncs the properties specified in the {@code mapping} from the external
identity to the given authorizable.
+ * Note that this method does not check for value equality and just
blindly copies or deletes the properties.
+ *
+ * @param ext external identity
+ * @param auth the authorizable
+ * @param mapping the property mapping
+ * @throws RepositoryException if an error occurs
+ */
+ protected void syncProperties(ExternalIdentity ext, Authorizable auth,
Map<String, String> mapping)
+ throws RepositoryException {
+ Map<String, ?> properties = ext.getProperties();
+ for (Map.Entry<String, String> entry: mapping.entrySet()) {
+ String relPath = entry.getKey();
+ String name = entry.getValue();
+ Object obj = properties.get(name);
+ if (obj == null) {
+ int nameLen = name.length();
+ if (nameLen > 1 && name.charAt(0) == '"' &&
name.charAt(nameLen-1) == '"') {
+ auth.setProperty(relPath,
valueFactory.createValue(name.substring(1, nameLen - 1)));
+ } else {
+ auth.removeProperty(relPath);
+ }
+ } else {
+ if (obj instanceof Collection) {
+ auth.setProperty(relPath, createValues((Collection) obj));
+ } else if (obj instanceof byte[] || obj instanceof char[]) {
+ auth.setProperty(relPath, createValue(obj));
+ } else if (obj instanceof Object[]) {
+ auth.setProperty(relPath,
createValues(Arrays.asList((Object[]) obj)));
+ } else {
+ auth.setProperty(relPath, createValue(obj));
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks if the given authorizable needs syncing based on the {@link
#REP_LAST_SYNCED} property.
+ * @param auth the authorizable to check
+ * @param expirationTime the expiration time to compare to.
+ * @param type debug message type
+ * @return {@code true} if the authorizable needs sync
+ */
+ protected boolean isExpired(Authorizable auth, long expirationTime, String
type) throws RepositoryException {
+ Value[] values = auth.getProperty(REP_LAST_SYNCED);
+ if (values == null || values.length == 0) {
+ if (log.isDebugEnabled()) {
+ log.debug("{} of {} '{}' need sync. " + REP_LAST_SYNCED + "
not set.",
+ type, auth.isGroup() ? "group" : "user", auth.getID());
+ }
+ return true;
+ } else if (now - values[0].getLong() > expirationTime) {
+ if (log.isDebugEnabled()) {
+ log.debug("{} of {} '{}' need sync. " + REP_LAST_SYNCED + "
expired ({} > {})",
+ type, auth.isGroup() ? "group" : "user", auth.getID(),
now - values[0].getLong(), expirationTime);
+ }
+ return true;
+ } else {
+ if (log.isDebugEnabled()) {
+ log.debug("{} of {} '{}' do not need sync.", type,
auth.isGroup() ? "group" : "user", auth.getID());
+ }
+ return false;
+ }
+ }
+
+ /**
+ * Creates a new JCR value of the given object, checking the internal type.
+ * @param v the value
+ * @return the JCR value or null
+ * @throws RepositoryException if an error occurs
+ */
+ @CheckForNull
+ protected Value createValue(@Nullable Object v) throws RepositoryException
{
+ if (v == null) {
+ return null;
+ } else if (v instanceof Boolean) {
+ return valueFactory.createValue((Boolean) v);
+ } else if (v instanceof Byte || v instanceof Short || v instanceof
Integer || v instanceof Long) {
+ return valueFactory.createValue(((Number) v).longValue());
+ } else if (v instanceof Float || v instanceof Double) {
+ return valueFactory.createValue(((Number) v).doubleValue());
+ } else if (v instanceof BigDecimal) {
+ return valueFactory.createValue((BigDecimal) v);
+ } else if (v instanceof Calendar) {
+ return valueFactory.createValue((Calendar) v);
+ } else if (v instanceof Date) {
+ Calendar cal = Calendar.getInstance();
+ cal.setTime((Date) v);
+ return valueFactory.createValue(cal);
+ } else if (v instanceof byte[]) {
+ Binary bin = valueFactory.createBinary(new
ByteArrayInputStream((byte[])v));
+ return valueFactory.createValue(bin);
+ } else if (v instanceof char[]) {
+ return valueFactory.createValue(new String((char[]) v));
+ } else {
+ return valueFactory.createValue(String.valueOf(v));
+ }
+ }
+
+ /**
+ * Creates an array of JCR values based on the type.
+ * @param propValues the given values
+ * @return and array of JCR values
+ * @throws RepositoryException if an error occurs
+ */
+ @CheckForNull
+ protected Value[] createValues(Collection<?> propValues) throws
RepositoryException {
+ 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()]);
+ }
+
+ /**
+ * Checks if the given authorizable was synced from the same IDP by
comparing the IDP name of the
+ * {@value #REP_EXTERNAL_ID} property.
+ *
+ * todo: allow multiple IDPs on 1 authorizable
+ *
+ * @param auth the authorizable.
+ * @return {@code true} if same IDP.
+ */
+ protected boolean isSameIDP(@Nullable Authorizable auth) throws
RepositoryException {
+ ExternalIdentityRef ref = DefaultSyncContext.getIdentityRef(auth);
+ return ref != null && idp.getName().equals(ref.getProviderName());
+ }
+}
\ No newline at end of file
Copied:
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncResultImpl.java
(from r1685106,
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncResultImpl.java)
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncResultImpl.java?p2=jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncResultImpl.java&p1=jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncResultImpl.java&r1=1685106&r2=1685189&rev=1685189&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncResultImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncResultImpl.java
Fri Jun 12 23:02:14 2015
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.jackrabbit.oak.spi.security.authentication.external.impl;
+package org.apache.jackrabbit.oak.spi.security.authentication.external.basic;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -22,21 +22,21 @@ import javax.annotation.Nonnull;
import
org.apache.jackrabbit.oak.spi.security.authentication.external.SyncResult;
/**
-* {@code SyncResultImpl}...
-*/
-public class SyncResultImpl implements SyncResult {
+ * Implements a simple sync result with and id and a status.
+ */
+public class DefaultSyncResultImpl implements SyncResult {
- private final SyncedIdentityImpl id;
+ private final DefaultSyncedIdentity id;
private Status status = Status.NOP;
- public SyncResultImpl(SyncedIdentityImpl id, Status status) {
+ public DefaultSyncResultImpl(DefaultSyncedIdentity id, Status status) {
this.id = id;
this.status = status;
}
@CheckForNull
- public SyncedIdentityImpl getIdentity() {
+ public DefaultSyncedIdentity getIdentity() {
return id;
}
Copied:
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncedIdentity.java
(from r1685106,
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncedIdentityImpl.java)
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncedIdentity.java?p2=jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncedIdentity.java&p1=jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncedIdentityImpl.java&r1=1685106&r2=1685189&rev=1685189&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncedIdentityImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncedIdentity.java
Fri Jun 12 23:02:14 2015
@@ -14,7 +14,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.jackrabbit.oak.spi.security.authentication.external.impl;
+package org.apache.jackrabbit.oak.spi.security.authentication.external.basic;
import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
@@ -23,7 +23,10 @@ import javax.annotation.Nullable;
import
org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityRef;
import
org.apache.jackrabbit.oak.spi.security.authentication.external.SyncedIdentity;
-public class SyncedIdentityImpl implements SyncedIdentity {
+/**
+ * Implements a simple synced identity that maps an authorizable id to an
external ref.
+ */
+public class DefaultSyncedIdentity implements SyncedIdentity {
private final String id;
@@ -33,7 +36,7 @@ public class SyncedIdentityImpl implemen
private final long lastSynced;
- public SyncedIdentityImpl(@Nonnull String id, @Nullable
ExternalIdentityRef ref, boolean isGroup, long lastSynced) {
+ public DefaultSyncedIdentity(@Nonnull String id, @Nullable
ExternalIdentityRef ref, boolean isGroup, long lastSynced) {
this.id = id;
this.ref = ref;
this.isGroup = isGroup;
Copied:
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/package-info.java
(from r1685106,
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncResultImpl.java)
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/package-info.java?p2=jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/package-info.java&p1=jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncResultImpl.java&r1=1685106&r2=1685189&rev=1685189&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncResultImpl.java
(original)
+++
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/package-info.java
Fri Jun 12 23:02:14 2015
@@ -14,38 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.jackrabbit.oak.spi.security.authentication.external.impl;
+@Version("1.0.0")
+@Export
+package org.apache.jackrabbit.oak.spi.security.authentication.external.basic;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nonnull;
-
-import
org.apache.jackrabbit.oak.spi.security.authentication.external.SyncResult;
-
-/**
-* {@code SyncResultImpl}...
-*/
-public class SyncResultImpl implements SyncResult {
-
- private final SyncedIdentityImpl id;
-
- private Status status = Status.NOP;
-
- public SyncResultImpl(SyncedIdentityImpl id, Status status) {
- this.id = id;
- this.status = status;
- }
-
- @CheckForNull
- public SyncedIdentityImpl getIdentity() {
- return id;
- }
-
- @Nonnull
- public Status getStatus() {
- return status;
- }
-
- public void setStatus(Status status) {
- this.status = status;
- }
-}
\ No newline at end of file
+import aQute.bnd.annotation.Version;
+import aQute.bnd.annotation.Export;
\ No newline at end of file
Copied:
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfigImpl.java
(from r1685106,
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/DefaultSyncConfigImpl.java?p2=jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfigImpl.java&p1=jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfig.java&r1=1685106&r2=1685189&rev=1685189&view=diff
==============================================================================
---
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfig.java
(original)
+++
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfigImpl.java
Fri Jun 12 23:02:14 2015
@@ -17,17 +17,15 @@
package org.apache.jackrabbit.oak.spi.security.authentication.external.impl;
-import java.util.Collections;
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;
+import
org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncConfig;
/**
* {@code DefaultSyncConfig} defines how users and groups from an external
source are synced into the repository using
@@ -40,7 +38,7 @@ import org.apache.jackrabbit.oak.spi.sec
metatype = true,
ds = false
)
-public class DefaultSyncConfig {
+public class DefaultSyncConfigImpl extends DefaultSyncConfig {
/**
* @see #getName()
@@ -58,12 +56,12 @@ public class DefaultSyncConfig {
public static final String PARAM_NAME = "handler.name";
/**
- * @see DefaultSyncConfig.User#getExpirationTime()
+ * @see DefaultSyncConfigImpl.User#getExpirationTime()
*/
public static final String PARAM_USER_EXPIRATION_TIME_DEFAULT = "1h";
/**
- * @see DefaultSyncConfig.User#getExpirationTime()
+ * @see DefaultSyncConfigImpl.User#getExpirationTime()
*/
@Property(
label = "User Expiration Time",
@@ -73,12 +71,12 @@ public class DefaultSyncConfig {
public static final String PARAM_USER_EXPIRATION_TIME =
"user.expirationTime";
/**
- * @see DefaultSyncConfig.User#getAutoMembership()
+ * @see DefaultSyncConfigImpl.User#getAutoMembership()
*/
public static final String[] PARAM_USER_AUTO_MEMBERSHIP_DEFAULT = {};
/**
- * @see DefaultSyncConfig.User#getAutoMembership()
+ * @see DefaultSyncConfigImpl.User#getAutoMembership()
*/
@Property(
label = "User auto membership",
@@ -89,12 +87,12 @@ public class DefaultSyncConfig {
public static final String PARAM_USER_AUTO_MEMBERSHIP =
"user.autoMembership";
/**
- * @see DefaultSyncConfig.User#getPropertyMapping()
+ * @see DefaultSyncConfigImpl.User#getPropertyMapping()
*/
public static final String[] PARAM_USER_PROPERTY_MAPPING_DEFAULT =
{"rep:fullname=cn"};
/**
- * @see DefaultSyncConfig.User#getPropertyMapping()
+ * @see DefaultSyncConfigImpl.User#getPropertyMapping()
*/
@Property(
label = "User property mapping",
@@ -106,12 +104,12 @@ public class DefaultSyncConfig {
public static final String PARAM_USER_PROPERTY_MAPPING =
"user.propertyMapping";
/**
- * @see DefaultSyncConfig.User#getPathPrefix()
+ * @see DefaultSyncConfigImpl.User#getPathPrefix()
*/
public static final String PARAM_USER_PATH_PREFIX_DEFAULT = "";
/**
- * @see DefaultSyncConfig.User#getPathPrefix()
+ * @see DefaultSyncConfigImpl.User#getPathPrefix()
*/
@Property(
label = "User Path Prefix",
@@ -121,12 +119,12 @@ public class DefaultSyncConfig {
public static final String PARAM_USER_PATH_PREFIX = "user.pathPrefix";
/**
- * @see DefaultSyncConfig.User#getMembershipExpirationTime()
+ * @see DefaultSyncConfigImpl.User#getMembershipExpirationTime()
*/
public static final String PARAM_USER_MEMBERSHIP_EXPIRATION_TIME_DEFAULT =
"1h";
/**
- * @see DefaultSyncConfig.User#getMembershipExpirationTime()
+ * @see DefaultSyncConfigImpl.User#getMembershipExpirationTime()
*/
@Property(
label = "User Membership Expiration",
@@ -154,12 +152,12 @@ public class DefaultSyncConfig {
public static final String PARAM_USER_MEMBERSHIP_NESTING_DEPTH =
"user.membershipNestingDepth";
/**
- * @see DefaultSyncConfig.Group#getExpirationTime()
+ * @see DefaultSyncConfigImpl.Group#getExpirationTime()
*/
public static final String PARAM_GROUP_EXPIRATION_TIME_DEFAULT = "1d";
/**
- * @see DefaultSyncConfig.Group#getExpirationTime()
+ * @see DefaultSyncConfigImpl.Group#getExpirationTime()
*/
@Property(
label = "Group Expiration Time",
@@ -169,12 +167,12 @@ public class DefaultSyncConfig {
public static final String PARAM_GROUP_EXPIRATION_TIME =
"group.expirationTime";
/**
- * @see DefaultSyncConfig.Group#getAutoMembership()
+ * @see DefaultSyncConfigImpl.Group#getAutoMembership()
*/
public static final String[] PARAM_GROUP_AUTO_MEMBERSHIP_DEFAULT = {};
/**
- * @see DefaultSyncConfig.Group#getAutoMembership()
+ * @see DefaultSyncConfigImpl.Group#getAutoMembership()
*/
@Property(
label = "Group auto membership",
@@ -185,12 +183,12 @@ public class DefaultSyncConfig {
public static final String PARAM_GROUP_AUTO_MEMBERSHIP =
"group.autoMembership";
/**
- * @see DefaultSyncConfig.Group#getPropertyMapping()
+ * @see DefaultSyncConfigImpl.Group#getPropertyMapping()
*/
public static final String[] PARAM_GROUP_PROPERTY_MAPPING_DEFAULT = {};
/**
- * @see DefaultSyncConfig.Group#getPropertyMapping()
+ * @see DefaultSyncConfigImpl.Group#getPropertyMapping()
*/
@Property(
label = "Group property mapping",
@@ -201,12 +199,12 @@ public class DefaultSyncConfig {
public static final String PARAM_GROUP_PROPERTY_MAPPING =
"group.propertyMapping";
/**
- * @see DefaultSyncConfig.Group#getPathPrefix()
+ * @see DefaultSyncConfigImpl.Group#getPathPrefix()
*/
public static final String PARAM_GROUP_PATH_PREFIX_DEFAULT = "";
/**
- * @see DefaultSyncConfig.Group#getPathPrefix()
+ * @see DefaultSyncConfigImpl.Group#getPathPrefix()
*/
@Property(
label = "Group Path Prefix",
@@ -220,196 +218,12 @@ public class DefaultSyncConfig {
private static final ConfigurationParameters.Milliseconds ONE_DAY =
ConfigurationParameters.Milliseconds.of(24 * MILLIS_PER_HOUR);
/**
- * 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 == null ? Collections.<String>emptySet() :
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>();
- for (String groupName: autoMembership) {
- if (!groupName.trim().isEmpty()) {
- this.autoMembership.add(groupName.trim());
- }
- }
- 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 == null ? Collections.<String,
String>emptyMap() : 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 == null ? "" : pathPrefix;
- }
-
- /**
- * Sets the path prefix.
- * @param pathPrefix the path prefix.
- * @return {@code this}
- * @see #getPathPrefix()
- */
- @Nonnull
- public Authorizable setPathPrefix(String pathPrefix) {
- this.pathPrefix = 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()
+ DefaultSyncConfig cfg = new DefaultSyncConfigImpl()
.setName(params.getConfigValue(PARAM_NAME,
PARAM_NAME_DEFAULT));
cfg.user()
@@ -455,48 +269,4 @@ public class DefaultSyncConfig {
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.
- */
- @Nonnull
- public User user() {
- return user;
- }
-
- /**
- * Returns the sync configuration for groups.
- * @return the group sync configuration.
- */
- @Nonnull
- public Group group() {
- return group;
- }
-
}
\ No newline at end of file