Author: angela
Date: Wed Oct 28 16:37:04 2020
New Revision: 1882944

URL: http://svn.apache.org/viewvc?rev=1882944&view=rev
Log:
OAK-9051 : Enhance oak-exercise for Principal base authorization

Added:
    
jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authorization/principalbased_evaluation.md
    
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/
    
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/AbstractPrincipalBasedTest.java
   (with props)
    
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L1_IntroductionTest.java
   (with props)
    
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L2_AccessControlManagementTest.java
   (with props)
    
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L3_PermissionEvaluationTest.java
   (with props)
    
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L4_DisabledAggregationFilterTest.java
   (with props)
Modified:
    
jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authorization/principalbased.md
    jackrabbit/oak/trunk/oak-exercise/pom.xml

Modified: 
jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authorization/principalbased.md
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authorization/principalbased.md?rev=1882944&r1=1882943&r2=1882944&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authorization/principalbased.md
 (original)
+++ 
jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authorization/principalbased.md
 Wed Oct 28 16:37:04 2020
@@ -163,8 +163,8 @@ looking up effective policies by princip
  
 If a given set of principals is supported by the configured 
`FilterProvider/Filter` implementation, the principal-based 
 authorization model will contribute an implementation of 
`AggregatedPermissionProvider` to the composite. Whether or not 
-access will be granted depends on the aggregated providers and their ranking, 
the composition type and whether or not an 
-`AggregationFilter` is defined for the setup (see also section [Combining 
Multiple Authorization Models](composite.html) for details). 
+access will be granted depends on the aggregated providers and their ranking, 
the composition type and the presence of an 
+`AggregationFilter` (see also section [Combining Multiple Authorization 
Models](composite.html) for details). 
 
 If the set of principals is not supported an `EmptyPermissionProvider` will be 
returned and the model will be ignored 
 altogether. It follows that in this case permission evaluation delegated to 
other authorization modules configured in the 
@@ -192,7 +192,7 @@ The inheritance model only takes the ite
 start at the target item and search up the item hierarchy for a matching 
entry. An entry is considered matching if it is 
 defined for any of the principals in the given set, applies to the target item 
and grants the specified permissions.  
 
-##### Allowed if Granted
+##### Evaluation Shortcut
 
 As soon as an entry matches the target item and grants the requested 
permission the evaluation will stop. As this 
 model only supports allowing entries there exists no particular requirement to 
maintain and handle the order of 
@@ -230,7 +230,7 @@ limit the scope of the principal-based a
 - the set of principals must not be empty and must only contain 
`SystemUserPrincipal`s
 - each `SystemUserPrincipal` must be associated with a location in the 
repository (i.e. must be `ItemBasedPrincipal` when 
   obtained through principal management API).
-- all principals must additionally be located below the path configured with 
`FilterProviderImpl` (see [below](#configuration)
+- all principals must additionally be located below the path configured with 
`FilterProviderImpl` (see section [Configuration](#configuration))
 
 So, if this implementation is enabled the principal-based authorization will 
only take effect for `SystemUserPrincipal`s 
 that are created below the configured path. As soon as a given `Subject` or 
set of principals contains principals that 
@@ -246,6 +246,12 @@ interface that stops the aggregation of
 `PrincipalBasedPermissionProvider` takes effect (i.e. the mandatory 
`FilterProvider` will handle a given set of principals).
 The `AggregationFilter` can be enabled by setting the corresponding flag with 
the module [configuration](#configuration). 
 
+<a name="details_examples"></a>
+#### Examples
+
+See [Permission Evaluation with Principal-Based 
Authorization](principalbased_evaluation.html) for examples illustrating  
+an authorization setup including principal-based authorization and how it 
handles different principals.
+
 <a name="representation"></a>
 ### Representation in the Repository
 

Added: 
jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authorization/principalbased_evaluation.md
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authorization/principalbased_evaluation.md?rev=1882944&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authorization/principalbased_evaluation.md
 (added)
+++ 
jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authorization/principalbased_evaluation.md
 Wed Oct 28 16:37:04 2020
@@ -0,0 +1,137 @@
+<!--
+   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.
+-->
+
+Permission Evaluation with Principal-Based Authorization
+--------------------------------------------------------------------------------
+
+The examples below describe permission evaluation based on an authorization 
setup with the following characteristices:
+   
+    FilterProviderImpl:
+        - Path: "/home/users/system/supported"
+
+    CompositeAuthorizationConfiguration (CompositionType=AND): 
+       
+        PrincipalBasedAuthorizationConfiguration
+        - FilterProvider: reference to FilterProviderImpl as configured above 
(default implementation)
+        - Enable AggregationFilter: true
+        - Ranking: 500
+        
+        AuthorizationConfigurationImpl
+        - Ranking: 100
+ 
+The following principals will be used in various combinations:
+ 
+    Principals not supported by the configured 'FilterProvider'
+    
+    - GroupPrincipal:      'testgroup'        
+    - Principal:           'user'        
+    - SystemUserPrincipal: 'service-A' with path /home/users/system/45
+    
+    Principals supporeted by the configured 'FilterProvider'
+    
+    - SystemUserPrincipal: 'service-B' with path 
/home/users/system/supported/featureB/11
+    - SystemUserPrincipal: 'service-C' with path 
/home/users/system/supported/featureC/C1
+    
+The following access control setup has been defined:
+ 
+    grant access using regular path-based ac-management calls 
+    i.e. 'AccessControlManager.getApplicablePolicies(String)' or 
'AccessControlManager.getPolicies(String))'
+    
+    - 'testgroup': /content [jcr:read, jcr:readAccessControl]
+    - 'service-A': /content [jcr:versionManagement]
+    - 'service-B': /content [jcr:read, jcr:modifyProperties]
+    
+    grant access using principal-based ac-management calls (only possible for 
supported principals)
+    i.e. 'JackrabbitAccessControlManager.getApplicablePolicies(Principal)' or 
'AccessControlManager.getPolicies(Principal))'
+    
+    - 'service-B': /content [jcr:read, jcr:nodeTypeManagement]
+    - 'service-C': /content [jcr:read, jcr:lockManagement]
+                   
+##### Example 1: Subject with principals _'user'_, _'testgroup'_
+Since neither 'user' nor 'testgroup' is a system-user-princial supported by 
principal-based authorization, 
+principal-based permission evaluation is omitted.
+
+Result: the Session is granted `jcr:read`, `jcr:readAccessControl` at /content.
+ 
+##### Example 2: Subject with principals _'service-A'_, _'testgroup'_
+Since neither 'service-A' nor 'testgroup' is supported by principal-based 
authorization, 
+principal-based permission evaluation is omitted.
+
+Result: the Session is granted `jcr:read`, `jcr:readAccessControl`, 
`jcr:versionManagement` at /content.
+ 
+##### Example 3: Subject with principals _'service-B'_, _'testgroup'_
+Since 'testgroup' is not supported by principal-based authorization, 
principal-based permission evaluation is omitted 
+and only path-based access control setup take effect.
+
+Result: the Session is granted 
`jcr:read`,`jcr:readAccessControl`,`jcr:modifyProperties` at /content.
+ 
+##### Example 4: Subject with principals _'service-A'_, _'service-B'_
+Since 'service-A' is not supported by principal-based authorization, 
principal-based permission evaluation is omitted 
+and only path-based access control setup take effect.
+
+Result: the Session is granted 
`jcr:read`,`jcr:modifyProperties`,`jcr:versionManagement` at /content.
+ 
+##### Example 5: Subject with principals _'service-B'_
+'service-B' is supported by principal-based authorization and no unsupported 
principal is present in the Subject.
+Therefore, principal-based permission evaluation takes effect. Since the 
`AggregationFilter` is enabled in the configuration 
+describedf above, permission evaluation stops and does not continue evaluating 
path-based permissions.
+
+Result: the Session is granted `jcr:read`, `jcr:nodeTypeManagement` at 
/content.
+
+NOTE: 
+If `AggregationFilter` was disabled _both_ permission providers would be used 
for the evaluation. 
+The result then depends on the `CompositionType`:
+
+| `AggregationFilter` | `CompositionType.AND` | `CompositionType.OR` |
+|---------------------|-----------------------|----------------------|
+| enabled           | `jcr:read`, `jcr:nodeTypeManagement` | `jcr:read`, 
`jcr:nodeTypeManagement` |
+| disabled          | `jcr:read`          | `jcr:read`, 
`jcr:modifyProperties`, `jcr:nodeTypeManagement` |
+ 
+##### Example 6: Subject with principals _'service-C'_
+'service-C' is supported by principal-based authorization and no unsupported 
principal is present in the Subject.
+Therefore, principal-based permission evaluation takes effect. Since the 
`AggregationFilter` is enabled in the configuration
+described above, permission evaluation stops and does not continue evaluating 
path-based permissions.
+
+Result: the Session is granted `jcr:read`, `jcr:lockManagement` at /content.
+
+NOTE: 
+If `AggregationFilter` was disabled _both_ permission providers would be used 
for the evaluation. 
+The result then depends on the `CompositionType`:
+
+| `AggregationFilter` | `CompositionType.AND` | `CompositionType.OR` |
+|---------------------|-----------------------|----------------------|
+| enabled           | `jcr:read`, `jcr:lockManagement` | `jcr:read`, 
`jcr:lockManagement` |
+| disabled          | -                   | `jcr:read`, `jcr:lockManagement` |
+ 
+##### Example 6: Subject with principals _'service-B'_, _'service-C'_
+Both 'service-B' is supported by principal-based authorization and no 
unsupported principal is present in the Subject.
+Therefore, principal-based permission evaluation takes effect. Since the 
`AggregationFilter` is enabled in the configuration
+described above, permission evaluation stops and does not continue evaluating 
path-based permissions.
+
+Result: the Session is granted `jcr:read`, `jcr:nodeTypeManagement`, 
`jcr:lockManagement` at /content.
+
+NOTE: 
+If `AggregationFilter` was disabled _both_ permission providers would be used 
for the evaluation. 
+The result then depends on the `CompositionType`:
+
+| `AggregationFilter` | `CompositionType.AND` | `CompositionType.OR` |
+|---------------------|-----------------------|----------------------|
+| enabled           | `jcr:read`, `jcr:nodeTypeManagement`, 
`jcr:lockManagement` | `jcr:read`, `jcr:nodeTypeManagement`, 
`jcr:lockManagement` |
+| disabled          | `jcr:read`          | `jcr:read`, 
`jcr:modifyProperties`, `jcr:nodeTypeManagement`, `jcr:lockManagement` |
+          
+    
+ 

Modified: jackrabbit/oak/trunk/oak-exercise/pom.xml
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/pom.xml?rev=1882944&r1=1882943&r2=1882944&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-exercise/pom.xml Wed Oct 28 16:37:04 2020
@@ -121,6 +121,11 @@
     </dependency>
     <dependency>
       <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-authorization-principalbased</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
       <artifactId>jackrabbit-jcr-commons</artifactId>
       <version>${jackrabbit.version}</version>
     </dependency>
@@ -205,9 +210,20 @@
       <scope>test</scope>
     </dependency>
     <dependency>
+      <groupId>org.apache.jackrabbit</groupId>
+      <artifactId>oak-store-composite</artifactId>
+      <version>${project.version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
       <groupId>ch.qos.logback</groupId>
       <artifactId>logback-classic</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.apache.sling</groupId>
+      <artifactId>org.apache.sling.testing.osgi-mock</artifactId>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
 </project>

Added: 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/AbstractPrincipalBasedTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/AbstractPrincipalBasedTest.java?rev=1882944&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/AbstractPrincipalBasedTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/AbstractPrincipalBasedTest.java
 Wed Oct 28 16:37:04 2020
@@ -0,0 +1,172 @@
+/*
+ * 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.exercise.security.authorization.principalbased;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlPolicy;
+import 
org.apache.jackrabbit.api.security.authorization.PrincipalAccessControlList;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.oak.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.composite.MountInfoProviderService;
+import 
org.apache.jackrabbit.oak.security.authorization.composite.CompositeAuthorizationConfiguration;
+import org.apache.jackrabbit.oak.security.internal.SecurityProviderHelper;
+import org.apache.jackrabbit.oak.spi.security.CompositeConfiguration;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregationFilter;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.principalbased.FilterProvider;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.principalbased.impl.FilterProviderImpl;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.principalbased.impl.PrincipalBasedAuthorizationConfiguration;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.apache.sling.testing.mock.osgi.junit.OsgiContext;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Rule;
+
+import javax.security.auth.Subject;
+import java.security.Principal;
+import java.security.PrivilegedExceptionAction;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+abstract class AbstractPrincipalBasedTest extends AbstractSecurityTest {
+
+    @Rule
+    public final OsgiContext context = new OsgiContext();
+
+    private Group gr;
+    private final Map<String, User> systemUsers = new HashMap<>();
+
+    private final PrincipalBasedAuthorizationConfiguration 
principalBasedAuthorizationConfiguration = new 
PrincipalBasedAuthorizationConfiguration();
+
+    @Override
+    public void after() throws Exception {
+        try {
+            if (gr != null) {
+                gr.remove();
+            }
+            for (User u : systemUsers.values()) {
+                u.remove();
+            }
+            root.commit();
+        } finally {
+            super.after();
+        }
+    }
+
+    @Override
+    protected SecurityProvider initSecurityProvider() {
+        // principal-based authorization is designed for osgi-setup.
+        // injecting the configuration into the security provider needs a some 
workarounds....
+        FilterProvider filterProvider = getFilterProvider();
+        context.registerInjectActivateService(filterProvider, 
Collections.singletonMap("path", getSupportedPath()));
+        context.registerInjectActivateService(new MountInfoProviderService());
+        ConfigurationParameters params = 
ConfigurationParameters.of(CompositeConfiguration.PARAM_RANKING, 500, 
"enableAggregationFilter", enableAggregationFilter());
+        
context.registerInjectActivateService(principalBasedAuthorizationConfiguration, 
params);
+
+        SecurityProvider sp = super.initSecurityProvider();
+        SecurityProviderHelper.updateConfig(sp, 
principalBasedAuthorizationConfiguration, AuthorizationConfiguration.class);
+        if (enableAggregationFilter()) {
+            AggregationFilter aggregationFilter = 
context.getService(AggregationFilter.class);
+            ((CompositeAuthorizationConfiguration) 
sp.getConfiguration(AuthorizationConfiguration.class)).withAggregationFilter(aggregationFilter);
+        }
+        return sp;
+    }
+
+    @NotNull
+    @Override
+    protected ConfigurationParameters getSecurityConfigParameters() {
+        return ConfigurationParameters.of("authorizationCompositionType", 
getCompositionType().toString());
+    }
+
+    @NotNull
+    CompositeAuthorizationConfiguration.CompositionType getCompositionType() {
+        return CompositeAuthorizationConfiguration.CompositionType.AND;
+    }
+
+    @NotNull
+    FilterProvider getFilterProvider() {
+        return new FilterProviderImpl();
+    }
+
+    boolean enableAggregationFilter() {
+        return true;
+    }
+
+    @NotNull
+    String getSupportedPath() {
+        return PathUtils.concat(UserConstants.DEFAULT_USER_PATH, 
getSupportedIntermediatePath());
+    }
+
+    @NotNull
+    String getSupportedIntermediatePath() {
+        return 
PathUtils.concatRelativePaths(UserConstants.DEFAULT_SYSTEM_RELATIVE_PATH, 
"supported");
+    }
+
+    @NotNull
+    Principal getRegularUserPrincipal() throws Exception {
+        return getTestUser().getPrincipal();
+    }
+
+    @NotNull
+    Principal getGroupPrincipal() throws Exception {
+        if (gr == null) {
+            gr = getUserManager(root).createGroup("groupId");
+            root.commit();
+        }
+        return gr.getPrincipal();
+    }
+
+    @NotNull
+    Principal getSystemUserPrincipal(@NotNull String name, @Nullable String 
intermediatePath) throws Exception {
+        User su;
+        if (systemUsers.containsKey(name)) {
+            su = systemUsers.get(name);
+        } else {
+            su = getUserManager(root).createSystemUser(name, intermediatePath);
+            root.commit();
+            systemUsers.put(name, su);
+        }
+        return su.getPrincipal();
+    }
+
+    @NotNull
+    PrincipalBasedAuthorizationConfiguration 
getPrincipalBasedAuthorizationConfiguration() {
+        return principalBasedAuthorizationConfiguration;
+    }
+
+    @Nullable
+    static PrincipalAccessControlList 
getApplicablePrincipalAccessControlList(@NotNull JackrabbitAccessControlManager 
acMgr, @NotNull Principal principal) throws Exception {
+        Set<JackrabbitAccessControlPolicy> applicable = 
ImmutableSet.copyOf(acMgr.getApplicablePolicies(principal));
+        PrincipalAccessControlList acl = (PrincipalAccessControlList) 
Iterables.find(applicable, accessControlPolicy -> accessControlPolicy 
instanceof PrincipalAccessControlList, null);
+        return acl;
+    }
+
+    @NotNull
+    ContentSession getTestSession(@NotNull Principal... principals) throws 
Exception {
+        Subject subject = new Subject(true, ImmutableSet.copyOf(principals), 
ImmutableSet.of(), ImmutableSet.of());
+        return Subject.doAsPrivileged(subject, 
(PrivilegedExceptionAction<ContentSession>) () -> 
getContentRepository().login(null, null), null);
+    }
+}
\ No newline at end of file

Propchange: 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/AbstractPrincipalBasedTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L1_IntroductionTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L1_IntroductionTest.java?rev=1882944&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L1_IntroductionTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L1_IntroductionTest.java
 Wed Oct 28 16:37:04 2020
@@ -0,0 +1,194 @@
+/*
+ * 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.exercise.security.authorization.principalbased;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import 
org.apache.jackrabbit.oak.security.authorization.AuthorizationConfigurationImpl;
+import org.apache.jackrabbit.oak.spi.security.CompositeConfiguration;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.permission.EmptyPermissionProvider;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.principalbased.Filter;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.principalbased.FilterProvider;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.principalbased.impl.PrincipalBasedAuthorizationConfiguration;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.junit.Test;
+
+import javax.jcr.security.AccessControlManager;
+import java.security.Principal;
+import java.util.List;
+import java.util.Set;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * <pre>
+ * Module: Principal-Based Authorization
+ * 
=============================================================================
+ *
+ * Title: Introduction to Principal-Based Authorization
+ * 
-----------------------------------------------------------------------------
+ *
+ * Goal:
+ * Recap extensions to JCR access control management defined by Jackrabbit API 
and get a basic understanding of
+ * the additional authorization model 'oak-authorization-principalbased'.
+ *
+ * Exercises:
+ *
+ * - Recap extensions to JCR access control management API defined in 
Jackrabbit API and compare getting/setting
+ *   access control policies by path and by principal.
+ *
+ *   
http://jackrabbit.apache.org/oak/docs/apidocs/org/apache/jackrabbit/api/security/JackrabbitAccessControlManager.html
+ *   
http://jackrabbit.apache.org/oak/docs/security/accesscontrol.html#jackrabbit_api
+ *   
http://jackrabbit.apache.org/oak/docs/security/authorization/principalbased.html#jackrabbit_api
+ *
+ *   Question: What does binding a policy to a node means in this context?
+ *   Question: Where does a principal-based policy take effect? see also
+ *   
https://docs.adobe.com/docs/en/spec/jcr/2.0/16_Access_Control_Management.html#16.3%20Access%20Control%20Policies
+ *   Question: How does the PrincipalAccessControlList allow to specify where 
a given entry takes effect and how
+ *   restrictions could be used to achieve the same effect?
+ *
+ * - Repository setup with principal-based authorization:
+ *   The subsequent exercises will use a default repository setup including 
principal-based authorization. Get the basics
+ *   of the security setup and the configuration options.
+ *
+ *   - {@link #testAuthorizationConfiguration()}:
+ *     Inspect the authorization configuration present with the exercise setup 
and fix the test case.
+ *     Discuss, why the order of the aggregated configurations matters. Can 
you explain it?
+ *
+ * - Supported Principals
+ *   The principal-based authorization module is designed to apply to a 
limited set of supported principals:
+ *
+ *   
http://jackrabbit.apache.org/oak/docs/security/authorization/principalbased.html#api_extensions
+ *   
http://jackrabbit.apache.org/oak/docs/security/authorization/principalbased.html#details_filterprovider
+ *
+ *   - {@link #testSupportedPrincipals()}
+ *     Distribute the different principals to the 2 set of principals 
(unsupported and supported) and verify that the test passes.
+ *     Try out different combinations and explain, which principals are 
supported and why.
+ *
+ *     Question: what change in the setup would be needed, if you wished to 
support other paths?
+ *     Question: what change in the setup would be needed, if you wished to 
support other types of principals?
+ *
+ * - Access Control Mangement and Permission Evaluation
+ *   Before starting with the detailed tests let's take another look at the 
impact of injecting the principal based
+ *   authorization module into the Oak security setup:
+ *
+ *   - {@link #testAccessControlManager()}: compare the access control manager 
obtained from the principal-based
+ *      authorization configuration with the manager obtained from the 
complete security setup.
+ *
+ *      Question: how are the different manager aggregated?
+ *      Question: can you explain the order?
+ *
+ *   Read 
http://jackrabbit.apache.org/oak/docs/security/authorization/principalbased.html#details_permission_eval
 and
+ *   complete the following 2 tests to get an idea how supported vs 
unsupported principals impact the permission evaluation.
+ *
+ *   - {@link #testPermissionProviderSupportedPrincipals()}: create a set of 
supported principals to make sure
+ *     the principal-based module contributes to the evaluation
+ *   - {@link #testPermissionProviderUnsupportedPrincipals()}: create a 
principal set that is not supported.
+ *
+ *     Question: can you explain the usage of {@link EmptyPermissionProvider}
+ *     Question: can you explain why the composite-PermissionProvider looks 
different for supported vs unsupported principals?
+ *
+ * Related Exercises:
+ * 
-----------------------------------------------------------------------------
+ *
+ * - {@link L2_AccessControlManagementTest}
+ * - {@link L3_PermissionEvaluationTest}
+ * - {@link L4_DisabledAggregationFilterTest}
+ *
+ * </pre>
+ */
+public class L1_IntroductionTest extends AbstractPrincipalBasedTest {
+
+    @Test
+    public void testAuthorizationConfiguration() {
+        AuthorizationConfiguration ac = 
getConfig(AuthorizationConfiguration.class);
+        assertTrue(ac instanceof CompositeConfiguration);
+
+        CompositeConfiguration<AuthorizationConfiguration> composite = 
(CompositeConfiguration<AuthorizationConfiguration>) ac;
+        assertEquals(2, composite.getConfigurations().size());
+
+        List<AuthorizationConfiguration> aggregates = 
composite.getConfigurations();
+        // EXERCISE: retrieve the principal-based authorization from the 
aggregated authorization configurations
+        AuthorizationConfiguration principalbased = aggregates.get(0);
+        assertTrue(principalbased instanceof 
PrincipalBasedAuthorizationConfiguration);
+
+        // EXERCISE: retrieve the default authorization from the aggregated 
authorization configurations
+        AuthorizationConfiguration defaultAc = aggregates.get(1);
+        assertTrue(defaultAc instanceof AuthorizationConfigurationImpl);
+    }
+
+    @Test
+    public void testSupportedPrincipals() throws Exception {
+        FilterProvider pf = getFilterProvider();
+        Filter filter = pf.getFilter(getSecurityProvider(), root, 
getNamePathMapper());
+
+        // EXERCISE: use different combinations of the 6 principals to build 2 
sets: one that is supported and one that is not supported by the filter
+        Principal regularUserPrincipal = getRegularUserPrincipal();
+        Principal groupPrincipal = getGroupPrincipal();
+        Principal systemUser1 = getSystemUserPrincipal("su1", null);
+        Principal systemUser2 = getSystemUserPrincipal("su2", 
getSupportedIntermediatePath());
+        Principal systemUser3 = getSystemUserPrincipal("su3", 
PathUtils.concatRelativePaths(UserConstants.DEFAULT_SYSTEM_RELATIVE_PATH, 
"testpath"));
+        Principal systemUser4 = getSystemUserPrincipal("su4", 
getSupportedIntermediatePath() + "/testpath");
+
+        Set<Principal> unsupported = ImmutableSet.of(/* EXERCISE*/);
+        Set<Principal> supported = ImmutableSet.of(/* EXERCISE*/);
+
+        assertFalse(filter.canHandle(unsupported));
+        assertTrue(filter.canHandle(supported));
+    }
+
+    @Test
+    public void testAccessControlManager() throws Exception {
+        AccessControlManager acMgr = 
getPrincipalBasedAuthorizationConfiguration().getAccessControlManager(root, 
getNamePathMapper());
+        assertTrue(acMgr instanceof JackrabbitAccessControlManager);
+        assertEquals("EXERCISE", acMgr.getClass().getName());
+
+        AccessControlManager compositeAcMgr = 
getConfig(AuthorizationConfiguration.class).getAccessControlManager(root, 
getNamePathMapper());
+        assertTrue(compositeAcMgr instanceof JackrabbitAccessControlManager);
+
+        // EXERCISE: inspect the 'compositeAcMgr'
+    }
+
+    @Test
+    public void testPermissionProviderSupportedPrincipals() throws Exception {
+        Set<Principal> principals = ImmutableSet.of(/* EXERCISE: fill set with 
supported principal(s) */);
+
+        PermissionProvider pp = 
getPrincipalBasedAuthorizationConfiguration().getPermissionProvider(root, 
adminSession.getWorkspaceName(), principals);
+        assertFalse(pp instanceof EmptyPermissionProvider);
+
+        // EXERCISE: inspect the return value and explain it. add an assertion.
+        PermissionProvider compositePP = 
getConfig(AuthorizationConfiguration.class).getPermissionProvider(root, 
root.getContentSession().getWorkspaceName(), principals);
+        assertEquals("EXERCISE", compositePP.getClass().getName());
+    }
+
+    @Test
+    public void testPermissionProviderUnsupportedPrincipals() throws Exception 
{
+        Set<Principal> principals = ImmutableSet.of(/* EXERCISE: fill set with 
unsupported principal(s) */);
+
+        PermissionProvider pp = 
getPrincipalBasedAuthorizationConfiguration().getPermissionProvider(root, 
root.getContentSession().getWorkspaceName(), principals);
+        assertTrue(pp instanceof EmptyPermissionProvider);
+
+        // EXERCISE: inspect the return value and explain it. add an assertion.
+        PermissionProvider compositePP = 
getConfig(AuthorizationConfiguration.class).getPermissionProvider(root, 
root.getContentSession().getWorkspaceName(), principals);
+        assertEquals("EXERCISE", compositePP.getClass().getName());
+    }
+}
\ No newline at end of file

Propchange: 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L1_IntroductionTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L2_AccessControlManagementTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L2_AccessControlManagementTest.java?rev=1882944&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L2_AccessControlManagementTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L2_AccessControlManagementTest.java
 Wed Oct 28 16:37:04 2020
@@ -0,0 +1,267 @@
+/*
+ * 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.exercise.security.authorization.principalbased;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
+import 
org.apache.jackrabbit.api.security.authorization.PrincipalAccessControlList;
+import 
org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.api.ContentSession;
+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.TreeUtil;
+import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlPolicy;
+import java.security.Principal;
+import java.util.Iterator;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * <pre>
+ * Module: Principal-Based Authorization
+ * 
=============================================================================
+ *
+ * Title: Access Control Management with Principal-Based Authorization
+ * 
-----------------------------------------------------------------------------
+ *
+ * Goal:
+ * Learn how to manage access control by principal and how to use it 
combination with path-based access control
+ * management.
+ *
+ * Reading:
+ * 
http://jackrabbit.apache.org/oak/docs/security/authorization/principalbased.html#details_access_mgt
+ *
+ * Exercises:
+ *
+ * Applicable Access Control Policies
+ * Complete the following 3 tests to train your understanding of applicable 
access control policies. Compare the
+ * policies obtained from the principal-based authorization module with the 
actual repository setup.
+ *
+ * - {@link #testApplicablePoliciesSupportedPrincipal()}
+ * - {@link #testApplicablePoliciesUnsupportedPrincipal()}
+ * - {@link #testApplicablePoliciesByPath()}
+ *
+ *   Questions: What are the main differences between the isolated 
principal-based access control manager and the real-world composite setup?
+ *              Can you explain the differences between accessing policies by 
principal and by path?
+ *
+ * Editing Access Control
+ * The following tests focus on editing access control by principal. Complete 
the tests such that they both pass.
+ * Notice, that the for the assertion of the effective permission setup, two 
slightly different content sessions are
+ * created (one containing an unsupported principal).
+ *
+ * - {@link #testEditAccssControl()}
+ * - {@link #testEditAccssControl2()}
+ *
+ *   Questions: Can you change the access control setup using alternative ways 
to get the expected effective permissions (not changing the assertion)?
+ *              Can you explain the main difference between 
'testEditAccssControl' and 'testEditAccssControl2'?
+ *              Could you use 
AccessControlManager.getApplicablePolicies(testPath) in 'testEditAccssControl' 
and/or 'testEditAccssControl2'? Explain why or why not.
+ *
+ * Effective Access Control Policies
+ * Walk through the tests to understand how effective policies are computed 
when accessed by a set of principals or by path.
+ *
+ * - {@link #testEffectivePolicies()}: The same access control setup results 
in different effective policies depending
+ *                                     on the set of principals passed to the 
method. Complete the assertions such that the
+ *                                     test passes.
+ * - {@link #testEffectivePoliciesByPath()}: This time effective policies are 
access by path. Complete the assertions and
+ *                                     compare the results with the previous 
test.
+ *
+ *   Questions: What are the differences between effective policies by 
principals and by path?
+ *              Discuss how the notion of supported principal is reflected in 
each case.
+ * </pre>
+ */
+public class L2_AccessControlManagementTest extends AbstractPrincipalBasedTest 
{
+
+    private Principal supportedPrincipal;
+    private Principal unsupportedPrincipal;
+
+    private JackrabbitAccessControlManager principalBasedAcMgr;
+    private JackrabbitAccessControlManager compositeAcMgr;
+
+    private String testPath;
+
+    @Before
+    @Override
+    public void before() throws Exception {
+        super.before();
+
+        supportedPrincipal = getSystemUserPrincipal("systemUser", 
getSupportedIntermediatePath());
+        unsupportedPrincipal = getGroupPrincipal();
+
+        principalBasedAcMgr = (JackrabbitAccessControlManager) 
getPrincipalBasedAuthorizationConfiguration().getAccessControlManager(root, 
getNamePathMapper());
+        compositeAcMgr = (JackrabbitAccessControlManager) 
getConfig(AuthorizationConfiguration.class).getAccessControlManager(root, 
getNamePathMapper());
+
+        Tree testTree = TreeUtil.addChild(root.getTree(PathUtils.ROOT_PATH), 
"test", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+        testPath = getNamePathMapper().getJcrPath(testTree.getPath());
+        root.commit();
+    }
+
+    @After
+    @Override
+    public void after() throws Exception {
+        try {
+            root.getTree(testPath).remove();
+            root.commit();
+        } finally {
+            super.after();
+        }
+    }
+
+    @Test
+    public void testApplicablePoliciesSupportedPrincipal() throws Exception {
+        AccessControlPolicy[] applicable = 
principalBasedAcMgr.getApplicablePolicies(supportedPrincipal);
+        assertEquals(-1 /*EXERCISE: fix assertion */, applicable.length);
+        assertTrue(applicable[0] instanceof PrincipalAccessControlList);
+
+        applicable = compositeAcMgr.getApplicablePolicies(supportedPrincipal);
+        assertEquals(-1 /*EXERCISE: fix assertion */, applicable.length);
+
+        // EXERCISE: inspect the applicable policies and write assertions
+        // EXERCISE: explain the difference between the composite setup and 
the principal-based-only access control manager.
+    }
+
+    @Test
+    public void testApplicablePoliciesUnsupportedPrincipal() throws Exception {
+        AccessControlPolicy[] applicable = 
principalBasedAcMgr.getApplicablePolicies(unsupportedPrincipal);
+        assertEquals(-1 /*EXERCISE: fix assertion */, applicable.length);
+
+        applicable = 
compositeAcMgr.getApplicablePolicies(unsupportedPrincipal);
+        assertEquals(-1 /*EXERCISE: fix assertion */, applicable.length);
+
+        // EXERCISE: inspect the applicable policies and write test-assertions
+        // EXERCISE: explain the difference between the composite setup and 
the principal-based-only access control manager.
+    }
+
+    @Test
+    public void testApplicablePoliciesByPath() throws Exception {
+        Iterator<AccessControlPolicy> applicable = 
principalBasedAcMgr.getApplicablePolicies(testPath);
+        assertEquals(null /*EXERCISE: complete assertion */, 
applicable.hasNext());
+
+        applicable = compositeAcMgr.getApplicablePolicies(testPath);
+        assertEquals(null /*EXERCISE: complete assertion */, 
applicable.hasNext());
+
+        // EXERCISE: inspect the available applicable policies
+        // EXERCISE: explain the difference between the composite setup and 
the principal-based-only access control manager.
+    }
+
+    @Test
+    public void testEditAccssControl() throws Exception {
+        PrincipalAccessControlList acl = 
getApplicablePrincipalAccessControlList(compositeAcMgr, supportedPrincipal);
+        assertNotNull(acl);
+
+        // EXERCISE: modify the PrincipalAccessControlList such that the test 
passes.
+        // EXERCISE: can you identify an alternative way to edit the access 
control entries?
+        compositeAcMgr.setPolicy(acl.getPath(), acl);
+        root.commit();
+
+        try (ContentSession cs = getTestSession(supportedPrincipal)) {
+            Root testRoot = cs.getLatestRoot();
+            assertTrue(testRoot.getTree(testPath).exists());
+        }
+    }
+
+    @Test
+    public void testEditAccssControl2() throws Exception {
+        // EXERCISE: Obtain the applicable policy that results in effective 
permissions for the Subject containing
+        //           both the supportedPrincipal and unsupportedPrincipal
+        JackrabbitAccessControlList acl = null; // EXERCISE
+        acl.addEntry(supportedPrincipal, 
privilegesFromNames(PrivilegeConstants.JCR_READ), true,
+                ImmutableMap.of(AccessControlConstants.REP_NODE_PATH, 
getValueFactory(root).createValue(testPath)));
+        compositeAcMgr.setPolicy(acl.getPath(), acl);
+        root.commit();
+
+        // EXERCISE: Can you identify another way of obtaining _and_ modifying 
the access control setup to achieve
+        //           the same effective setup?
+
+        try (ContentSession cs = getTestSession(supportedPrincipal, 
unsupportedPrincipal)) {
+            Root testRoot = cs.getLatestRoot();
+            assertTrue(testRoot.getTree(testPath).exists());
+        }
+    }
+
+    @Test
+    public void testEffectivePolicies() throws Exception {
+        JackrabbitAccessControlList acl = 
checkNotNull(AccessControlUtils.getAccessControlList(compositeAcMgr, testPath));
+        acl.addAccessControlEntry(supportedPrincipal, 
privilegesFromNames(PrivilegeConstants.JCR_REMOVE_CHILD_NODES));
+        acl.addAccessControlEntry(unsupportedPrincipal, 
privilegesFromNames(PrivilegeConstants.JCR_MODIFY_PROPERTIES));
+        compositeAcMgr.setPolicy(acl.getPath(), acl);
+
+        PrincipalAccessControlList pacl = 
checkNotNull(getApplicablePrincipalAccessControlList(compositeAcMgr, 
supportedPrincipal));
+        pacl.addEntry(testPath, 
privilegesFromNames(PrivilegeConstants.JCR_ADD_CHILD_NODES));
+        compositeAcMgr.setPolicy(pacl.getPath(), pacl);
+        root.commit();
+
+        // 1. get effective policies for just 'supportedPrincipal'
+
+        // EXERCISE: what is the expected result? verify by filling in the 
missing assertions.
+        AccessControlPolicy[] effective = 
compositeAcMgr.getEffectivePolicies(ImmutableSet.of(supportedPrincipal));
+        assertEquals(-1 /*EXERCISE*/, effective.length);
+        // EXERCISE: inspect the nature of the policies
+
+        assertTrue(effective[0] instanceof AccessControlList);
+        AccessControlEntry[] entries = ((AccessControlList) 
effective[0]).getAccessControlEntries();
+        assertEquals(-1 /*EXERCISE*/, entries.length);
+        assertArrayEquals(null /*EXERCISE*/, entries[0].getPrivileges());
+        // EXERCISE: inspect the entries. where do they take effect?
+
+        // 2. get effective policies for the set containing both 
'supportedPrincipal' and 'unsupportedPrincipal'
+
+        // EXERCISE: what is the expected result? verify it by filling in the 
missing assertions.
+        effective = 
compositeAcMgr.getEffectivePolicies(ImmutableSet.of(supportedPrincipal, 
unsupportedPrincipal));
+        assertEquals(-1 /*EXERCISE*/, effective.length);
+        // EXERCISE: inspect the nature of the policies
+
+        assertTrue(effective[0] instanceof AccessControlList);
+        entries = ((AccessControlList) effective[0]).getAccessControlEntries();
+        assertEquals(-1 /*EXERCISE*/, entries.length);
+        assertArrayEquals(null /*EXERCISE*/, entries[0].getPrivileges());
+        // EXERCISE: inspect the entries. where do they take effect?
+    }
+
+    @Test
+    public void testEffectivePoliciesByPath() throws Exception {
+        JackrabbitAccessControlList acl = 
checkNotNull(AccessControlUtils.getAccessControlList(compositeAcMgr, testPath));
+        acl.addAccessControlEntry(unsupportedPrincipal, 
privilegesFromNames(PrivilegeConstants.REP_REMOVE_PROPERTIES));
+        compositeAcMgr.setPolicy(acl.getPath(), acl);
+
+        PrincipalAccessControlList pacl = 
checkNotNull(getApplicablePrincipalAccessControlList(compositeAcMgr, 
supportedPrincipal));
+        pacl.addEntry(testPath, 
privilegesFromNames(PrivilegeConstants.REP_ADD_PROPERTIES));
+        compositeAcMgr.setPolicy(pacl.getPath(), pacl);
+        root.commit();
+
+        // notice, that effective policies are accessed by path!
+        AccessControlPolicy[] effective = 
compositeAcMgr.getEffectivePolicies(testPath);
+        assertEquals(-1 /*EXERCISE*/, effective.length);
+        // EXERCISE: inspect the policies
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L2_AccessControlManagementTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L3_PermissionEvaluationTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L3_PermissionEvaluationTest.java?rev=1882944&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L3_PermissionEvaluationTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L3_PermissionEvaluationTest.java
 Wed Oct 28 16:37:04 2020
@@ -0,0 +1,229 @@
+/*
+ * 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.exercise.security.authorization.principalbased;
+
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
+import 
org.apache.jackrabbit.api.security.authorization.PrincipalAccessControlList;
+import 
org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.api.ContentSession;
+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.TreeUtil;
+import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
+import org.jetbrains.annotations.NotNull;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.security.Principal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_MODIFY_PROPERTIES;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_READ;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_READ_ACCESS_CONTROL;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_WRITE;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_ADD_PROPERTIES;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_READ_NODES;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_READ_PROPERTIES;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_REMOVE_PROPERTIES;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * <pre>
+ * Module: Principal-Based Authorization
+ * 
=============================================================================
+ *
+ * Title: Permission Evaluation with Principal-Based Authorization
+ * 
-----------------------------------------------------------------------------
+ *
+ * Goal:
+ * Learn how effective permissions are being evaluation in a composite setup 
that includes both principal-based and
+ * path based authorization.
+ *
+ * Reading:
+ * 
http://jackrabbit.apache.org/oak/docs/security/authorization/principalbased.html#details_permission_eval
+ * 
http://jackrabbit.apache.org/oak/docs/security/authorization/principalbased.html#details_aggregationfilter
+ *
+ * Exercises:
+ *
+ * - {@link #testPermissions()}: defined the list of principals whose 
effective permission make the test pass
+ *   Question: Are the other combinations of principals with the same effect?
+ *             Can you explain the test and the permission evaluation for this 
test case?
+ *
+ * - {@link #testPermissions2()}: fix the assertions for the given content 
session and explain the result
+ *
+ * - {@link #testPermissions3()}: defined the list of principals whose 
effective permission make the test pass
+ * - {@link #testPermissions4()}: defined the list of principals whose 
effective permission make the test pass
+ *   Question: Can you explain the main difference between the two tests?
+ *
+ * - {@link #testPermissions5()}:
+ *
+ * - {@link #testReadablePaths()}: fill in a path that with the current setup 
is always readable.
+ *   Question: How many alternative paths would make the test pass?
+ *   Question: Discuss what changes to the authorization setup would be needed 
to have a different set of paths marked as readable.
+ *
+ * </pre>
+ */
+public class L3_PermissionEvaluationTest extends AbstractPrincipalBasedTest {
+
+    private Principal systemUserPrincipal1;
+    private Principal systemUserPrincipal2;
+    private Principal userPrincipal;
+    private Principal groupPrincipal;
+
+    private String testPath;
+
+    @Before
+    @Override
+    public void before() throws Exception {
+        super.before();
+
+        systemUserPrincipal1 = getSystemUserPrincipal("systemUser1", 
getSupportedIntermediatePath());
+        systemUserPrincipal2 = getSystemUserPrincipal("systemUser2", 
getSupportedIntermediatePath());
+        userPrincipal = getRegularUserPrincipal();
+        groupPrincipal = getGroupPrincipal();
+
+        Tree testTree = TreeUtil.addChild(root.getTree(PathUtils.ROOT_PATH), 
"test", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+        testTree.setProperty("prop", "value");
+
+        testPath = getNamePathMapper().getJcrPath(testTree.getPath());
+
+        setupAccessControl();
+        root.commit();
+    }
+
+    @After
+    @Override
+    public void after() throws Exception {
+        try {
+            root.getTree(testPath).remove();
+            root.commit();
+        } finally {
+            super.after();
+        }
+    }
+
+    private void setupAccessControl() throws Exception {
+        JackrabbitAccessControlManager compositeAcMgr = 
(JackrabbitAccessControlManager) 
getConfig(AuthorizationConfiguration.class).getAccessControlManager(root, 
getNamePathMapper());
+
+        PrincipalAccessControlList pacl = 
checkNotNull(getApplicablePrincipalAccessControlList(compositeAcMgr, 
systemUserPrincipal1));
+        pacl.addEntry(testPath, privilegesFromNames(REP_READ_NODES));
+        compositeAcMgr.setPolicy(pacl.getPath(), pacl);
+
+        pacl = 
checkNotNull(getApplicablePrincipalAccessControlList(compositeAcMgr, 
systemUserPrincipal2));
+        pacl.addEntry(testPath, privilegesFromNames(REP_READ_PROPERTIES, 
REP_ADD_PROPERTIES));
+        compositeAcMgr.setPolicy(pacl.getPath(), pacl);
+
+        JackrabbitAccessControlList acl = 
AccessControlUtils.getAccessControlList(compositeAcMgr, testPath);
+        acl.addAccessControlEntry(groupPrincipal, 
privilegesFromNames(JCR_READ));
+        acl.addAccessControlEntry(systemUserPrincipal1, 
privilegesFromNames(JCR_WRITE));
+        acl.addAccessControlEntry(systemUserPrincipal2, 
privilegesFromNames(JCR_READ_ACCESS_CONTROL));
+        acl.addEntry(userPrincipal, 
privilegesFromNames(REP_REMOVE_PROPERTIES), false);
+        compositeAcMgr.setPolicy(acl.getPath(), acl);
+    }
+
+    @NotNull
+    private PermissionProvider getPermissionProvider(@NotNull ContentSession 
cs) {
+        return 
getConfig(AuthorizationConfiguration.class).getPermissionProvider(cs.getLatestRoot(),
 cs.getWorkspaceName(), cs.getAuthInfo().getPrincipals());
+    }
+
+    @Test
+    public void testPermissions() throws Exception {
+        try (ContentSession cs = getTestSession(/*EXERCISE: add principals 
such that the test passes */)) {
+            Root r = cs.getLatestRoot();
+            assertTrue(r.getTree(testPath).exists());
+            assertFalse(r.getTree(testPath).hasProperty("prop"));
+        }
+    }
+
+    @Test
+    public void testPermissions2() throws Exception {
+        try (ContentSession cs = getTestSession(systemUserPrincipal1, 
systemUserPrincipal2)) {
+            PermissionProvider pp = getPermissionProvider(cs);
+
+            Tree t = cs.getLatestRoot().getTree(testPath);
+
+            // EXERCISE: fix the assertions and explain the result
+            assertEquals(null /*EXERCISE */, t.exists());
+            assertEquals(null /*EXERCISE */, 
t.hasChild(AccessControlConstants.REP_POLICY));
+            assertEquals(null /*EXERCISE */, t.hasProperty("prop"));
+
+            assertEquals(null /*EXERCISE */, pp.hasPrivileges(t, 
JCR_READ_ACCESS_CONTROL));
+            assertEquals(null /*EXERCISE */, pp.hasPrivileges(t, JCR_WRITE));
+            assertEquals(null /*EXERCISE */, pp.hasPrivileges(t, 
JCR_MODIFY_PROPERTIES));
+            assertEquals(null /*EXERCISE */, pp.hasPrivileges(t, 
REP_ADD_PROPERTIES));
+        }
+    }
+
+    @Test
+    public void testPermissions3() throws Exception {
+        try (ContentSession cs = getTestSession(/*EXERCISE: add principals 
such that the test passes */)) {
+            Tree t = cs.getLatestRoot().getTree(testPath);
+            assertTrue(t.exists());
+            assertTrue(t.hasProperty("prop"));
+            assertTrue(t.hasChild(AccessControlConstants.REP_POLICY));
+            assertFalse(getPermissionProvider(cs).hasPrivileges(t, JCR_WRITE));
+        }
+    }
+
+    @Test
+    public void testPermissions4() throws Exception {
+        try (ContentSession cs = getTestSession(/*EXERCISE: add principals 
such that the test passes */)) {
+            Tree t = cs.getLatestRoot().getTree(testPath);
+            assertTrue(t.exists());
+            assertTrue(t.hasProperty("prop"));
+            assertFalse(t.hasChild(AccessControlConstants.REP_POLICY));
+
+            PermissionProvider pp = getPermissionProvider(cs);
+            assertTrue(pp.hasPrivileges(t, REP_ADD_PROPERTIES));
+            assertFalse(pp.hasPrivileges(t, REP_REMOVE_PROPERTIES));
+        }
+    }
+
+    @Test
+    public void testPermissions5() throws Exception {
+        try (ContentSession cs = getTestSession(systemUserPrincipal1, 
groupPrincipal)) {
+            PermissionProvider pp = getPermissionProvider(cs);
+
+            Tree t = cs.getLatestRoot().getTree(testPath);
+
+            // EXERCISE: fix the assertions and explain the result
+            assertEquals(null /*EXERCISE */, t.exists());
+            assertEquals(null /*EXERCISE */, 
t.hasChild(AccessControlConstants.REP_POLICY));
+            assertEquals(null /*EXERCISE */, t.hasProperty("prop"));
+
+            assertEquals(null /*EXERCISE */, pp.hasPrivileges(t, 
JCR_READ_ACCESS_CONTROL));
+            assertEquals(null /*EXERCISE */, pp.hasPrivileges(t, JCR_WRITE));
+            assertEquals(null /*EXERCISE */, pp.hasPrivileges(t, 
REP_REMOVE_PROPERTIES));
+        }
+    }
+
+    @Test
+    public void testReadablePaths() throws Exception {
+        try (ContentSession cs = getTestSession(systemUserPrincipal1, 
systemUserPrincipal2)) {
+            String readablePath = null; // EXERCISE: enter a path that is 
always readable for the given 2 principals
+            assertTrue(cs.getLatestRoot().getTree(readablePath).exists());
+        }
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L3_PermissionEvaluationTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L4_DisabledAggregationFilterTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L4_DisabledAggregationFilterTest.java?rev=1882944&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L4_DisabledAggregationFilterTest.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L4_DisabledAggregationFilterTest.java
 Wed Oct 28 16:37:04 2020
@@ -0,0 +1,172 @@
+/*
+ * 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.exercise.security.authorization.principalbased;
+
+import com.google.common.collect.ImmutableSet;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
+import 
org.apache.jackrabbit.api.security.authorization.PrincipalAccessControlList;
+import 
org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.PathUtils;
+import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
+import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
+import 
org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
+import org.jetbrains.annotations.NotNull;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import javax.jcr.security.AccessControlPolicy;
+import java.security.Principal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_MODIFY_PROPERTIES;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_READ_ACCESS_CONTROL;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_WRITE;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_ADD_PROPERTIES;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_READ_NODES;
+import static 
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.REP_READ_PROPERTIES;
+import static org.junit.Assert.assertEquals;
+
+/**
+ * <pre>
+ * Module: Principal-Based Authorization
+ * 
=============================================================================
+ *
+ * Title: Effect of AggregationFilter
+ * 
-----------------------------------------------------------------------------
+ *
+ * Goal:
+ * All previous exercises had the AggregationFilter enabled. The following 
test will illustrate the behavior of the
+ * composite permission provider, if the filter was disabled.
+ *
+ * Reading:
+ * 
https://jackrabbit.apache.org/oak/docs/security/authorization/composite.html#AggregationFilter
+ * 
http://jackrabbit.apache.org/oak/docs/security/authorization/principalbased.html#details_aggregationfilter
+ *
+ * Exercises:
+ *
+ * - {@link #testPermissions()}: complete the assertions to make the test case 
pass and compare the results with the
+ *                               previous lession. Explain the difference and 
discuss the benefits of enabling the filter.
+ *
+ * - {@link #testEffectivePolicies()}: fix the assertion and explain the 
result (compared to previous exercises)
+ *   Question: How do the effective policies explain the outcome of the 
permission evaluation?
+ *
+ * Advanced Exercise:
+ * 
-----------------------------------------------------------------------------
+ *
+ * - Change the {@link #getCompositionType()} to OR and observe how it changes 
the effective permissions.
+ *   Explain your findings.
+ *
+ * </pre>
+ */
+public class L4_DisabledAggregationFilterTest extends 
AbstractPrincipalBasedTest {
+
+    private Principal supportedPrincipal1;
+    private Principal supportedPrincipal2;
+
+    private String testPath;
+
+    @Before
+    @Override
+    public void before() throws Exception {
+        super.before();
+
+        supportedPrincipal1 = getSystemUserPrincipal("systemUser1", 
getSupportedIntermediatePath());
+        supportedPrincipal2 = getSystemUserPrincipal("systemUser2", 
getSupportedIntermediatePath());
+
+        Tree testTree = TreeUtil.addChild(root.getTree(PathUtils.ROOT_PATH), 
"test", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+        testTree.setProperty("prop", "value");
+
+        testPath = getNamePathMapper().getJcrPath(testTree.getPath());
+
+        setupAccessControl();
+        root.commit();
+    }
+
+    @After
+    @Override
+    public void after() throws Exception {
+        try {
+            root.getTree(testPath).remove();
+            root.commit();
+        } finally {
+            super.after();
+        }
+    }
+
+    @Override
+    boolean enableAggregationFilter() {
+        return false;
+    }
+
+    private void setupAccessControl() throws Exception {
+        JackrabbitAccessControlManager compositeAcMgr = 
(JackrabbitAccessControlManager) 
getConfig(AuthorizationConfiguration.class).getAccessControlManager(root, 
getNamePathMapper());
+
+        PrincipalAccessControlList pacl = 
checkNotNull(getApplicablePrincipalAccessControlList(compositeAcMgr, 
supportedPrincipal1));
+        pacl.addEntry(testPath, privilegesFromNames(REP_READ_NODES));
+        compositeAcMgr.setPolicy(pacl.getPath(), pacl);
+
+        pacl = 
checkNotNull(getApplicablePrincipalAccessControlList(compositeAcMgr, 
supportedPrincipal2));
+        pacl.addEntry(testPath, privilegesFromNames(REP_READ_PROPERTIES, 
REP_ADD_PROPERTIES));
+        compositeAcMgr.setPolicy(pacl.getPath(), pacl);
+
+        JackrabbitAccessControlList acl = 
AccessControlUtils.getAccessControlList(compositeAcMgr, testPath);
+        acl.addAccessControlEntry(supportedPrincipal1, 
privilegesFromNames(JCR_WRITE));
+        acl.addAccessControlEntry(supportedPrincipal2, 
privilegesFromNames(JCR_READ_ACCESS_CONTROL));
+        compositeAcMgr.setPolicy(acl.getPath(), acl);
+    }
+
+    @NotNull
+    private PermissionProvider getPermissionProvider(@NotNull ContentSession 
cs) {
+        return 
getConfig(AuthorizationConfiguration.class).getPermissionProvider(cs.getLatestRoot(),
 cs.getWorkspaceName(), cs.getAuthInfo().getPrincipals());
+    }
+
+    @Test
+    public void testPermissions() throws Exception {
+        try (ContentSession cs = getTestSession(supportedPrincipal1, 
supportedPrincipal2)) {
+            PermissionProvider pp = getPermissionProvider(cs);
+
+            Tree t = cs.getLatestRoot().getTree(testPath);
+
+            // EXERCISE: fix the assertions and explain the result
+            assertEquals(null /*EXERCISE */, t.exists());
+            assertEquals(null /*EXERCISE */, 
t.hasChild(AccessControlConstants.REP_POLICY));
+            assertEquals(null /*EXERCISE */, t.hasProperty("prop"));
+
+            assertEquals(null /*EXERCISE */, pp.hasPrivileges(t, 
JCR_READ_ACCESS_CONTROL));
+            assertEquals(null /*EXERCISE */, pp.hasPrivileges(t, JCR_WRITE));
+            assertEquals(null /*EXERCISE */, pp.hasPrivileges(t, 
JCR_MODIFY_PROPERTIES));
+            assertEquals(null /*EXERCISE */, pp.hasPrivileges(t, 
REP_ADD_PROPERTIES));
+
+            assertEquals(ImmutableSet.of(/*EXERCISE */), pp.getPrivileges(t));
+        }
+    }
+
+    @Test
+    public void testEffectivePolicies() throws Exception {
+        JackrabbitAccessControlManager compositeAcMgr = 
(JackrabbitAccessControlManager) 
getConfig(AuthorizationConfiguration.class).getAccessControlManager(root, 
getNamePathMapper());
+        AccessControlPolicy[] effectivePolicies = 
compositeAcMgr.getEffectivePolicies(ImmutableSet.of(supportedPrincipal1, 
supportedPrincipal2));
+
+        // EXERCISE: inspect the effective policies and explain the result
+        assertEquals(-1 /*EXERCISE*/, effectivePolicies.length);
+    }
+}
\ No newline at end of file

Propchange: 
jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/principalbased/L4_DisabledAggregationFilterTest.java
------------------------------------------------------------------------------
    svn:eol-style = native


Reply via email to