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 an...@apache.org on 2016/08/04 14:03:31 UTC
svn commit: r1755191 - in /jackrabbit/oak/trunk:
oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/
oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/pr...
Author: angela
Date: Thu Aug 4 14:03:31 2016
New Revision: 1755191
URL: http://svn.apache.org/viewvc?rev=1755191&view=rev
Log:
OAK-4301 : Missing protection for system-maintained rep:externalId
Added:
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ValidatorNoProtectionTest.java
- copied, changed from r1754940, jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityValidatorTest.java
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ValidatorNotDynamicTest.java
Modified:
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalIdentityConstants.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityRepositoryInitializer.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityValidatorProvider.java
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfiguration.java
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/RepExternalIdTest.java
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityImporterTest.java
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityRepositoryInitializerTest.java
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityValidatorTest.java
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfigurationTest.java
jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/external/defaultusersync.md
Modified: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalIdentityConstants.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/ExternalIdentityConstants.java?rev=1755191&r1=1755190&r2=1755191&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalIdentityConstants.java (original)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalIdentityConstants.java Thu Aug 4 14:03:31 2016
@@ -67,4 +67,15 @@ public interface ExternalIdentityConstan
*/
Set<String> RESERVED_PROPERTY_NAMES = ImmutableSet.of(REP_EXTERNAL_ID, REP_EXTERNAL_PRINCIPAL_NAMES);
+ /**
+ * Configuration parameter to enable special protection of external IDs
+ *
+ * @see <a href="https://issues.apache.org/jira/browse/OAK-4301">OAK-4301</a>
+ */
+ String PARAM_PROTECT_EXTERNAL_IDS = "protectExternalId";
+
+ /**
+ * Default value for {@link #PARAM_PROTECT_EXTERNAL_IDS}.
+ */
+ boolean DEFAULT_PROTECT_EXTERNAL_IDS = true;
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityRepositoryInitializer.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/principal/ExternalIdentityRepositoryInitializer.java?rev=1755191&r1=1755190&r2=1755191&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityRepositoryInitializer.java (original)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityRepositoryInitializer.java Thu Aug 4 14:03:31 2016
@@ -60,7 +60,10 @@ class ExternalIdentityRepositoryInitiali
private static final Logger log = LoggerFactory.getLogger(ExternalIdentityRepositoryInitializer.class);
- ExternalIdentityRepositoryInitializer() {
+ private final boolean enforceUniqueIds;
+
+ ExternalIdentityRepositoryInitializer(boolean enforceUniqueIds) {
+ this.enforceUniqueIds = enforceUniqueIds;
}
@Override
@@ -79,6 +82,12 @@ class ExternalIdentityRepositoryInitiali
NodeUtil rootTree = checkNotNull(new NodeUtil(root.getTree("/")));
NodeUtil index = rootTree.getOrAddChild(IndexConstants.INDEX_DEFINITIONS_NAME, JcrConstants.NT_UNSTRUCTURED);
+ if (enforceUniqueIds && !index.hasChild("externalId")) {
+ NodeUtil definition = IndexUtils.createIndexDefinition(index, "externalId", true,
+ new String[]{ExternalIdentityConstants.REP_EXTERNAL_ID}, null);
+ definition.setString("info", "Oak index assuring uniqueness of rep:externalId properties.");
+ }
+
if (!index.hasChild("externalPrincipalNames")) {
NodeUtil definition = IndexUtils.createIndexDefinition(index, "externalPrincipalNames", false,
new String[]{ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES}, null);
Modified: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityValidatorProvider.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/principal/ExternalIdentityValidatorProvider.java?rev=1755191&r1=1755190&r2=1755191&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityValidatorProvider.java (original)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityValidatorProvider.java Thu Aug 4 14:03:31 2016
@@ -17,9 +17,11 @@
package org.apache.jackrabbit.oak.spi.security.authentication.external.impl.principal;
import java.security.Principal;
+import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
+import com.google.common.collect.ImmutableMap;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Type;
@@ -40,35 +42,60 @@ import org.apache.jackrabbit.oak.spi.sta
*/
class ExternalIdentityValidatorProvider extends ValidatorProvider implements ExternalIdentityConstants {
+ private static final Map<Integer, String> ERROR_MSGS = ImmutableMap.<Integer, String>builder()
+ .put(70, "Attempt to create, modify or remove the system property 'rep:externalPrincipalNames'")
+ .put(71, "Property 'rep:externalPrincipalNames' must be multi-valued of type STRING.")
+ .put(72, "Property 'rep:externalPrincipalNames' requires 'rep:externalId' to be present on the Node.")
+ .put(73, "Property 'rep:externalId' cannot be removed as long as 'rep:externalPrincipalNames' is present.")
+ .put(74, "Attempt to add, modify or remove the system maintained property 'rep:externalId'.")
+ .put(75, "Property 'rep:externalId' may only have a single value of type STRING.").build();
+
private final boolean isSystem;
+ private final boolean protectedExternalIds;
- ExternalIdentityValidatorProvider(@Nonnull Set<Principal> principals) {
+ ExternalIdentityValidatorProvider(@Nonnull Set<Principal> principals, boolean protectExternalIds) {
isSystem = principals.contains(SystemPrincipal.INSTANCE);
+ this.protectedExternalIds = protectExternalIds;
}
- private void checkAddModifyProperties(@Nonnull NodeState parent, @Nonnull String name, @Nonnull PropertyState propertyState) throws CommitFailedException {
- if (REP_EXTERNAL_PRINCIPAL_NAMES.equals(name)) {
- if (!isSystem) {
- throw new CommitFailedException(CommitFailedException.CONSTRAINT, 70, "Attempt to create, modify or remove the system property " + name);
- }
+ private void checkAddModifyProperties(@Nonnull NodeState parent, @Nonnull String name, @Nonnull PropertyState propertyState, boolean isModify) throws CommitFailedException {
+ if (RESERVED_PROPERTY_NAMES.contains(name)) {
Type<?> type = propertyState.getType();
- if (!Type.STRINGS.equals(type) || !propertyState.isArray()) {
- throw new CommitFailedException(CommitFailedException.CONSTRAINT, 71, "Property rep:externalPrincipalNames must be multi-valued of type STRING.");
+ if (REP_EXTERNAL_PRINCIPAL_NAMES.equals(name)) {
+ if (!isSystem) {
+ throw new CommitFailedException(CommitFailedException.CONSTRAINT, 70, ERROR_MSGS.get(70));
+ }
+ if (!Type.STRINGS.equals(type) || !propertyState.isArray()) {
+ throw new CommitFailedException(CommitFailedException.CONSTRAINT, 71, ERROR_MSGS.get(71));
+ }
+ if (!parent.hasProperty(REP_EXTERNAL_ID)) {
+ throw new CommitFailedException(CommitFailedException.CONSTRAINT, 72, ERROR_MSGS.get(72));
+ }
}
- if (!parent.hasProperty(REP_EXTERNAL_ID)) {
- throw new CommitFailedException(CommitFailedException.CONSTRAINT, 72, "Property rep:externalPrincipalNames requires rep:externalId to be present on the Node.");
+ if (REP_EXTERNAL_ID.equals(name) && protectedExternalIds) {
+ if (isModify && !isSystem) {
+ throw new CommitFailedException(CommitFailedException.CONSTRAINT, 74, ERROR_MSGS.get(74));
+ }
+ if (!Type.STRING.equals(type) || propertyState.isArray()) {
+ throw new CommitFailedException(CommitFailedException.CONSTRAINT, 75, ERROR_MSGS.get(75));
+ }
}
}
}
private void checkRemoveProperties(@Nonnull NodeState parent, @Nonnull String name) throws CommitFailedException {
if (RESERVED_PROPERTY_NAMES.contains(name)) {
- if (REP_EXTERNAL_ID.equals(name) && parent.hasProperty(REP_EXTERNAL_PRINCIPAL_NAMES)) {
- throw new CommitFailedException(CommitFailedException.CONSTRAINT, 73, "Property rep:externalId cannot be removed as long as rep:externalPrincipalNames is present.");
+ if (REP_EXTERNAL_ID.equals(name)) {
+ if (parent.hasProperty(REP_EXTERNAL_PRINCIPAL_NAMES)) {
+ throw new CommitFailedException(CommitFailedException.CONSTRAINT, 73, ERROR_MSGS.get(73));
+ }
+ if (protectedExternalIds && !isSystem) {
+ throw new CommitFailedException(CommitFailedException.CONSTRAINT, 74, ERROR_MSGS.get(74));
+ }
}
if (REP_EXTERNAL_PRINCIPAL_NAMES.equals(name) && !isSystem) {
- throw new CommitFailedException(CommitFailedException.CONSTRAINT, 70, "Attempt to create, modify or remove the system property " + name);
+ throw new CommitFailedException(CommitFailedException.CONSTRAINT, 70, ERROR_MSGS.get(70));
}
}
}
@@ -76,25 +103,27 @@ class ExternalIdentityValidatorProvider
@Override
protected Validator getRootValidator(@Nonnull NodeState before, @Nonnull NodeState after,
@Nonnull CommitInfo info) {
- return new ExternalIdentityValidator(after);
+ return new ExternalIdentityValidator(after, true);
}
private final class ExternalIdentityValidator extends DefaultValidator {
private final NodeState parent;
+ private final boolean modifiedParent;
- private ExternalIdentityValidator(@Nonnull NodeState parent) {
+ private ExternalIdentityValidator(@Nonnull NodeState parent, boolean modifiedParent) {
this.parent = parent;
+ this.modifiedParent = modifiedParent;
}
@Override
public void propertyAdded(PropertyState after) throws CommitFailedException {
- checkAddModifyProperties(parent, after.getName(), after);
+ checkAddModifyProperties(parent, after.getName(), after, modifiedParent);
}
@Override
public void propertyChanged(PropertyState before, PropertyState after) throws CommitFailedException {
- checkAddModifyProperties(parent, before.getName(), after);
+ checkAddModifyProperties(parent, before.getName(), after, modifiedParent);
}
@Override
@@ -103,17 +132,17 @@ class ExternalIdentityValidatorProvider
}
@Override
- public Validator childNodeAdded(String name, NodeState after) throws CommitFailedException {
- return new ExternalIdentityValidator(after);
+ public Validator childNodeAdded(String name, NodeState after) {
+ return new ExternalIdentityValidator(after, false);
}
@Override
- public Validator childNodeChanged(String name, NodeState before, NodeState after) throws CommitFailedException {
- return new ExternalIdentityValidator(after);
+ public Validator childNodeChanged(String name, NodeState before, NodeState after) {
+ return new ExternalIdentityValidator(after, true);
}
@Override
- public Validator childNodeDeleted(String name, NodeState before) throws CommitFailedException {
+ public Validator childNodeDeleted(String name, NodeState before) {
// removal of the parent node containing a reserved property must be possible
return null;
}
Modified: jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfiguration.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/principal/ExternalPrincipalConfiguration.java?rev=1755191&r1=1755190&r2=1755191&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfiguration.java (original)
+++ jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfiguration.java Thu Aug 4 14:03:31 2016
@@ -34,6 +34,8 @@ import com.google.common.collect.Iterabl
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.Properties;
+import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.jackrabbit.api.security.principal.PrincipalManager;
import org.apache.jackrabbit.oak.api.Root;
@@ -48,6 +50,7 @@ import org.apache.jackrabbit.oak.spi.sec
import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
import org.apache.jackrabbit.oak.spi.security.authentication.external.SyncHandler;
import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.DefaultSyncConfigImpl;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalIdentityConstants;
import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalLoginModuleFactory;
import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.SyncHandlerMapping;
import org.apache.jackrabbit.oak.spi.security.principal.EmptyPrincipalProvider;
@@ -78,6 +81,12 @@ import org.slf4j.LoggerFactory;
immediate = true
)
@Service({PrincipalConfiguration.class, SecurityConfiguration.class})
+@Properties({
+ @Property(name = ExternalIdentityConstants.PARAM_PROTECT_EXTERNAL_IDS,
+ label = "External Identity Protection",
+ description = "If disabled rep:externalId properties won't be properly protected (backwards compatible behavior). NOTE: for security reasons it is strongly recommend to keep the protection enabled!",
+ boolValue = ExternalIdentityConstants.DEFAULT_PROTECT_EXTERNAL_IDS)
+})
public class ExternalPrincipalConfiguration extends ConfigurationBase implements PrincipalConfiguration {
private static final Logger log = LoggerFactory.getLogger(ExternalPrincipalConfiguration.class);
@@ -122,13 +131,13 @@ public class ExternalPrincipalConfigurat
@Nonnull
@Override
public RepositoryInitializer getRepositoryInitializer() {
- return new ExternalIdentityRepositoryInitializer();
+ return new ExternalIdentityRepositoryInitializer(protectedExternalIds());
}
@Nonnull
@Override
public List<? extends ValidatorProvider> getValidators(@Nonnull String workspaceName, @Nonnull Set<Principal> principals, @Nonnull MoveTracker moveTracker) {
- return ImmutableList.of(new ExternalIdentityValidatorProvider(principals));
+ return ImmutableList.of(new ExternalIdentityValidatorProvider(principals, protectedExternalIds()));
}
@Nonnull
@@ -168,6 +177,10 @@ public class ExternalPrincipalConfigurat
return syncConfigTracker != null && syncConfigTracker.isEnabled;
}
+ private boolean protectedExternalIds() {
+ return getParameters().getConfigValue(ExternalIdentityConstants.PARAM_PROTECT_EXTERNAL_IDS, ExternalIdentityConstants.DEFAULT_PROTECT_EXTERNAL_IDS);
+ }
+
/**
* {@code ServiceTracker} to detect any {@link SyncHandler} that has
* dynamic membership enabled.
Modified: jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/RepExternalIdTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/RepExternalIdTest.java?rev=1755191&r1=1755190&r2=1755191&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/RepExternalIdTest.java (original)
+++ jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/RepExternalIdTest.java Thu Aug 4 14:03:31 2016
@@ -19,7 +19,10 @@ package org.apache.jackrabbit.oak.spi.se
import javax.annotation.Nonnull;
import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.spi.security.authentication.external.AbstractExternalAuthTest;
@@ -34,16 +37,21 @@ import static org.junit.Assert.assertFal
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
public class RepExternalIdTest extends AbstractExternalAuthTest {
+ private Root r;
+ private UserManager userManager;
private DefaultSyncContext syncCtx;
@Before
public void before() throws Exception {
super.before();
- syncCtx = new DefaultSyncContext(syncConfig, idp, getUserManager(root), getValueFactory());
+ r = getSystemRoot();
+ userManager = getUserManager(r);
+ syncCtx = new DefaultSyncContext(syncConfig, idp, getUserManager(r), getValueFactory(r));
}
@Override
@@ -61,10 +69,10 @@ public class RepExternalIdTest extends A
assertNotNull(si);
- Authorizable authorizable = getUserManager(root).getAuthorizable(si.getId());
+ Authorizable authorizable = userManager.getAuthorizable(si.getId());
assertNotNull(authorizable);
- Tree userTree = root.getTree(authorizable.getPath());
+ Tree userTree = r.getTree(authorizable.getPath());
assertTrue(userTree.hasProperty(DefaultSyncContext.REP_EXTERNAL_ID));
PropertyState ps = userTree.getProperty(DefaultSyncContext.REP_EXTERNAL_ID);
@@ -87,4 +95,59 @@ public class RepExternalIdTest extends A
assertRepExternalId(res);
}
+
+ @Test
+ public void testUniqueConstraint() throws Exception {
+ SyncResult res = syncCtx.sync(idp.getUser(USER_ID));
+
+ try {
+ Tree t = r.getTree(getTestUser().getPath());
+ t.setProperty(DefaultSyncContext.REP_EXTERNAL_ID, res.getIdentity().getExternalIdRef().getString());
+ r.commit();
+ fail("Duplicate value for rep:externalId must be detected in the default setup.");
+ } catch (CommitFailedException e) {
+ // success: verify nature of the exception
+ assertTrue(e.isConstraintViolation());
+ assertEquals(30, e.getCode());
+ } finally {
+ r.refresh();
+ }
+ }
+
+ @Test
+ public void testUniqueConstraintSubsequentCommit() throws Exception {
+ SyncResult res = syncCtx.sync(idp.getUser(USER_ID));
+ r.commit();
+
+ try {
+ Tree t = r.getTree(getTestUser().getPath());
+ t.setProperty(DefaultSyncContext.REP_EXTERNAL_ID, res.getIdentity().getExternalIdRef().getString());
+ r.commit();
+ fail("Duplicate value for rep:externalId must be detected in the default setup.");
+ } catch (CommitFailedException e) {
+ // success: verify nature of the exception
+ assertTrue(e.isConstraintViolation());
+ assertEquals(30, e.getCode());
+ } finally {
+ r.refresh();
+ }
+ }
+
+ @Test
+ public void testUniqueConstraintNonUserNode() throws Exception {
+ try {
+ SyncResult res = syncCtx.sync(idp.getUser(USER_ID));
+ Tree nonUserTree = r.getTree("/");
+ nonUserTree.setProperty(DefaultSyncContext.REP_EXTERNAL_ID, res.getIdentity().getExternalIdRef().getString());
+ r.commit();
+
+ fail("Duplicate value for rep:externalId must be detected in the default setup.");
+ } catch (CommitFailedException e) {
+ // success: verify nature of the exception
+ assertTrue(e.isConstraintViolation());
+ assertEquals(30, e.getCode());
+ } finally {
+ r.refresh();
+ }
+ }
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java?rev=1755191&r1=1755190&r2=1755191&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java (original)
+++ jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandlerTest.java Thu Aug 4 14:03:31 2016
@@ -26,6 +26,7 @@ import javax.jcr.Value;
import com.google.common.collect.Sets;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentity;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityRef;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalLoginModuleTestBase;
@@ -145,10 +146,12 @@ public class DefaultSyncHandlerTest exte
public void testFindIdentityWithRemovedExternalId() throws Exception {
sync(USER_ID, false);
- // NOTE: this is only possible as long the rep:externalId property is not protected
+ // NOTE: use system-root to remove the protected rep:externalId property (since Oak 1.5.8)
Authorizable authorizable = userManager.getAuthorizable(USER_ID);
- authorizable.removeProperty(DefaultSyncContext.REP_EXTERNAL_ID);
- root.commit();
+ Root systemRoot = getSystemRoot();
+ systemRoot.getTree(authorizable.getPath()).removeProperty(DefaultSyncContext.REP_EXTERNAL_ID);
+ systemRoot.commit();
+ root.refresh();
SyncedIdentity si = syncHandler.findIdentity(userManager, USER_ID);
assertNotNull(si);
Modified: jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityImporterTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityImporterTest.java?rev=1755191&r1=1755190&r2=1755191&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityImporterTest.java (original)
+++ jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityImporterTest.java Thu Aug 4 14:03:31 2016
@@ -50,6 +50,16 @@ import static org.junit.Assert.assertTru
*/
public class ExternalIdentityImporterTest {
+ public static final String XML_EXTERNAL_USER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
+ "<sv:node sv:name=\"t\" xmlns:mix=\"http://www.jcp.org/jcr/mix/1.0\" xmlns:nt=\"http://www.jcp.org/jcr/nt/1.0\" xmlns:fn_old=\"http://www.w3.org/2004/10/xpath-functions\" xmlns:fn=\"http://www.w3.org/2005/xpath-functions\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:sv=\"http://www.jcp.org/jcr/sv/1.0\" xmlns:rep=\"internal\" xmlns:jcr=\"http://www.jcp.org/jcr/1.0\">" +
+ " <sv:property sv:name=\"jcr:primaryType\" sv:type=\"Name\"><sv:value>rep:User</sv:value></sv:property>" +
+ " <sv:property sv:name=\"jcr:uuid\" sv:type=\"String\"><sv:value>e358efa4-89f5-3062-b10d-d7316b65649e</sv:value></sv:property>" +
+ " <sv:property sv:name=\"rep:authorizableId\" sv:type=\"String\"><sv:value>t</sv:value></sv:property>" +
+ " <sv:property sv:name=\"rep:principalName\" sv:type=\"String\"><sv:value>tPrinc</sv:value></sv:property>" +
+ " <sv:property sv:name=\"rep:externalId\" sv:type=\"String\"><sv:value>idp;ext-t</sv:value></sv:property>" +
+ " <sv:property sv:name=\"rep:lastSynced\" sv:type=\"Date\"><sv:value>2016-05-03T10:03:08.061+02:00</sv:value></sv:property>" +
+ "</sv:node>";
+
public static final String XML_EXTERNAL_USER_WITH_PRINCIPAL_NAMES = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<sv:node sv:name=\"t\" xmlns:mix=\"http://www.jcp.org/jcr/mix/1.0\" xmlns:nt=\"http://www.jcp.org/jcr/nt/1.0\" xmlns:fn_old=\"http://www.w3.org/2004/10/xpath-functions\" xmlns:fn=\"http://www.w3.org/2005/xpath-functions\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:sv=\"http://www.jcp.org/jcr/sv/1.0\" xmlns:rep=\"internal\" xmlns:jcr=\"http://www.jcp.org/jcr/1.0\">" +
" <sv:property sv:name=\"jcr:primaryType\" sv:type=\"Name\"><sv:value>rep:User</sv:value></sv:property>" +
@@ -133,6 +143,20 @@ public class ExternalIdentityImporterTes
}
@Test
+ public void importExternalUser() throws Exception {
+ Node parent = doImport(createSession(false), UserConstants.DEFAULT_USER_PATH, XML_EXTERNAL_USER);
+ assertHasProperties(parent.getNode("t"), ExternalIdentityConstants.REP_EXTERNAL_ID, ExternalIdentityConstants.REP_LAST_SYNCED);
+ assertNotHasProperties(parent.getNode("t"), ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES);
+ }
+
+ @Test
+ public void importExternalUserAsSystem() throws Exception {
+ Node parent = doImport(createSession(true), UserConstants.DEFAULT_USER_PATH, XML_EXTERNAL_USER);
+ assertHasProperties(parent.getNode("t"), ExternalIdentityConstants.REP_EXTERNAL_ID, ExternalIdentityConstants.REP_LAST_SYNCED);
+ assertNotHasProperties(parent.getNode("t"), ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES);
+ }
+
+ @Test
public void importExternalUserWithPrincipalNames() throws Exception {
Node parent = doImport(createSession(false), UserConstants.DEFAULT_USER_PATH, XML_EXTERNAL_USER_WITH_PRINCIPAL_NAMES);
assertHasProperties(parent.getNode("t"), ExternalIdentityConstants.REP_EXTERNAL_ID);
Modified: jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityRepositoryInitializerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityRepositoryInitializerTest.java?rev=1755191&r1=1755190&r2=1755191&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityRepositoryInitializerTest.java (original)
+++ jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityRepositoryInitializerTest.java Thu Aug 4 14:03:31 2016
@@ -32,7 +32,16 @@ import static org.junit.Assert.assertTru
public class ExternalIdentityRepositoryInitializerTest extends AbstractExternalAuthTest {
@Test
- public void testIndexDefinitions() throws Exception {
+ public void testExternalIdIndexDefinition() throws Exception {
+ Tree oakIndex = root.getTree('/' + IndexConstants.INDEX_DEFINITIONS_NAME);
+ assertTrue(oakIndex.exists());
+
+ Tree externalIdIndex = oakIndex.getChild("externalId");
+ assertIndexDefinition(externalIdIndex, ExternalIdentityConstants.REP_EXTERNAL_ID, true);
+ }
+
+ @Test
+ public void testPrincipalNamesIndexDefinition() throws Exception {
Tree oakIndex = root.getTree('/' + IndexConstants.INDEX_DEFINITIONS_NAME);
assertTrue(oakIndex.exists());
Modified: jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityValidatorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityValidatorTest.java?rev=1755191&r1=1755190&r2=1755191&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityValidatorTest.java (original)
+++ jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityValidatorTest.java Thu Aug 4 14:03:31 2016
@@ -22,11 +22,13 @@ import com.google.common.collect.Immutab
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalLoginModuleTestBase;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.TestIdentityProvider;
import org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncConfig;
import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalIdentityConstants;
import org.apache.jackrabbit.oak.util.NodeUtil;
@@ -54,32 +56,19 @@ public class ExternalIdentityValidatorTe
Authorizable a = getUserManager(root).getAuthorizable(USER_ID);
assertNotNull(a);
- assertTrue(a.hasProperty(ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES));
+ assertEquals(isDynamic(), a.hasProperty(ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES));
externalUserPath = a.getPath();
}
@Override
protected DefaultSyncConfig createSyncConfig() {
DefaultSyncConfig config = super.createSyncConfig();
- config.user().setDynamicMembership(true);
+ config.user().setDynamicMembership(isDynamic());
return config;
}
- @Test
- public void testRemoveRepExternalIdAsSystem() throws Exception {
- Root systemRoot = getSystemRoot();
- try {
- NodeUtil n = new NodeUtil(systemRoot.getTree(externalUserPath));
-
- n.removeProperty(ExternalIdentityConstants.REP_EXTERNAL_ID);
- systemRoot.commit();
- fail("Removing rep:externalId is not allowed if rep:externalPrincipalNames is present.");
- } catch (CommitFailedException e) {
- // success
- assertEquals(73, e.getCode());
- } finally {
- systemRoot.refresh();
- }
+ protected boolean isDynamic() {
+ return true;
}
@Test
@@ -213,4 +202,174 @@ public class ExternalIdentityValidatorTe
systemRoot.refresh();
}
}
+
+ @Test
+ public void testRepExternalIdMultiple() throws Exception {
+ Root systemRoot = getSystemRoot();
+ try {
+ NodeUtil n = new NodeUtil(systemRoot.getTree(testUserPath));
+ n.setStrings(ExternalIdentityConstants.REP_EXTERNAL_ID, "id", "id2");
+ systemRoot.commit();
+ fail("Creating rep:externalId as multiple STRING property must be detected.");
+ } catch (CommitFailedException e) {
+ // success
+ assertEquals(75, e.getCode());
+ } finally {
+ systemRoot.refresh();
+ }
+ }
+
+ @Test
+ public void testRepExternalIdType() throws Exception {
+ Root systemRoot = getSystemRoot();
+ Tree userTree = systemRoot.getTree(testUserPath);
+
+ java.util.Map<Type, Object> valMap = ImmutableMap.<Type, Object>of(
+ Type.BOOLEAN, Boolean.TRUE,
+ Type.LONG, new Long(1234),
+ Type.NAME, "id"
+ );
+ for (Type t : valMap.keySet()) {
+ Object val = valMap.get(t);
+ try {
+ userTree.setProperty(ExternalIdentityConstants.REP_EXTERNAL_ID, val, t);
+ systemRoot.commit();
+ fail("Creating rep:externalId with type "+t+" must be detected.");
+ } catch (CommitFailedException e) {
+ // success
+ assertEquals(75, e.getCode());
+ } finally {
+ systemRoot.refresh();
+ }
+ }
+ }
+
+ @Test
+ public void testCreateUserWithRepExternalId() throws Exception {
+ User u = getUserManager(root).createUser(TestIdentityProvider.ID_SECOND_USER, null);
+ root.getTree(u.getPath()).setProperty(ExternalIdentityConstants.REP_EXTERNAL_ID, TestIdentityProvider.ID_SECOND_USER);
+ root.commit();
+ }
+
+ @Test
+ public void testCreateUserWithRepExternalIdAsSystem() throws Exception {
+ Root systemRoot = getSystemRoot();
+ User u = getUserManager(systemRoot).createUser(TestIdentityProvider.ID_SECOND_USER, null);
+ systemRoot.getTree(u.getPath()).setProperty(ExternalIdentityConstants.REP_EXTERNAL_ID, TestIdentityProvider.ID_SECOND_USER);
+ systemRoot.commit();
+ }
+
+ @Test
+ public void testAddRepExternalId() throws Exception {
+ try {
+ root.getTree(testUserPath).setProperty(ExternalIdentityConstants.REP_EXTERNAL_ID, "id");
+ root.commit();
+ fail("Adding rep:externalId must be detected in the default setup.");
+ } catch (CommitFailedException e) {
+ // success: verify nature of the exception
+ assertTrue(e.isConstraintViolation());
+ assertEquals(74, e.getCode());
+ }
+
+ }
+
+ @Test
+ public void testAddRepExternalIdAsSystem() throws Exception {
+ Root systemRoot = getSystemRoot();
+ systemRoot.getTree(testUserPath).setProperty(ExternalIdentityConstants.REP_EXTERNAL_ID, "id");
+ systemRoot.commit();
+ }
+
+ @Test
+ public void testModifyRepExternalId() throws Exception {
+ try {
+ root.getTree(externalUserPath).setProperty(ExternalIdentityConstants.REP_EXTERNAL_ID, "anotherValue");
+ root.commit();
+
+ fail("Modification of rep:externalId must be detected in the default setup.");
+ } catch (CommitFailedException e) {
+ // success: verify nature of the exception
+ assertTrue(e.isConstraintViolation());
+ assertEquals(74, e.getCode());
+ }
+ }
+
+ @Test
+ public void testModifyRepExternalIdAsSystem() throws Exception {
+ Root systemRoot = getSystemRoot();
+ systemRoot.getTree(externalUserPath).setProperty(ExternalIdentityConstants.REP_EXTERNAL_ID, "anotherValue");
+ systemRoot.commit();
+ }
+
+ @Test
+ public void testRemoveRepExternalId() throws Exception {
+ try {
+ root.getTree(externalUserPath).removeProperty(ExternalIdentityConstants.REP_EXTERNAL_ID);
+ root.commit();
+
+ fail("Removal of rep:externalId must be detected in the default setup.");
+ } catch (CommitFailedException e) {
+ // success: verify nature of the exception
+ assertTrue(e.isConstraintViolation());
+ assertEquals(73, e.getCode());
+ }
+ }
+
+ @Test
+ public void testRemoveRepExternalIdAsSystem() throws Exception {
+ Root systemRoot = getSystemRoot();
+ try {
+ NodeUtil n = new NodeUtil(systemRoot.getTree(externalUserPath));
+
+ n.removeProperty(ExternalIdentityConstants.REP_EXTERNAL_ID);
+ systemRoot.commit();
+ fail("Removing rep:externalId is not allowed if rep:externalPrincipalNames is present.");
+ } catch (CommitFailedException e) {
+ // success
+ assertEquals(73, e.getCode());
+ } finally {
+ systemRoot.refresh();
+ }
+ }
+
+ @Test
+ public void testRemoveRepExternalIdWithoutPrincipalNames() throws Exception {
+ Root systemRoot = getSystemRoot();
+ systemRoot.getTree(testUserPath).setProperty(ExternalIdentityConstants.REP_EXTERNAL_ID, "id");
+ systemRoot.commit();
+ root.refresh();
+
+ try {
+ root.getTree(testUserPath).removeProperty(ExternalIdentityConstants.REP_EXTERNAL_ID);
+ root.commit();
+
+ fail("Removal of rep:externalId must be detected in the default setup.");
+ } catch (CommitFailedException e) {
+ // success: verify nature of the exception
+ assertTrue(e.isConstraintViolation());
+ assertEquals(74, e.getCode());
+ }
+ }
+
+ @Test
+ public void testRemoveRepExternalIdWithoutPrincipalNamesAsSystem() throws Exception {
+ Root systemRoot = getSystemRoot();
+ systemRoot.getTree(testUserPath).setProperty(ExternalIdentityConstants.REP_EXTERNAL_ID, "id");
+ systemRoot.commit();
+
+ systemRoot.getTree(testUserPath).removeProperty(ExternalIdentityConstants.REP_EXTERNAL_ID);
+ systemRoot.commit();
+ }
+
+ @Test
+ public void testRemoveExternalUser() throws Exception {
+ getUserManager(root).getAuthorizable(USER_ID).remove();
+ root.commit();
+ }
+
+ @Test
+ public void testRemoveExternalUserTree() throws Exception {
+ root.getTree(externalUserPath).remove();
+ root.commit();
+ }
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfigurationTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfigurationTest.java?rev=1755191&r1=1755190&r2=1755191&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfigurationTest.java (original)
+++ jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfigurationTest.java Thu Aug 4 14:03:31 2016
@@ -34,6 +34,7 @@ import org.apache.jackrabbit.oak.namepat
import org.apache.jackrabbit.oak.spi.commit.MoveTracker;
import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
import org.apache.jackrabbit.oak.spi.lifecycle.WorkspaceInitializer;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
import org.apache.jackrabbit.oak.spi.security.Context;
import org.apache.jackrabbit.oak.spi.security.authentication.external.AbstractExternalAuthTest;
import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalIdentityProvider;
@@ -45,6 +46,7 @@ import org.apache.jackrabbit.oak.spi.sec
import org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncContext;
import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.DefaultSyncConfigImpl;
import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.DefaultSyncHandler;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalIdentityConstants;
import org.apache.jackrabbit.oak.spi.security.principal.PrincipalConfiguration;
import org.apache.jackrabbit.oak.spi.security.principal.PrincipalProvider;
import org.apache.jackrabbit.oak.spi.xml.ProtectedItemImporter;
@@ -157,6 +159,24 @@ public class ExternalPrincipalConfigurat
assertFalse(validatorProviders.isEmpty());
assertEquals(1, validatorProviders.size());
assertTrue(validatorProviders.get(0) instanceof ExternalIdentityValidatorProvider);
+
+ enable();
+
+ validatorProviders = principalConfiguration.getValidators(cs.getWorkspaceName(), cs.getAuthInfo().getPrincipals(), new MoveTracker());
+ assertFalse(validatorProviders.isEmpty());
+ assertEquals(1, validatorProviders.size());
+ assertTrue(validatorProviders.get(0) instanceof ExternalIdentityValidatorProvider);
+ }
+
+ @Test
+ public void testGetValidatorsOmitIdProtection() throws Exception {
+ principalConfiguration.setParameters(ConfigurationParameters.of(ExternalIdentityConstants.PARAM_PROTECT_EXTERNAL_IDS, false));
+ ContentSession cs = root.getContentSession();
+
+ List<? extends ValidatorProvider> validatorProviders = principalConfiguration.getValidators(cs.getWorkspaceName(), cs.getAuthInfo().getPrincipals(), new MoveTracker());
+ assertFalse(validatorProviders.isEmpty());
+ assertEquals(1, validatorProviders.size());
+ assertTrue(validatorProviders.get(0) instanceof ExternalIdentityValidatorProvider);
enable();
Copied: jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ValidatorNoProtectionTest.java (from r1754940, jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityValidatorTest.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ValidatorNoProtectionTest.java?p2=jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ValidatorNoProtectionTest.java&p1=jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityValidatorTest.java&r1=1754940&r2=1755191&rev=1755191&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalIdentityValidatorTest.java (original)
+++ jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ValidatorNoProtectionTest.java Thu Aug 4 14:03:31 2016
@@ -16,201 +16,77 @@
*/
package org.apache.jackrabbit.oak.spi.security.authentication.external.impl.principal;
-import javax.jcr.SimpleCredentials;
+import java.util.Map;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
-import org.apache.jackrabbit.api.security.user.Authorizable;
-import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.Root;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
-import org.apache.jackrabbit.oak.spi.security.authentication.external.ExternalLoginModuleTestBase;
-import org.apache.jackrabbit.oak.spi.security.authentication.external.basic.DefaultSyncConfig;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalIdentityConstants;
import org.apache.jackrabbit.oak.util.NodeUtil;
import org.junit.Test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-public class ExternalIdentityValidatorTest extends ExternalLoginModuleTestBase {
-
- String testUserPath;
- String externalUserPath;
+public class ValidatorNoProtectionTest extends ExternalIdentityValidatorTest {
@Override
public void before() throws Exception {
super.before();
- testUserPath = getTestUser().getPath();
-
- // force an external user to be synchronized into the repo
- login(new SimpleCredentials(USER_ID, new char[0])).close();
- root.refresh();
-
- Authorizable a = getUserManager(root).getAuthorizable(USER_ID);
- assertNotNull(a);
- assertTrue(a.hasProperty(ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES));
- externalUserPath = a.getPath();
+ ConfigurationParameters params = ConfigurationParameters.of(externalPrincipalConfiguration.getParameters(), ConfigurationParameters.of(ExternalIdentityConstants.PARAM_PROTECT_EXTERNAL_IDS, false));
+ externalPrincipalConfiguration.setParameters(params);
}
@Override
- protected DefaultSyncConfig createSyncConfig() {
- DefaultSyncConfig config = super.createSyncConfig();
- config.user().setDynamicMembership(true);
- return config;
- }
-
- @Test
- public void testRemoveRepExternalIdAsSystem() throws Exception {
- Root systemRoot = getSystemRoot();
- try {
- NodeUtil n = new NodeUtil(systemRoot.getTree(externalUserPath));
-
- n.removeProperty(ExternalIdentityConstants.REP_EXTERNAL_ID);
- systemRoot.commit();
- fail("Removing rep:externalId is not allowed if rep:externalPrincipalNames is present.");
- } catch (CommitFailedException e) {
- // success
- assertEquals(73, e.getCode());
- } finally {
- systemRoot.refresh();
- }
- }
-
- @Test
- public void testAddExternalPrincipalNames() throws Exception {
- Tree userTree = root.getTree(testUserPath);
- NodeUtil userNode = new NodeUtil(userTree);
- try {
- userNode.setStrings(ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES, "principalName");
- root.commit();
- fail("Creating rep:externalPrincipalNames must be detected.");
- } catch (CommitFailedException e) {
- // success
- assertEquals(70, e.getCode());
- } finally {
- root.refresh();
- }
- }
-
@Test
- public void testAddExternalPrincipalNamesAsSystemMissingExternalId() throws Exception {
- Root systemRoot = getSystemRoot();
- try {
- NodeUtil n = new NodeUtil(systemRoot.getTree(testUserPath));
- n.setStrings(ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES, "principalName");
- systemRoot.commit();
- fail("Creating rep:externalPrincipalNames without rep:externalId must be detected.");
- } catch (CommitFailedException e) {
- // success
- assertEquals(72, e.getCode());
- } finally {
- systemRoot.refresh();
- }
- }
-
- @Test
- public void testAddExternalPrincipalNamesAsSystem() throws Exception {
+ public void testRepExternalIdMultiple() throws Exception {
Root systemRoot = getSystemRoot();
NodeUtil n = new NodeUtil(systemRoot.getTree(testUserPath));
- n.setString(ExternalIdentityConstants.REP_EXTERNAL_ID, "externalId");
- n.setStrings(ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES, "principalName");
- systemRoot.commit();
- }
-
- @Test
- public void testRemoveExternalPrincipalNames() throws Exception {
- Tree userTree = root.getTree(externalUserPath);
- try {
- userTree.removeProperty(ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES);
- root.commit();
- fail("Removing rep:externalPrincipalNames must be detected.");
- } catch (CommitFailedException e) {
- // success
- assertEquals(70, e.getCode());
- } finally {
- root.refresh();
- }
- }
-
- @Test
- public void testRemoveExternalPrincipalNamesAsSystem() throws Exception {
- Root systemRoot = getSystemRoot();
- NodeUtil n = new NodeUtil(systemRoot.getTree(externalUserPath));
-
- // removal with system root must succeed
- n.removeProperty(ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES);
- systemRoot.commit();
- }
-
- @Test
- public void testModifyExternalPrincipalNames() throws Exception {
- Tree userTree = root.getTree(externalUserPath);
- try {
- userTree.setProperty(ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES, Lists.newArrayList("principalNames"), Type.STRINGS);
- root.commit();
- fail("Changing rep:externalPrincipalNames must be detected.");
- } catch (CommitFailedException e) {
- // success
- assertEquals(70, e.getCode());
- } finally {
- root.refresh();
- }
- }
-
- @Test
- public void testModifyExternalPrincipalNamesAsSystem() throws Exception {
- Root systemRoot = getSystemRoot();
- NodeUtil n = new NodeUtil(systemRoot.getTree(externalUserPath));
-
- // changing with system root must succeed
- n.setStrings(ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES, "principalNames");
+ n.setStrings(ExternalIdentityConstants.REP_EXTERNAL_ID, "id", "id2");
systemRoot.commit();
}
+ @Override
@Test
- public void testExternalPrincipalNamesType() throws Exception {
+ public void testRepExternalIdType() throws Exception {
Root systemRoot = getSystemRoot();
Tree userTree = systemRoot.getTree(testUserPath);
- java.util.Map<Type, Object> valMap = ImmutableMap.<Type, Object>of(
- Type.BOOLEANS, ImmutableSet.of(Boolean.TRUE),
- Type.LONGS, ImmutableSet.of(new Long(1234)),
- Type.NAMES, ImmutableSet.of("id", "id2")
+ Map<Type, Object> valMap = ImmutableMap.<Type, Object>of(
+ Type.BOOLEAN, Boolean.TRUE,
+ Type.LONG, new Long(1234),
+ Type.NAME, "id"
);
for (Type t : valMap.keySet()) {
Object val = valMap.get(t);
try {
- userTree.setProperty(ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES, val, t);
+ userTree.setProperty(ExternalIdentityConstants.REP_EXTERNAL_ID, val, t);
systemRoot.commit();
- fail("Creating rep:externalPrincipalNames with type "+t+" must be detected.");
- } catch (CommitFailedException e) {
- // success
- assertEquals(71, e.getCode());
} finally {
systemRoot.refresh();
}
}
}
+ @Override
+ public void testAddRepExternalId() throws Exception {
+ root.getTree(testUserPath).setProperty(ExternalIdentityConstants.REP_EXTERNAL_ID, "id");
+ root.commit();
+ }
+
+ @Override
@Test
- public void testExternalPrincipalNamesSingle() throws Exception {
- Root systemRoot = getSystemRoot();
- try {
- NodeUtil n = new NodeUtil(systemRoot.getTree(testUserPath));
- n.setString(ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES, "id");
- systemRoot.commit();
- fail("Creating rep:externalPrincipalNames as single STRING property must be detected.");
- } catch (CommitFailedException e) {
- // success
- assertEquals(71, e.getCode());
- } finally {
- systemRoot.refresh();
- }
+ public void testModifyRepExternalId() throws Exception {
+ root.getTree(externalUserPath).setProperty(ExternalIdentityConstants.REP_EXTERNAL_ID, "anotherValue");
+ root.commit();
+ }
+
+ @Override
+ public void testRemoveRepExternalIdWithoutPrincipalNames() throws Exception {
+ root.getTree(testUserPath).setProperty(ExternalIdentityConstants.REP_EXTERNAL_ID, "id");
+ root.commit();
+
+ root.getTree(testUserPath).removeProperty(ExternalIdentityConstants.REP_EXTERNAL_ID);
+ root.commit();
}
}
\ No newline at end of file
Added: jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ValidatorNotDynamicTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ValidatorNotDynamicTest.java?rev=1755191&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ValidatorNotDynamicTest.java (added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ValidatorNotDynamicTest.java Thu Aug 4 14:03:31 2016
@@ -0,0 +1,108 @@
+/*
+ * 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.principal;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.spi.security.authentication.external.impl.ExternalIdentityConstants;
+import org.apache.jackrabbit.oak.util.NodeUtil;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+public class ValidatorNotDynamicTest extends ExternalIdentityValidatorTest {
+
+ @Override
+ public void before() throws Exception {
+ super.before();
+ }
+
+ @Override
+ protected boolean isDynamic() {
+ return false;
+ }
+
+ private void setExternalPrincipalNames() throws Exception {
+ Root systemRoot = getSystemRoot();
+ systemRoot.getTree(externalUserPath).setProperty(ExternalIdentityConstants.REP_EXTERNAL_PRINCIPAL_NAMES, ImmutableList.of("principalName"), Type.STRINGS);
+ systemRoot.commit();
+
+ root.refresh();
+ }
+
+ @Override
+ @Test
+ public void testRemoveExternalPrincipalNames() throws Exception {
+ setExternalPrincipalNames();
+
+ super.testRemoveExternalPrincipalNames();
+ }
+
+ @Override
+ @Test
+ public void testRemoveExternalPrincipalNamesAsSystem() throws Exception {
+ setExternalPrincipalNames();
+
+ super.testRemoveExternalPrincipalNamesAsSystem();
+ }
+
+ @Override
+ @Test
+ public void testModifyExternalPrincipalNames() throws Exception {
+ setExternalPrincipalNames();
+
+ super.testModifyExternalPrincipalNames();
+ }
+
+ @Override
+ @Test
+ public void testModifyExternalPrincipalNamesAsSystem() throws Exception {
+ setExternalPrincipalNames();
+
+ super.testModifyExternalPrincipalNamesAsSystem();
+ }
+
+
+ @Override
+ @Test
+ public void testRemoveRepExternalId() throws Exception {
+ try {
+ root.getTree(externalUserPath).removeProperty(ExternalIdentityConstants.REP_EXTERNAL_ID);
+ root.commit();
+
+ fail("Removal of rep:externalId must be detected in the default setup.");
+ } catch (CommitFailedException e) {
+ // success: verify nature of the exception
+ assertTrue(e.isConstraintViolation());
+ assertEquals(74, e.getCode());
+ }
+ }
+
+ @Override
+ @Test
+ public void testRemoveRepExternalIdAsSystem() throws Exception {
+ Root systemRoot = getSystemRoot();
+ NodeUtil n = new NodeUtil(systemRoot.getTree(externalUserPath));
+
+ n.removeProperty(ExternalIdentityConstants.REP_EXTERNAL_ID);
+ systemRoot.commit();
+ }
+}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/external/defaultusersync.md
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/external/defaultusersync.md?rev=1755191&r1=1755190&r2=1755191&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/external/defaultusersync.md (original)
+++ jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/external/defaultusersync.md Thu Aug 4 14:03:31 2016
@@ -50,6 +50,12 @@ the authorizables can later on be identi
- `rep:externalId` : This allows to identify the external users, know the associated IDP and distinguish them from others.
- `rep:lastSynced` : Sync timestamp to mark the external user/group valid for the configurable time (to reduce expensive syncing). Once expired, they will be validated against the 3rd party system again.
+NOTE: Since Oak 1.5.8 the system-maintained property `rep:externalId` is
+protected and can not be altered using regular JCR and Jackrabbit
+API, irrespective of the permission setup of the editing session. For
+backwards compatibility this protection can be turned off. See [OAK-4301]
+for further details.
+
The [DefaultSyncContext] is exported as part of the 'basic' package space and
may be used to provide custom implementations.
@@ -106,6 +112,8 @@ will re-create the `rep:externalPrincipa
<a name="validation"/>
#### Validation
+##### rep:externalPrincipalNames
+
As of Oak 1.5.3 a dedicated `Validator` implementation asserts that the protected,
system-maintained property `rep:externalPrincipalNames` is only written by the
internal system session.
@@ -119,10 +127,21 @@ with external user/group accounts.
| Code | Message |
|-------------------|----------------------------------------------------------|
-| 0070 | Attempt to create, modify or remove the system property rep:externalPrincipalNames |
-| 0071 | Attempt to write rep:externalPrincipalNames with a type other than Type.STRINGS |
-| 0072 | Property rep:externalPrincipalNames requires rep:externalId to be present on the Node. |
-| 0073 | Property rep:externalId cannot be removed if rep:externalPrincipalNames is present. |
+| 0070 | Attempt to create, modify or remove the system property 'rep:externalPrincipalNames' |
+| 0071 | Attempt to write 'rep:externalPrincipalNames' with a type other than Type.STRINGS |
+| 0072 | Property 'rep:externalPrincipalNames' requires 'rep:externalId' to be present on the Node. |
+| 0073 | Property 'rep:externalId' cannot be removed if 'rep:externalPrincipalNames' is present. |
+
+##### rep:externalId
+
+If protection of the `rep:externalId` property is enabled (since Oak 1.5.8) the
+validator performs the following checks:
+
+| Code | Message |
+|-------------------|----------------------------------------------------------|
+| 0074 | Attempt to add, modify or remove the system maintained property 'rep:externalId'. |
+| 0075 | Property 'rep:externalId' may only have a single value of type STRING. |
+
<a name="configuration"/>
### Configuration
@@ -160,6 +179,13 @@ as additional value to the `requiredServ
See section [Introduction to Oak Security](../introduction.html) for further details on the `SecurityProviderRegistration`.
+The `ExternalPrincipalConfiguration` defines the following configuration options:
+
+| Name | Property | Description |
+|------------------------------|-------------------------------|------------------------------------------|
+| External Identity Protection | `protectExternalId` | Enables protection of the system maintained `rep:externalId` properties |
+| | | |
+
<!-- references -->
[SyncContext]: /oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncContext.html
[DefaultSyncContext]: /oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncContext.html
@@ -171,4 +197,5 @@ See section [Introduction to Oak Securit
[ExternalPrincipalConfiguration]: /oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfiguration.html
[DynamicSyncContext]: /oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/DynamicSyncContext.html
[OAK-4101]: https://issues.apache.org/jira/browse/OAK-4101
-[OAK-2687]: https://issues.apache.org/jira/browse/OAK-2687
\ No newline at end of file
+[OAK-2687]: https://issues.apache.org/jira/browse/OAK-2687
+[OAK-4301]: https://issues.apache.org/jira/browse/OAK-4301
\ No newline at end of file