[ https://issues.apache.org/jira/browse/OAK-7997?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16748049#comment-16748049 ]
angela commented on OAK-7997: ----------------------------- [~snj], i extracted a test case based on your description (directly operating on oak QueryEngine and oak API for simplicity) and i added some additional variants: a) your case: single policy on /node with single entry + rep:glob restriction with empty value => unexpected result b) policy on /node (allow) and another policy on /node/subnode (deny) => expected result (but obviously not practical in real life... just for the limited test-setup that's equivalent) and while writing the summary i noticed a potential reason for the failure in a): with the ""-rep:glob we not only deny access to the child node but also to all properties of /node because the glob restriction is just a simple path-matching and doesn't differentiate between child properties and child nodes. to illustrate this (and because I suspect that the query looks at jcr:primaryType property) i added yet another test case c) same as a) but additionally granting property-read at /node/jcr:primaryType => expected result. that's just for an initial illustration. i don't think that extra entry should be needed because in the JCR API implementation in Oak we added some extra logic to make sure a Node and its primary type information is accessible even if the {{jcr:primaryType}} property is not. So, with your setup {{Session.getNode("/node")}} succeeds and I think so does {{Session.getNode("/node").getPrimaryNodeType()}}. but afaik {{Session.getNode("/node").getProperty("jcr:primaryType")}} and {{Session.getProperty("/node/jcr:primaryType")}} will fail because your test-session doesn't have the ability to read that property because of the ""-glob-restriction. what i didn't find out until now is where exactly the query engine misses (skips) the result and if it's really because of the primary-type property...the only thing i found was {{org.apache.jackrabbit.oak.query.index.FilterImpl.isAccessible(String path)}} but somehow i never got there when debugging. that's what i will next (and reach out to the query team in case i get stuck)... more tomorrow. > Adding restrictions to ACLs yields empty results for queries in Jackrabbit Oak > ------------------------------------------------------------------------------ > > Key: OAK-7997 > URL: https://issues.apache.org/jira/browse/OAK-7997 > Project: Jackrabbit Oak > Issue Type: Bug > Components: query, security > Affects Versions: 1.10.0, 1.8.10 > Reporter: Søren Jensen > Priority: Major > Attachments: OAK-7997.patch > > > Using Jackrabbit Oak, I've been attempting to configure security through > {{SecurityProvider}} and {{SecurityConfiguration's. In particular, I've been > using the restrictions which generally works as expected. However, when > dealing with JCR-SQL2}} queries, more gets filtered out than expected. > *Details* > It can be reproduced with the repository below. > {code:java} > / > node [nt:unstructured] > subnode [nt:unstructured] {code} > On {{node}}, I add an access control entry with privilege {{JCR_ALL}} for > "{{user"}} together with a restriction for {{rep:glob}} -> {{""}}, such that > {{user}} do not have access to any children of {{node - in this case, only > subnode}}. > It works as expected when using {{session.getNode}}: > * {{session.getNode("/node")}} returns the node > * {{session.getNode("/node/subnode")}} throws {{PathNotFoundException}} as > expected due to the restriction. > However, when I execute the following {{JCR-SQL2}} query: > {code:java} > SELECT * FROM [nt:unstructured]{code} > I get *no results back*. Here I would have expected to get {{/node}}, as it > is otherwise available when using {{session.getNode}}. Removing the > restriction yields the expected result of both _/node_ and _/node/subnode_. > As discussed with [~anchela] on the _users_ mailing list, this may either be > an actual bug, or it is a conscious decision - in which case it would be nice > to have it documented for the security. > *Code for reproducing:* > The code for reproducing the error is shown below. The "_restrictions"_ map > below seems to be the problem, as this is what results in both _/node_ and > _/node/subnode_ being filtered out. > > {code:java} > public static void main(String[] args) throws Exception { > Repository repository = new Jcr().with(new > MySecurityProvider()).createRepository(); > Session session = repository.login(new UserIdCredentials("")); // > principal is "SystemPrincipal.INSTANCE" > // Create nodes > Node node = session.getRootNode().addNode("node", "nt:unstructured"); > node.addNode("subnode", "nt:unstructured"); > // Add access control entry + restriction > AccessControlManager acm = session.getAccessControlManager(); > JackrabbitAccessControlList acl = (JackrabbitAccessControlList) acm > .getApplicablePolicies("/node").nextAccessControlPolicy(); > Privilege[] privileges = new > Privilege[]{acm.privilegeFromName(Privilege.JCR_ALL)}; > Map<String, Value> restrictions = new HashMap<String, Value>() > {{put("rep:glob", new StringValue(""));}}; > acl.addEntry(new PrincipalImpl("user"), privileges, true, restrictions); > acm.setPolicy("/node", acl); > session.save(); > // executes query > RowIterator rows = repository.login(new > UserIdCredentials("user")).getWorkspace().getQueryManager() > .createQuery("SELECT * FROM [nt:unstructured]", > Query.JCR_SQL2).execute().getRows(); > System.out.println("Number of rows: " + rows.getSize()); //Prints 0 > } > {code} > *Code for security configuration:* > The above code makes use of "MySecurityProvider". I do not suspect this to be > the root cause, but please let me know if it can be helpful to have. The > security provider has the configuration set to > "ConfigurationParameters.EMPTY", and it uses all the default implementations > present within the Jackrabbit Oak project. The only exception is the > _AuthenticationConfiguration_ which uses a custom implementation using > pre-authentication: > > {code:java} > class MyAuthenticationConfiguration extends AuthenticationConfigurationImpl { > public MyAuthenticationConfiguration(SecurityProvider securityProvider) { > super(securityProvider); > } > @NotNull > @Override > public LoginContextProvider getLoginContextProvider(ContentRepository > contentRepository) { > return new LoginContextProvider() { > @NotNull > public LoginContext getLoginContext(Credentials credentials, > String workspaceName) { > String userId = ((UserIdCredentials) credentials).getUserId(); > Set<Principal> principalSets = new HashSet<>(); > if (userId.isEmpty()) { > principalSets.add(SystemPrincipal.INSTANCE); > } else { > principalSets.add(new PrincipalImpl(userId)); > } > Map<String, ? extends Principal> publicPrivileges = new > HashMap<>(); > AuthInfoImpl authInfoImpl = new AuthInfoImpl(userId, > publicPrivileges, principalSets); > Subject subject = new Subject(true, principalSets, > Collections.singleton(authInfoImpl), new HashSet<Principal>()); > return new PreAuthContext(subject); > } > }; > } > } > {code} > -- This message was sent by Atlassian JIRA (v7.6.3#76005)