Search code examples
spring-bootspring-securityspring-security-acl

MutableAcl.createAcl() with custom UserDetailsService


I am currently trying to implement Spring's ACLs into my existing application. Sadly i am stuck at a specific point which seems to be caused by my UserDetailsService.

The problem/error is the following when i call the createAcl() function of the MutableAcl class like this:

public void addPermission(long objectId, Sid recipient, Permission permission, Class clazz) {
    MutableAcl acl;
    ObjectIdentity oid = new ObjectIdentityImpl(clazz.getCanonicalName(), objectId);

    try {
        acl = (MutableAcl) mutableAclService.readAclById(oid);
    } catch (NotFoundException nfe) {
        acl = mutableAclService.createAcl(oid);
    }

    acl.insertAce(acl.getEntries().size(), permission, recipient, true);
    mutableAclService.updateAcl(acl);
}

Inside of this function a new ObjectIdentity is created, if this class instance does not yet have one. A new PrincipalSid is created from the current Authentication object for this purpose (saved inside the ACL_SID table). Like this:

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
PrincipalSid sid = new PrincipalSid(auth);
this.createObjectIdentity(objectIdentity, sid);

The problem occurs when it tries to save the entry into the ACL_SID table which is defined as this:

CREATE TABLE IF NOT EXISTS ACL_SID (
  id BIGSERIAL NOT NULL PRIMARY KEY,
  principal BOOLEAN NOT NULL,
  sid VARCHAR(100) NOT NULL,
  CONSTRAINT UNIQUE_UK_1 UNIQUE(sid,principal)
);

As you can see the sid is a VARCHAR with 100 characters. My custom User class contains a few properties which are mostly converted to a String representation, which causes the PrincipalSid to be longer than 100 characters. Now the first obvious solution would be to just change the toString method to only return the most essential values. Still this seems kinda "hacky" to me. Is there a better solution?


Solution

  • The sid column in ACL_SID table should only contain the username, not the entire user object with its properties. To create a correct instance of PrincipalSid, make sure at least one of following is true:

    • auth.getPrincipal() returns an instance of UserDetails interface.

    • auth.getPrincipal().toString() returns the username.