CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springframework-security--spring-security-acl

Spring Security ACL provides instance-based security for domain objects through a comprehensive Access Control List implementation

Pending
Overview
Eval results
Files

domain-model.mddocs/

Core Domain Model

Spring Security ACL's domain model provides a clean abstraction for representing access control lists and their components. Understanding these core interfaces is essential for working with the ACL module.

Overview

The domain model consists of seven core interfaces that work together to represent permissions:

  • Acl - Contains access control entries for a domain object (read-only view)
  • MutableAcl - Extends Acl with modification capabilities
  • ObjectIdentity - Identifies a specific domain object instance
  • Sid - Represents a security identity (user or role)
  • Permission - Defines the type of access being granted
  • AccessControlEntry - Individual permission assignment within an ACL
  • AuditableAccessControlEntry - ACE with audit success/failure tracking

Core Interfaces

Acl Interface

The Acl interface represents an access control list for a domain object:

package org.springframework.security.acls.model;

public interface Acl extends Serializable {
    
    // Get all ACL entries (for administrative purposes)
    List<AccessControlEntry> getEntries();
    
    // Get the domain object this ACL protects
    ObjectIdentity getObjectIdentity();
    
    // Get the owner of this ACL
    Sid getOwner();
    
    // Get parent ACL for inheritance
    Acl getParentAcl();
    
    // Check if entries inherit from parent
    boolean isEntriesInheriting();
    
    // Main authorization method
    boolean isGranted(List<Permission> permission, List<Sid> sids, boolean administrativeMode)
            throws NotFoundException, UnloadedSidException;
    
    // Check if specific SIDs are loaded
    boolean isSidLoaded(List<Sid> sids);
}

Key Points:

  • isGranted() is the primary method for authorization decisions
  • ACLs can inherit entries from parent ACLs
  • Not all SIDs need to be loaded for performance optimization
  • Entries are ordered and this ordering affects permission evaluation

MutableAcl Interface

The MutableAcl interface extends Acl to provide modification capabilities:

package org.springframework.security.acls.model;

public interface MutableAcl extends Acl {
    
    // Get the ACL identifier
    Serializable getId();
    
    // Insert new ACE at specific index
    void insertAce(int atIndexLocation, Permission permission, Sid sid, boolean granting) 
        throws NotFoundException;
    
    // Update permission for existing ACE
    void updateAce(int aceIndex, Permission permission) throws NotFoundException;
    
    // Remove ACE at specific index
    void deleteAce(int aceIndex) throws NotFoundException;
    
    // Change ACL ownership
    void setOwner(Sid newOwner);
    
    // Set parent ACL for inheritance
    void setParent(Acl newParent);
    
    // Control inheritance behavior
    void setEntriesInheriting(boolean entriesInheriting);
}

Key Points:

  • All modification operations require appropriate security authorization
  • ACE ordering is significant - earlier entries take precedence
  • Index-based operations for precise control over ACE placement
  • Provides full lifecycle management for ACL entries

ObjectIdentity Interface

Represents the identity of a domain object instance:

package org.springframework.security.acls.model;

public interface ObjectIdentity extends Serializable {
    
    // Get the object's unique identifier
    Serializable getIdentifier();
    
    // Get the object's type/class name
    String getType();
    
    // Standard equality methods
    boolean equals(Object obj);
    int hashCode();
}

Implementation Example:

// Using ObjectIdentityImpl for different scenarios
ObjectIdentity docId = new ObjectIdentityImpl(Document.class, 123L);
ObjectIdentity customId = new ObjectIdentityImpl("com.example.Document", "DOC-456");
ObjectIdentity fromObject = new ObjectIdentityImpl(documentInstance);

Sid Interface

Represents a security identity - either a principal (user) or granted authority (role):

package org.springframework.security.acls.model;

public interface Sid extends Serializable {
    boolean equals(Object obj);
    int hashCode();
}

Built-in Implementations:

// Principal-based SID (represents a user)
public class PrincipalSid implements Sid {
    public PrincipalSid(String principal);
    public PrincipalSid(Authentication authentication);
    public String getPrincipal();
}

// Authority-based SID (represents a role/group)  
public class GrantedAuthoritySid implements Sid {
    public GrantedAuthoritySid(String grantedAuthority);
    public GrantedAuthoritySid(GrantedAuthority grantedAuthority);
    public String getGrantedAuthority();
}

Usage Examples:

// Create SIDs for different scenarios
Sid userSid = new PrincipalSid("john.doe");
Sid adminSid = new GrantedAuthoritySid("ROLE_ADMIN");
Sid managerSid = new GrantedAuthoritySid("ROLE_DOCUMENT_MANAGER");

// From Spring Security Authentication
Sid currentUser = new PrincipalSid(authentication);
List<Sid> userAuthorities = authentication.getAuthorities()
    .stream()
    .map(GrantedAuthoritySid::new)
    .collect(Collectors.toList());

Permission Interface

Represents a permission that can be granted or denied:

package org.springframework.security.acls.model;

public interface Permission extends Serializable {
    
    // Get the permission bitmask
    int getMask();
    
    // Get human-readable pattern representation
    String getPattern();
    
    // Constants for pattern display
    char RESERVED_ON = '~';
    char RESERVED_OFF = '.';
    String THIRTY_TWO_RESERVED_OFF = "................................";
}

Built-in Permissions:

public class BasePermission extends AbstractPermission {
    
    public static final Permission READ = new BasePermission(1 << 0, 'R'); // 1
    public static final Permission WRITE = new BasePermission(1 << 1, 'W'); // 2  
    public static final Permission CREATE = new BasePermission(1 << 2, 'C'); // 4
    public static final Permission DELETE = new BasePermission(1 << 3, 'D'); // 8
    public static final Permission ADMINISTRATION = new BasePermission(1 << 4, 'A'); // 16
    
    protected BasePermission(int mask);
    protected BasePermission(int mask, char code);
}

Custom Permissions:

public class CustomPermission extends AbstractPermission {
    public static final Permission APPROVE = new CustomPermission(1 << 5, 'P');
    public static final Permission PUBLISH = new CustomPermission(1 << 6, 'U');
    
    public CustomPermission(int mask, char code) {
        super(mask, code);
    }
}

AccessControlEntry Interface

Represents an individual permission assignment within an ACL:

package org.springframework.security.acls.model;

public interface AccessControlEntry extends Serializable {
    
    // Get the ACL this entry belongs to
    Acl getAcl();
    
    // Get unique identifier for this entry
    Serializable getId();
    
    // Get the permission being granted/denied
    Permission getPermission();
    
    // Get the security identity
    Sid getSid();
    
    // Check if this is a grant (true) or deny (false)
    boolean isGranting();
}

Extended Interface for Auditing:

public interface AuditableAccessControlEntry extends AccessControlEntry {
    boolean isAuditFailure();
    boolean isAuditSuccess();
}

Extended Interfaces

The ACL module provides additional specialized interfaces:

Extended Mutable Interfaces

// For ownership operations
public interface OwnershipAcl extends MutableAcl {
    void setOwner(Sid newOwner);
}

// For audit configuration  
public interface AuditableAcl extends MutableAcl {
    void updateAuditing(int aceIndex, boolean auditSuccess, boolean auditFailure);
}

Relationships and Interactions

ACL Structure

// An ACL contains multiple ACEs
Acl documentAcl = aclService.readAclById(objectIdentity);
List<AccessControlEntry> entries = documentAcl.getEntries();

for (AccessControlEntry ace : entries) {
    Sid sid = ace.getSid();
    Permission permission = ace.getPermission();
    boolean isGrant = ace.isGranting();
    
    System.out.printf("SID: %s, Permission: %s, Grant: %s%n", 
                      sid, permission.getPattern(), isGrant);
}

Permission Checking Flow

// 1. Get object identity
ObjectIdentity identity = new ObjectIdentityImpl(Document.class, documentId);

// 2. Get current user's SIDs
List<Sid> sids = Arrays.asList(
    new PrincipalSid(authentication.getName()),
    new GrantedAuthoritySid("ROLE_USER")
);

// 3. Define required permissions
List<Permission> permissions = Arrays.asList(BasePermission.READ);

// 4. Load ACL and check permissions
Acl acl = aclService.readAclById(identity, sids);
boolean granted = acl.isGranted(permissions, sids, false);

ACL Inheritance

// Parent-child relationship example
ObjectIdentity parentFolder = new ObjectIdentityImpl(Folder.class, parentId);
ObjectIdentity childDocument = new ObjectIdentityImpl(Document.class, documentId);

// Child ACL can inherit from parent
MutableAcl childAcl = aclService.createAcl(childDocument);
Acl parentAcl = aclService.readAclById(parentFolder);

childAcl.setParent(parentAcl);
childAcl.setEntriesInheriting(true);  // Enable inheritance
aclService.updateAcl(childAcl);

// Permission check will consider both child and parent entries
boolean hasAccess = childAcl.isGranted(Arrays.asList(BasePermission.READ), sids, false);

Strategy Interfaces

The ACL module provides several strategy interfaces for customization:

ObjectIdentityRetrievalStrategy

public interface ObjectIdentityRetrievalStrategy {
    ObjectIdentity getObjectIdentity(Object domainObject);
}

// Default implementation
public class ObjectIdentityRetrievalStrategyImpl implements ObjectIdentityRetrievalStrategy {
    public ObjectIdentity getObjectIdentity(Object domainObject) {
        return new ObjectIdentityImpl(domainObject);
    }
}

SidRetrievalStrategy

public interface SidRetrievalStrategy {
    List<Sid> getSids(Authentication authentication);
}

// Default implementation  
public class SidRetrievalStrategyImpl implements SidRetrievalStrategy {
    public List<Sid> getSids(Authentication authentication) {
        List<Sid> sids = new ArrayList<>();
        sids.add(new PrincipalSid(authentication));
        
        for (GrantedAuthority authority : authentication.getAuthorities()) {
            sids.add(new GrantedAuthoritySid(authority));
        }
        return sids;
    }
}

PermissionFactory

public interface PermissionFactory {
    Permission buildFromMask(int mask);
    Permission buildFromName(String name);
    List<Permission> buildFromNames(List<String> names);
}

// Usage example
@Bean
public PermissionFactory permissionFactory() {
    DefaultPermissionFactory factory = new DefaultPermissionFactory();
    
    // Register custom permissions
    Map<String, Permission> customPermissions = new HashMap<>();
    customPermissions.put("APPROVE", CustomPermission.APPROVE);
    customPermissions.put("PUBLISH", CustomPermission.PUBLISH);
    
    factory.registerPublicPermissions(CustomPermission.class);
    return factory;
}

Exception Handling

The ACL module defines several specific exceptions:

// Base exception for ACL operations
public abstract class AclDataAccessException extends DataAccessException {
    protected AclDataAccessException(String msg);
    protected AclDataAccessException(String msg, Throwable cause);
}

// Specific exceptions
public class NotFoundException extends AclDataAccessException;
public class AlreadyExistsException extends AclDataAccessException;
public class ChildrenExistException extends AclDataAccessException;
public class UnloadedSidException extends AclDataAccessException;

Exception Handling Example:

try {
    Acl acl = aclService.readAclById(objectIdentity);
    return acl.isGranted(permissions, sids, false);
} catch (NotFoundException e) {
    // No ACL exists - apply default policy
    return false;
} catch (UnloadedSidException e) {
    // Requested SID not loaded - reload with all SIDs
    Acl fullAcl = aclService.readAclById(objectIdentity);
    return fullAcl.isGranted(permissions, sids, false);
}

Best Practices

1. Use Appropriate SID Types

// Use PrincipalSid for user-specific permissions
Sid userSid = new PrincipalSid("john.doe");

// Use GrantedAuthoritySid for role-based permissions  
Sid roleSid = new GrantedAuthoritySid("ROLE_DOCUMENT_ADMIN");

2. Leverage ACL Inheritance

// Set up hierarchical permissions
MutableAcl folderAcl = aclService.createAcl(folderIdentity);
folderAcl.insertAce(0, BasePermission.READ, managerSid, true);

MutableAcl documentAcl = aclService.createAcl(documentIdentity);  
documentAcl.setParent(folderAcl);
documentAcl.setEntriesInheriting(true);
// Documents inherit folder permissions automatically

3. Optimize for Performance

// Load ACLs with specific SIDs for better performance
List<Sid> relevantSids = sidRetrievalStrategy.getSids(authentication);
Acl acl = aclService.readAclById(objectIdentity, relevantSids);

4. Use Custom Permissions Appropriately

// Define business-specific permissions
public class DocumentPermission extends AbstractPermission {
    public static final Permission APPROVE = new DocumentPermission(1 << 5, 'P');
    public static final Permission PUBLISH = new DocumentPermission(1 << 6, 'U');
    public static final Permission ARCHIVE = new DocumentPermission(1 << 7, 'H');
}

The domain model provides a flexible foundation for implementing fine-grained access control. The next step is understanding how to configure and use ACL services to work with this domain model.

Install with Tessl CLI

npx tessl i tessl/maven-org-springframework-security--spring-security-acl

docs

acl-services.md

caching-performance.md

configuration.md

domain-model.md

index.md

permission-evaluation.md

strategy-interfaces.md

tile.json