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 2023/03/05 15:58:08 UTC

[jackrabbit-oak] branch trunk updated: OAK-10132 ; Duplication in XPathConditionVisitor and ImpersonationImpl (#866)

This is an automated email from the ASF dual-hosted git repository.

angela pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/jackrabbit-oak.git


The following commit(s) were added to refs/heads/trunk by this push:
     new f666b0dbdf OAK-10132 ; Duplication in XPathConditionVisitor and ImpersonationImpl (#866)
f666b0dbdf is described below

commit f666b0dbdf937dc0376fa4fc0f2abfb703c80428
Author: anchela <an...@apache.org>
AuthorDate: Sun Mar 5 16:58:02 2023 +0100

    OAK-10132 ; Duplication in XPathConditionVisitor and ImpersonationImpl (#866)
---
 .../oak/security/user/ImpersonationImpl.java       |  9 +--
 .../apache/jackrabbit/oak/security/user/Utils.java | 28 ++++++++-
 .../security/user/query/XPathConditionVisitor.java | 13 +---
 .../jackrabbit/oak/security/user/UtilsTest.java    | 72 ++++++++++++++++++++++
 4 files changed, 103 insertions(+), 19 deletions(-)

diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/ImpersonationImpl.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/ImpersonationImpl.java
index 51152a1b79..867cdbaffe 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/ImpersonationImpl.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/ImpersonationImpl.java
@@ -26,7 +26,6 @@ import org.apache.jackrabbit.api.security.principal.PrincipalIterator;
 import org.apache.jackrabbit.api.security.principal.PrincipalManager;
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.Impersonation;
-import org.apache.jackrabbit.api.security.user.User;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.api.Type;
@@ -177,13 +176,7 @@ class ImpersonationImpl implements Impersonation, UserConstants {
         } else if (GroupPrincipals.isGroup(principal)) {
             return false;
         } else {
-            try {
-                Authorizable authorizable = user.getUserManager().getAuthorizable(principal);
-                return authorizable != null && !authorizable.isGroup() && ((User) authorizable).isAdmin();
-            } catch (RepositoryException e) {
-                log.debug(e.getMessage());
-                return false;
-            }
+            return Utils.canImpersonateAllUsers(principal, user.getUserManager());
         }
     }
 
diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/Utils.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/Utils.java
index 197f661ab0..a39bf98a6e 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/Utils.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/Utils.java
@@ -18,6 +18,7 @@ package org.apache.jackrabbit.oak.security.user;
 
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.commons.PathUtils;
@@ -28,11 +29,16 @@ import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
 import org.apache.jackrabbit.oak.spi.security.user.util.UserUtil;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import javax.jcr.AccessDeniedException;
 import javax.jcr.RepositoryException;
+import java.security.Principal;
 
-final class Utils {
+public final class Utils {
+
+    private static final Logger log = LoggerFactory.getLogger(Utils.class);
 
     private Utils() {}
 
@@ -83,6 +89,26 @@ final class Utils {
     static boolean isEveryone(@NotNull Authorizable authorizable) {
         return authorizable.isGroup() && EveryonePrincipal.NAME.equals(getPrincipalName(authorizable));
     }
+
+    /**
+     * Return {@code true} if the given principal can impersonate all users. 
+     * The implementation tests if the given principal refers to an existing {@code User} for which {@link User#isAdmin()} 
+     * returns {@code true}.
+     * 
+     * @param principal A non-null principal instance.
+     * @param userManager The user manager used for the lookup calling {@link UserManager#getAuthorizable(Principal))}
+     * @return {@code true} if the given principal can impersonate all users; {@code false} if that condition is not met 
+     * or if the evaluation failed.
+     */
+    public static boolean canImpersonateAllUsers(@NotNull Principal principal, @NotNull UserManager userManager) {
+        try {
+            Authorizable authorizable = userManager.getAuthorizable(principal);
+            return authorizable != null && !authorizable.isGroup() && ((User) authorizable).isAdmin();
+        } catch (RepositoryException e) {
+            log.debug(e.getMessage());
+            return false;        
+        }
+    }
     
     @Nullable
     private static String getPrincipalName(@NotNull Authorizable authorizable) {
diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/query/XPathConditionVisitor.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/query/XPathConditionVisitor.java
index 8beb4697ee..f5c6a2e0aa 100644
--- a/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/query/XPathConditionVisitor.java
+++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/query/XPathConditionVisitor.java
@@ -19,14 +19,14 @@ package org.apache.jackrabbit.oak.security.user.query;
 import javax.jcr.RepositoryException;
 
 import org.apache.jackrabbit.JcrConstants;
-import org.apache.jackrabbit.api.security.user.Authorizable;
-import org.apache.jackrabbit.api.security.user.User;
 import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
 import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
 import org.jetbrains.annotations.NotNull;
 
+import static org.apache.jackrabbit.oak.security.user.Utils.canImpersonateAllUsers;
+
 /**
  * XPATH based condition visitor.
  */
@@ -98,14 +98,7 @@ class XPathConditionVisitor implements ConditionVisitor {
     @Override
     public void visit(@NotNull Condition.Impersonation condition) {
         String principalName = condition.getName();
-        boolean isAdmin = false;
-        try {
-            Authorizable authorizable = userMgr.getAuthorizable(new PrincipalImpl(principalName));
-            isAdmin = authorizable != null && !authorizable.isGroup() && ((User) authorizable).isAdmin();
-        } catch (RepositoryException e) {
-            // unable to retrieve authorizable
-        }
-        if (isAdmin) {
+        if (canImpersonateAllUsers(new PrincipalImpl(principalName), userMgr)) {
             statement.append('@')
                     .append(QueryUtil.escapeForQuery(JcrConstants.JCR_PRIMARYTYPE, namePathMapper))
                     .append("='")
diff --git a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UtilsTest.java b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UtilsTest.java
index 6462817d17..6a5df7e4ea 100644
--- a/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UtilsTest.java
+++ b/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UtilsTest.java
@@ -16,29 +16,43 @@
  */
 package org.apache.jackrabbit.oak.security.user;
 
+import java.security.Principal;
 import java.util.Map;
 import com.google.common.collect.ImmutableMap;
+import org.apache.jackrabbit.api.security.principal.GroupPrincipal;
 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.AbstractSecurityTest;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.commons.PathUtils;
 import org.apache.jackrabbit.oak.plugins.tree.TreeAware;
 import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.spi.security.principal.AdminPrincipal;
 import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
+import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration;
 import org.jetbrains.annotations.NotNull;
 import org.junit.Test;
 
 import javax.jcr.AccessDeniedException;
 import javax.jcr.RepositoryException;
 
+import static org.apache.jackrabbit.oak.security.user.Utils.canImpersonateAllUsers;
+import static org.apache.jackrabbit.oak.spi.security.user.UserConstants.DEFAULT_ADMIN_ID;
+import static org.apache.jackrabbit.oak.spi.security.user.UserConstants.PARAM_ADMIN_ID;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoInteractions;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -68,6 +82,13 @@ public class UtilsTest extends AbstractSecurityTest {
     private void assertEqualPath(@NotNull Tree expected, @NotNull Tree result) {
         assertEquals(expected.getPath(), result.getPath());
     }
+    
+    private @NotNull Principal getAdminPrincipal(@NotNull UserManager userManager) throws Exception {
+        String adminId = getConfig(UserConfiguration.class).getParameters().getConfigValue(PARAM_ADMIN_ID, DEFAULT_ADMIN_ID);
+        User admin = userManager.getAuthorizable(adminId, User.class);
+        assertNotNull(admin);
+        return admin.getPrincipal();
+    }
 
     @Test
     public void testGetOrAddTreeCurrentElement() throws Exception {
@@ -157,6 +178,57 @@ public class UtilsTest extends AbstractSecurityTest {
         assertFalse(Utils.isEveryone(a));
     }
     
+    @Test
+    public void testCanImpersonateAllNonExisting() throws Exception {
+        Principal principal = new PrincipalImpl("nonExisting");
+        UserManager userManager = getUserManager(root);
+        
+        assertNull(userManager.getAuthorizable(principal));
+        assertFalse(canImpersonateAllUsers(principal, userManager));
+    }
+    
+    @Test
+    public void testCanImpersonateAllForGroup() throws Exception {
+        Principal principal = new PrincipalImpl("aGroup");
+        Group gr = getUserManager(root).createGroup(principal);
+
+        UserManager userManager = spy(getUserManager(root));
+        assertFalse(canImpersonateAllUsers(principal, userManager));
+    }
+    
+    @Test
+    public void testCanImpersonateAllForAdminUser() throws Exception {
+        UserManager userManager = getUserManager(root);
+        Principal adminPrincipal = getAdminPrincipal(userManager);
+        
+        assertTrue(canImpersonateAllUsers(adminPrincipal, userManager));
+        assertTrue(canImpersonateAllUsers(new PrincipalImpl(adminPrincipal.getName()), userManager));
+        
+        GroupPrincipal gp = when(mock(GroupPrincipal.class).getName()).thenReturn(adminPrincipal.getName()).getMock();
+        assertTrue(canImpersonateAllUsers(gp, userManager));
+    }
+
+    @Test
+    public void testCanImpersonateAllForNonAdminUser() throws Exception {
+        User u = getTestUser();
+
+        UserManager userManager = getUserManager(root);
+        String userPrincipalName = u.getPrincipal().getName();
+
+        assertFalse(canImpersonateAllUsers(u.getPrincipal(), userManager));
+        assertFalse(canImpersonateAllUsers(new PrincipalImpl(userPrincipalName), userManager));
+        assertFalse(canImpersonateAllUsers((AdminPrincipal) () -> userPrincipalName, userManager));
+    }
+    
+    @Test
+    public void testCanImpersonateAllLookupFails() throws Exception {
+        UserManager umgrMock = when(mock(UserManager.class).getAuthorizable(any(Principal.class))).thenThrow(new RepositoryException()).getMock();
+
+        Principal adminPrincipal = getAdminPrincipal(getUserManager(root));
+
+        assertFalse(canImpersonateAllUsers(adminPrincipal, umgrMock));
+    }
+    
     @Test
     public void testGetTreeFromTreeAware() throws Exception {
         Tree t = mock(Tree.class);