diff --git a/README.md b/README.md index 77a7e71..a07f706 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ The Access Control Validator provides an easy to use tool for testers and develo Features: * Easy-to-read Yaml configuration file format * Page and user management tests +* Testing of systemusers (since v1.0.2) * Run mode support * Health checks * Service API @@ -29,6 +30,8 @@ Therefore the tool temporarily creates a testuser, makes it member of the group This not only makes testing more thorough but also allows to define additional parameters in the respective test definition like e.g. a template when testing if a page can be creates under a certain path of a property name which will be used when testing if modification of a page is possible. +Also systemuser permission can be tested using the Tool. In that case a testuser creation is not needed. Instead the tool uses an administrative session impersonating the systemuser of interest. In order for this to work, the accescontrolvalidator bundle is whitelisted via OSGi configuration. + The tool does not leave any test content in the repository such as the testuser, or modified properties, by either not persisting any changes or if this can not be avoided, deletes them when the test is done. ## Run Mode Support diff --git a/accesscontrolvalidator-bundle/src/main/java/biz/netcentric/aem/tools/acvalidator/model/AcTestSet.java b/accesscontrolvalidator-bundle/src/main/java/biz/netcentric/aem/tools/acvalidator/model/AcTestSet.java index fd15e7d..3d56a0d 100644 --- a/accesscontrolvalidator-bundle/src/main/java/biz/netcentric/aem/tools/acvalidator/model/AcTestSet.java +++ b/accesscontrolvalidator-bundle/src/main/java/biz/netcentric/aem/tools/acvalidator/model/AcTestSet.java @@ -12,7 +12,10 @@ import java.util.List; import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.SimpleCredentials; +import org.apache.jackrabbit.api.security.user.Authorizable; import org.apache.jackrabbit.api.security.user.AuthorizableExistsException; import org.apache.jackrabbit.api.security.user.Group; import org.apache.jackrabbit.api.security.user.User; @@ -34,7 +37,7 @@ * */ public class AcTestSet { - + private final Logger LOG = LoggerFactory.getLogger(AcTestSet.class); @@ -57,7 +60,7 @@ public AcTestSet(String authorizableID, String pathToTestfile) { public void addAcTestCase(Testable testable){ this.acTestCase.add(testable); } - + public String getAuthorizableID(){ return this.authorizableID; } @@ -72,7 +75,7 @@ public String getAuthorizableID(){ public List isOk(ServiceResourceResolverService serviceResourceResolverService) throws RepositoryException, LoginException { List resultList = new ArrayList<>(); User testuser = null; - Group testGroup = null; + Authorizable authorizableToTest = null; ResourceResolver serviceResourcerResolver = null; ResourceResolver testUserResolver = null; try { @@ -80,33 +83,37 @@ public List isOk(ServiceResourceResolverService serviceResourceResol serviceResourcerResolver = serviceResourceResolverService.getServiceResourceResolver(); UserManager userManager = getUserManager(serviceResourcerResolver); - - testuser = userManager.createUser(ACVALIDATOR_TESTUSER_ID, ACVALIDATOR_TESTUSER_PASSWORD); - testGroup = getTestGroup(getUserManager(serviceResourcerResolver), authorizableID, testuser); - - // we need to persist the created testuser in order to be able to get a resolver for him - serviceResourcerResolver.commit(); - LOG.debug("comitting serviceResourcerResolver to persist testuser"); - // create ResourceResolver for the testuser based on his permissions - testUserResolver = serviceResourceResolverService.getTestUserResourceResolver(ACVALIDATOR_TESTUSER_ID, ACVALIDATOR_TESTUSER_PASSWORD); - + boolean isSystemUser = !userManager.getAuthorizable(authorizableID).isGroup(); + if (isSystemUser) { + testUserResolver = serviceResourceResolverService.getSystemUserResourceResolver(authorizableID); + authorizableToTest = userManager.getAuthorizable(authorizableID); + } else { + testuser = userManager.createUser(ACVALIDATOR_TESTUSER_ID, ACVALIDATOR_TESTUSER_PASSWORD); + authorizableToTest = getTestGroup(getUserManager(serviceResourcerResolver), authorizableID, testuser); + + // we need to persist the created testuser in order to be able to get a resolver for him + serviceResourcerResolver.commit(); + LOG.debug("comitting serviceResourcerResolver to persist testuser"); + // create ResourceResolver for the testuser based on his permissions + testUserResolver = serviceResourceResolverService.getTestUserResourceResolver(ACVALIDATOR_TESTUSER_ID, ACVALIDATOR_TESTUSER_PASSWORD); + } // execute all testcases for the testuser for(Testable testable: acTestCase){ - resultList.add(testable.isOk(serviceResourcerResolver, testUserResolver, testGroup)); + resultList.add(testable.isOk(serviceResourcerResolver, testUserResolver, authorizableToTest)); } } catch (PersistenceException e) { throw new RepositoryException(e); }finally{ // clean up temporary testuser - if(testGroup != null && testuser != null){ - testGroup.removeMember(testuser); + if(authorizableToTest != null && authorizableToTest instanceof Group && testuser != null){ + ((Group)authorizableToTest).removeMember(testuser); } if(testuser != null){ testuser.remove(); } - + // close resolvers - + if(testUserResolver != null){ testUserResolver.revert(); testUserResolver.close(); diff --git a/accesscontrolvalidator-bundle/src/main/java/biz/netcentric/aem/tools/acvalidator/serviceuser/ServiceResourceResolverService.java b/accesscontrolvalidator-bundle/src/main/java/biz/netcentric/aem/tools/acvalidator/serviceuser/ServiceResourceResolverService.java index 741f4ca..c8d0f90 100644 --- a/accesscontrolvalidator-bundle/src/main/java/biz/netcentric/aem/tools/acvalidator/serviceuser/ServiceResourceResolverService.java +++ b/accesscontrolvalidator-bundle/src/main/java/biz/netcentric/aem/tools/acvalidator/serviceuser/ServiceResourceResolverService.java @@ -35,4 +35,7 @@ public interface ServiceResourceResolverService { ResourceResolver getTestUserResourceResolver(String username, String password) throws LoginException; + + ResourceResolver getSystemUserResourceResolver(String authorizableID); + } diff --git a/accesscontrolvalidator-bundle/src/main/java/biz/netcentric/aem/tools/acvalidator/serviceuser/ServiceResourceResolverServiceImpl.java b/accesscontrolvalidator-bundle/src/main/java/biz/netcentric/aem/tools/acvalidator/serviceuser/ServiceResourceResolverServiceImpl.java index b9a1475..f9c5eea 100644 --- a/accesscontrolvalidator-bundle/src/main/java/biz/netcentric/aem/tools/acvalidator/serviceuser/ServiceResourceResolverServiceImpl.java +++ b/accesscontrolvalidator-bundle/src/main/java/biz/netcentric/aem/tools/acvalidator/serviceuser/ServiceResourceResolverServiceImpl.java @@ -8,6 +8,7 @@ */ package biz.netcentric.aem.tools.acvalidator.serviceuser; +import java.util.Collections; import java.util.HashMap; import java.util.Map; @@ -35,9 +36,9 @@ public class ServiceResourceResolverServiceImpl implements ServiceResourceResolv @Reference ResourceResolverFactory resourceResolverFactory; - + @Reference - SlingRepository repository; + SlingRepository repository; @Override public ResourceResolver getServiceResourceResolver() throws LoginException { @@ -51,13 +52,37 @@ public Session getUserSession(SimpleCredentials credentials) throws javax.jcr.Lo javax.jcr.Session session = repository.login(credentials); return session; } - + @Override public ResourceResolver getTestUserResourceResolver(String username, String password) throws LoginException { final Map authenticationInfo = new HashMap<>(); authenticationInfo.put(ResourceResolverFactory.USER, username); - authenticationInfo.put(ResourceResolverFactory.PASSWORD, password.toCharArray()); + authenticationInfo.put(ResourceResolverFactory.PASSWORD, password.toCharArray()); return resourceResolverFactory.getResourceResolver(authenticationInfo); } + @Override + public ResourceResolver getSystemUserResourceResolver(String authorizableID) { + ResourceResolver adminResolver = null; + Session systemUserSession = null; + try { + try { + adminResolver = resourceResolverFactory.getAdministrativeResourceResolver(null); + Session adminSession = adminResolver.adaptTo(Session.class); + if(adminSession == null) { + throw new IllegalStateException("Could not adapt ResourceResolver to Session!"); + } + systemUserSession = adminSession.impersonate(new SimpleCredentials(authorizableID, new char[0])); + return resourceResolverFactory.getResourceResolver(Collections.singletonMap("user.jcr.session", (Object) systemUserSession)); + } catch (RepositoryException | LoginException e) { + throw new IllegalStateException(e); + } + } finally { + if(adminResolver != null) { + adminResolver.close(); + } + } + + } + } diff --git a/accesscontrolvalidator-package/src/main/jcr_root/apps/netcentric/acvalidator/config/org.apache.sling.jcr.base.internal.LoginAdminWhitelist.fragment-accesscontrolvalidator.config b/accesscontrolvalidator-package/src/main/jcr_root/apps/netcentric/acvalidator/config/org.apache.sling.jcr.base.internal.LoginAdminWhitelist.fragment-accesscontrolvalidator.config new file mode 100644 index 0000000..8b430a1 --- /dev/null +++ b/accesscontrolvalidator-package/src/main/jcr_root/apps/netcentric/acvalidator/config/org.apache.sling.jcr.base.internal.LoginAdminWhitelist.fragment-accesscontrolvalidator.config @@ -0,0 +1,2 @@ +whitelist.name="accesscontrolvalidator" +whitelist.bundles=[ "biz.netcentric.aem.tools.accesscontrolvalidator.bundle" ] \ No newline at end of file diff --git a/docs/testfiles.md b/docs/testfiles.md index e64f183..441df2a 100644 --- a/docs/testfiles.md +++ b/docs/testfiles.md @@ -1,6 +1,6 @@ ## Overall structure a of an AC test definition file -Every testfile comprises one or more variables section(s) (optional) and a „tests“ section. Inside, there can be testcases for one or more groups. Inside a group block a group for wich tescases should be executed gets defined by the respective groupID. Inside each group block, there can be page related testcases inside a „pages“ block and user/group related testcases inside a „useradmin“ block. +Every testfile comprises one or more variables section(s) (optional) and a „tests“ section. Inside, there can be testcases for one or more groups/systemuser. A group/systemuser for wich testcases should be executed gets defined by the respective ID. Inside each block, there can be page related testcases inside a „pages“ block and user/group related testcases inside a „useradmin“ block. So here’s the overall structure: ``` @@ -12,13 +12,13 @@ So here’s the overall structure: - tests: - - group1: + - group/systemuser 1: - pages: (testcases) - useradmin: (testcases) - - group n: + - group/systemuser n: ... ```