Uploaded image for project: 'Jackrabbit Oak'
  1. Jackrabbit Oak
  2. OAK-7997

Adding restrictions to ACLs yields empty results for queries in Jackrabbit Oak

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 1.10.0, 1.8.10
    • 1.12.0
    • query, security
    • None

    Description

      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.

      / 
        node      [nt:unstructured]
          subnode [nt:unstructured] 

      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:

      SELECT * FROM [nt:unstructured]

      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.

       

      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 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:

       

      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);
                  }
              };
          }
      }
      

       

      Attachments

        1. OAK-7997.patch
          9 kB
          Angela Schreiber
        2. OAK-7997_2.patch
          43 kB
          Angela Schreiber
        3. OAK-7997_3.patch
          37 kB
          Angela Schreiber
        4. OAK-7997-selectorimpl.patch
          6 kB
          Angela Schreiber

        Issue Links

          Activity

            People

              angela Angela Schreiber
              snj Søren Jensen
              Votes:
              0 Vote for this issue
              Watchers:
              5 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved: