How to get a List of Objects that a user can access using ACLs related tables
Asked Answered
R

2

8

I'm designing a system that has a lot of requirements around user management/permissions, so I decided to use Spring Security ACL to manage the permissions at the Domain Objects level.

Although, using ACLs to maintain the relations between Users and Entities force us to rely on that to present the data on the UI.

The PostFilter solution that is provided by Spring Security does a good job filtering the objects that a User can/cannot see but it has a big performance issue when we're dealing with an entity that has hundreds/thousands of entries, because we need to load everything from the database and then discard the objects that user isn't allowed to "see".

That problem is described here - SEC-2409 - but it'll take some time until the feature is available. So, I'm trying to find a workaround to use Spring Security ACL but avoid the performance issue.

I thought about implementing some code to retrieve the Objects that a User can access (after the authentication process) and keep that information available to be used on every request to allow the developers to use that info to perform the queries and not relying on the PostFilter.

In order to implement that, I'm trying to find a way to retrieve the list of permissions for a given principal/granted authority but I'm not able to find a way to do that with the available AclService implementations.

Example: aclService.getObjectIdentityList(<sid>,<acl_class>)

Note: The method should use the inheritance structure and include all the ObjectIdentities that are inherited from a parent entry

Any suggestion to get the data or another approach to solve this problem?


UPDATE

I already found a way to retrieve the List of objects that a User can access.

List<ObjectIdentity> childObjects = aclService.findChildren(objectIdentity);
Map<ObjectIdentity, Acl> result = aclService.readAclsById(childObjects, sids);

And this approach work for us, because we just have a few entities which the access is controlled by ACLs, so we can construct the list of ObjectsIdentities that a User has access.

Although, the Map that is being return, is returning all the ACLs for the ObjectIdentities that are being passed and then I need to check the if the user has access to each ObjectIdentity that is being returned.

Do you have an easy way to do this or to simplify all of this logic?

Redheaded answered 8/5, 2015 at 22:18 Comment(0)
C
2

The current approach to handling larger data sets is to update your query to include the currently logged in user within your query. For example, you can use Spring Security and Spring Data integration to update your query to refer to the current user:

@Query("select d from MyDomain d where d.owner = #{principal.name}")

Obviously this is not ideal because you need to manage the permissions manually. Once we resolve SEC-2409 Spring can do a lot of the heavy lifting for you automatically.

Clarethaclaretta answered 17/6, 2015 at 14:57 Comment(3)
Thanks for your answer @rob-winch But that approach forces me to keep that relation in the domain and lose the separation of concerns that Spring Security ACL is supposed to provide, right? Also, how would you manage that if you want to use the inheritance of ACLs?Redheaded
You are right this is not ideal. This is why we have the above JIRA. Unfortunately, until then this is the best solution we have.Clarethaclaretta
this doesn't work if you want to include users with access that are not the owners.Parthenogenesis
P
2

I ran into this question from needing a solution to deal with the lack of SEC-2409. Looking at JdbcAclService.findChildren() lead me to this

private final String FIND_OBJECTS_WITH_ACCESS = ""+
          "SELECT " +
          "    obj.object_id_identity AS obj_id, " +
          "    class.class AS class " +
          "FROM " +
          "    acl_object_identity obj, " +
          "    acl_class class, " +
          "    acl_entry entry " +
          "WHERE " +
          "    obj.object_id_class = class.id " +
          "    and entry.granting = true " +
          "    and entry.acl_object_identity = obj.id " +
          "    and entry.sid = (SELECT id FROM acl_sid WHERE sid = ?) " +
          "    and obj.object_id_class = (SELECT id FROM acl_class WHERE acl_class.class = ?) " +
          "GROUP BY " +
          "    obj.object_id_identity, " +
          "    class.class ";


public List<ObjectIdentity> getObjectsWithAccess(Class clazz, String sid) {
    Object[] args = { sid, clazz.getName() };
    List<ObjectIdentity> objects = _jdbcTemplate.query(FIND_OBJECTS_WITH_ACCESS, args, getRowMapper());
    return objects.size() == 0 ? null : objects;
}

private RowMapper<ObjectIdentity> getRowMapper() {
    return (rs, rowNum) -> {
        String javaType = rs.getString("class");
        Long identifier = rs.getLong("obj_id");
        return new ObjectIdentityImpl(javaType, identifier);
    };
}
Parthenogenesis answered 27/10, 2016 at 2:31 Comment(1)
Works great, although i have rewritten this query using JOIN clausesBollinger

© 2022 - 2024 — McMap. All rights reserved.