CtrlK
BlogDocsLog inGet started
Tessl Logo

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

Spring Security configuration module providing comprehensive declarative security configuration capabilities for Spring applications

Pending
Overview
Eval results
Files

method-security.mddocs/

Method Security Configuration

Spring Security Config provides comprehensive method-level security configuration through annotations and configuration classes. Method security enables fine-grained access control at the method level using annotations like @PreAuthorize, @PostAuthorize, @Secured, and JSR-250 annotations.

Method Security Annotations

@EnableMethodSecurity

Modern method-level security configuration annotation (Spring Security 5.6+).

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(MethodSecurityConfiguration.class)
public @interface EnableMethodSecurity {
    /**
     * Determines if Spring Security's pre/post annotations should be enabled.
     * @return true if pre/post annotations are enabled, false otherwise. Default is true.
     */
    boolean prePostEnabled() default true;
    
    /**
     * Determines if Spring Security's @Secured annotation should be enabled.
     * @return true if @Secured is enabled, false otherwise. Default is false.
     */
    boolean securedEnabled() default false;
    
    /**
     * Determines if JSR-250 annotations should be enabled.
     * @return true if JSR-250 annotations are enabled, false otherwise. Default is false.
     */
    boolean jsr250Enabled() default false;
    
    /**
     * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
     * to standard Java interface-based proxies.
     * @return true to use CGLIB proxies, false for JDK proxies. Default is false.
     */
    boolean proxyTargetClass() default false;
    
    /**
     * Indicate how security advice should be applied.
     * @return the advice mode. Default is PROXY.
     */
    AdviceMode mode() default AdviceMode.PROXY;
    
    /**
     * Indicate the offset in the order for SecurityMethodInterceptor.
     * @return the offset value. Default is 0.
     */
    int offset() default 0;
}

Usage Example:

@Configuration
@EnableMethodSecurity(
    prePostEnabled = true,
    securedEnabled = true,
    jsr250Enabled = true
)
public class MethodSecurityConfig {
    
    @Bean
    public MethodSecurityExpressionHandler methodSecurityExpressionHandler() {
        DefaultMethodSecurityExpressionHandler expressionHandler = 
            new DefaultMethodSecurityExpressionHandler();
        expressionHandler.setPermissionEvaluator(customPermissionEvaluator());
        return expressionHandler;
    }
}

@EnableGlobalMethodSecurity (Deprecated)

Legacy method-level security configuration annotation.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(GlobalMethodSecurityConfiguration.class)
@Deprecated
public @interface EnableGlobalMethodSecurity {
    boolean prePostEnabled() default false;
    boolean securedEnabled() default false;
    boolean jsr250Enabled() default false;
    boolean proxyTargetClass() default false;
    AdviceMode mode() default AdviceMode.PROXY;
    int order() default Ordered.LOWEST_PRECEDENCE;
}

@EnableReactiveMethodSecurity

Reactive method security configuration for WebFlux applications.

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ReactiveMethodSecurityConfiguration.class)
public @interface EnableReactiveMethodSecurity {
    /**
     * Indicate whether subclass-based (CGLIB) proxies are to be created as opposed
     * to standard Java interface-based proxies.
     * @return true to use CGLIB proxies, false for JDK proxies. Default is false.
     */
    boolean proxyTargetClass() default false;
    
    /**
     * Indicate how security advice should be applied.
     * @return the advice mode. Default is PROXY.
     */
    AdviceMode mode() default AdviceMode.PROXY;
    
    /**
     * Indicate the order in which the SecurityMethodInterceptor should be applied.
     * @return the order value. Default is LOWEST_PRECEDENCE.
     */
    int order() default Ordered.LOWEST_PRECEDENCE;
    
    /**
     * Indicate whether to use AuthorizationManager for reactive method security.
     * @return true to use AuthorizationManager, false for legacy approach. Default is true.
     */
    boolean useAuthorizationManager() default true;
}

Method Security Configuration Classes

GlobalMethodSecurityConfiguration

Base class for method security configuration (legacy approach).

public abstract class GlobalMethodSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
    
    // Configuration Methods
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {}
    
    // Access Decision Manager
    protected AccessDecisionManager accessDecisionManager() {
        List<AccessDecisionVoter<?>> decisionVoters = new ArrayList<>();
        ExpressionBasedPreInvocationAdvice expressionAdvice = 
            new ExpressionBasedPreInvocationAdvice();
        expressionAdvice.setExpressionHandler(getExpressionHandler());
        
        if (prePostEnabled()) {
            decisionVoters.add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice));
        }
        if (jsr250Enabled()) {
            decisionVoters.add(new Jsr250Voter());
        }
        
        return new AffirmativeBased(decisionVoters);
    }
    
    // Expression Handler
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        DefaultMethodSecurityExpressionHandler expressionHandler = 
            new DefaultMethodSecurityExpressionHandler();
        if (authenticationTrustResolver != null) {
            expressionHandler.setTrustResolver(authenticationTrustResolver);
        }
        if (roleHierarchy != null) {
            expressionHandler.setRoleHierarchy(roleHierarchy);
        }
        if (permissionEvaluator != null) {
            expressionHandler.setPermissionEvaluator(permissionEvaluator);
        }
        return expressionHandler;
    }
    
    // Configuration Properties
    protected boolean prePostEnabled() { return false; }
    protected boolean securedEnabled() { return false; }
    protected boolean jsr250Enabled() { return false; }
    
    // Authentication Manager
    protected AuthenticationManager authenticationManager() throws Exception {
        return authenticationManagerBuilder.build();
    }
    
    // Run As Manager
    protected RunAsManager runAsManager() { return null; }
    
    // Permission Evaluator
    protected PermissionEvaluator permissionEvaluator() { return null; }
    
    // Role Hierarchy
    protected RoleHierarchy roleHierarchy() { return null; }
    
    // Authentication Trust Resolver
    protected AuthenticationTrustResolver authenticationTrustResolver() { return null; }
}

Usage Example:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class CustomMethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserDetailsService())
            .passwordEncoder(passwordEncoder());
    }
    
    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        DefaultMethodSecurityExpressionHandler expressionHandler = 
            new DefaultMethodSecurityExpressionHandler();
        expressionHandler.setPermissionEvaluator(customPermissionEvaluator());
        expressionHandler.setRoleHierarchy(roleHierarchy());
        return expressionHandler;
    }
    
    @Override
    protected AccessDecisionManager accessDecisionManager() {
        List<AccessDecisionVoter<?>> decisionVoters = Arrays.asList(
            new RoleVoter(),
            new AuthenticatedVoter(),
            new WebExpressionVoter()
        );
        return new AffirmativeBased(decisionVoters);
    }
    
    @Bean
    public RoleHierarchy roleHierarchy() {
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER > ROLE_GUEST");
        return roleHierarchy;
    }
    
    @Bean
    public PermissionEvaluator customPermissionEvaluator() {
        return new CustomPermissionEvaluator();
    }
}

ReactiveMethodSecurityConfiguration

Configuration class for reactive method security.

@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ReactiveMethodSecurityConfiguration {
    
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public ReactiveMethodSecurityInterceptor methodSecurityInterceptor(
            ReactiveAuthorizationManager<MethodInvocation> authorizationManager) {
        ReactiveMethodSecurityInterceptor interceptor = 
            new ReactiveMethodSecurityInterceptor();
        interceptor.setAuthorizationManager(authorizationManager);
        return interceptor;
    }
    
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public ReactiveAuthorizationManager<MethodInvocation> methodAuthorizationManager() {
        return new PrePostAdviceReactiveMethodInterceptor();
    }
}

Method Security Infrastructure

MethodSecurityMetadataSourceAdvisorRegistrar

Registrar for method security metadata source advisors.

public final class MethodSecurityMetadataSourceAdvisorRegistrar implements ImportBeanDefinitionRegistrar {
    
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, 
            BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        
        // Register method security advisor
        BeanDefinition advisor = BeanDefinitionBuilder
            .rootBeanDefinition(MethodSecurityMetadataSourceAdvisor.class)
            .setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
            .getBeanDefinition();
        
        registry.registerBeanDefinition("methodSecurityAdvisor", advisor);
    }
}

AuthorizationProxyConfiguration

Configuration for authorization proxies in method security.

@Configuration
@ConditionalOnClass(AuthorizationManager.class)
public class AuthorizationProxyConfiguration {
    
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public AuthorizationAdvisor authorizationAdvisor(
            AuthorizationManager<MethodInvocation> authorizationManager) {
        return new AuthorizationAdvisor(authorizationManager);
    }
    
    @Bean
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public AuthorizationManager<MethodInvocation> methodAuthorizationManager() {
        return new PrePostAdviceAuthorizationManager();
    }
}

Security Expressions and Evaluation

MethodSecurityExpressionHandler

Interface for handling method security expressions.

public interface MethodSecurityExpressionHandler extends SecurityExpressionHandler<MethodInvocation> {
    
    /**
     * Filter the collection or array returned from a method invocation.
     * @param filterObject the collection or array to filter
     * @param expression the expression to evaluate for each element
     * @param ctx the evaluation context
     * @return the filtered collection or array
     */
    Object filter(Object filterObject, Expression expression, EvaluationContext ctx);
    
    /**
     * Create an evaluation context for method invocation.
     * @param auth the current authentication
     * @param mi the method invocation
     * @return the evaluation context
     */
    EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi);
    
    /**
     * Set the permission evaluator for object-level security.
     * @param permissionEvaluator the permission evaluator
     */
    void setPermissionEvaluator(PermissionEvaluator permissionEvaluator);
    
    /**
     * Set the role hierarchy for inherited roles.
     * @param roleHierarchy the role hierarchy
     */
    void setRoleHierarchy(RoleHierarchy roleHierarchy);
    
    /**
     * Set the trust resolver for authentication state evaluation.
     * @param trustResolver the authentication trust resolver
     */
    void setTrustResolver(AuthenticationTrustResolver trustResolver);
}

DefaultMethodSecurityExpressionHandler

Default implementation of method security expression handler.

public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpressionHandler<MethodInvocation>
        implements MethodSecurityExpressionHandler, BeanFactoryAware {
    
    private PermissionEvaluator permissionEvaluator = new DenyAllPermissionEvaluator();
    private RoleHierarchy roleHierarchy;
    private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();
    
    @Override
    public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) {
        MethodSecurityEvaluationContext ctx = new MethodSecurityEvaluationContext(auth, mi, getParameterNameDiscoverer());
        MethodSecurityExpressionRoot root = new MethodSecurityExpressionRoot(auth);
        root.setPermissionEvaluator(permissionEvaluator);
        root.setTrustResolver(trustResolver);
        root.setRoleHierarchy(roleHierarchy);
        ctx.setRootObject(root);
        return ctx;
    }
    
    @Override
    public Object filter(Object filterObject, Expression expression, EvaluationContext ctx) {
        if (filterObject instanceof Collection) {
            return filterCollection((Collection<?>) filterObject, expression, ctx);
        } else if (filterObject.getClass().isArray()) {
            return filterArray((Object[]) filterObject, expression, ctx);
        }
        return filterObject;
    }
    
    // Setter methods
    public void setPermissionEvaluator(PermissionEvaluator permissionEvaluator) {
        this.permissionEvaluator = permissionEvaluator;
    }
    
    public void setRoleHierarchy(RoleHierarchy roleHierarchy) {
        this.roleHierarchy = roleHierarchy;
    }
    
    public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
        this.trustResolver = trustResolver;
    }
}

Method Security Annotations Usage

Pre/Post Authorization Annotations

Security annotations for method-level access control.

// Pre-authorization annotation
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface PreAuthorize {
    /**
     * Spring Expression Language (SpEL) expression used to determine
     * if a method invocation is allowed.
     * @return the SpEL expression
     */
    String value();
}

// Post-authorization annotation
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface PostAuthorize {
    /**
     * Spring Expression Language (SpEL) expression used to determine
     * if a method return value should be returned to the caller.
     * @return the SpEL expression
     */
    String value();
}

// Pre-filtering annotation
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface PreFilter {
    /**
     * Spring Expression Language (SpEL) expression used to filter
     * method arguments before method invocation.
     * @return the SpEL expression
     */
    String value();
    
    /**
     * Name of the argument to filter when there are multiple arguments.
     * @return the argument name
     */
    String filterTarget() default "";
}

// Post-filtering annotation
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface PostFilter {
    /**
     * Spring Expression Language (SpEL) expression used to filter
     * the method return value.
     * @return the SpEL expression
     */
    String value();
}

// Secured annotation
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Secured {
    /**
     * List of roles/authorities required to invoke the secured method.
     * @return the required roles/authorities
     */
    String[] value();
}

Usage Examples:

@Service
public class DocumentService {
    
    // Pre-authorization: Check role before method execution
    @PreAuthorize("hasRole('ADMIN')")
    public void deleteDocument(Long documentId) {
        // Implementation
    }
    
    // Pre-authorization: Check ownership
    @PreAuthorize("@documentService.isOwner(authentication.name, #documentId)")
    public Document getDocument(Long documentId) {
        // Implementation
    }
    
    // Post-authorization: Filter return value based on ownership
    @PostAuthorize("returnObject.owner == authentication.name or hasRole('ADMIN')")
    public Document loadDocument(Long documentId) {
        // Implementation
    }
    
    // Pre-filtering: Filter collection arguments
    @PreFilter("hasPermission(filterObject, 'READ')")
    public List<Document> processDocuments(List<Document> documents) {
        // Process only documents the user can read
        return documents;
    }
    
    // Post-filtering: Filter collection return values
    @PostFilter("hasPermission(filterObject, 'READ')")
    public List<Document> findAllDocuments() {
        // Return only documents the user can read
        return documentRepository.findAll();
    }
    
    // Secured annotation: Simple role-based access
    @Secured({"ROLE_USER", "ROLE_ADMIN"})
    public List<Document> getUserDocuments() {
        // Implementation
    }
    
    // JSR-250 annotations
    @RolesAllowed("ADMIN")
    public void adminOnlyMethod() {
        // Implementation
    }
    
    @PermitAll
    public String publicMethod() {
        return "Public access";
    }
    
    @DenyAll
    public void restrictedMethod() {
        // This method is never accessible
    }
}

Custom Permission Evaluation

PermissionEvaluator Interface

Interface for custom permission evaluation logic.

public interface PermissionEvaluator {
    /**
     * Determine whether the user has the given permission for the domain object.
     * @param authentication the user authentication
     * @param targetDomainObject the domain object
     * @param permission the permission to check
     * @return true if access is granted, false otherwise
     */
    boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission);
    
    /**
     * Determine whether the user has the given permission for the domain object
     * identified by its identifier.
     * @param authentication the user authentication
     * @param targetId the identifier of the domain object
     * @param targetType the type of the domain object
     * @param permission the permission to check
     * @return true if access is granted, false otherwise
     */
    boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission);
}

Custom Permission Evaluator Example:

@Component
public class CustomPermissionEvaluator implements PermissionEvaluator {
    
    @Autowired
    private PermissionService permissionService;
    
    @Override
    public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
        if (authentication == null || targetDomainObject == null || !(permission instanceof String)) {
            return false;
        }
        
        String username = authentication.getName();
        String permissionName = (String) permission;
        
        if (targetDomainObject instanceof Document) {
            Document document = (Document) targetDomainObject;
            return permissionService.hasDocumentPermission(username, document.getId(), permissionName);
        }
        
        return false;
    }
    
    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
        if (authentication == null || targetId == null || targetType == null || !(permission instanceof String)) {
            return false;
        }
        
        String username = authentication.getName();
        String permissionName = (String) permission;
        
        if ("Document".equals(targetType)) {
            return permissionService.hasDocumentPermission(username, (Long) targetId, permissionName);
        }
        
        return false;
    }
}

// Usage in service methods
@Service
public class DocumentService {
    
    @PreAuthorize("hasPermission(#documentId, 'Document', 'READ')")
    public Document getDocument(Long documentId) {
        return documentRepository.findById(documentId);
    }
    
    @PreAuthorize("hasPermission(#document, 'WRITE')")
    public Document updateDocument(Document document) {
        return documentRepository.save(document);
    }
}

Advanced Method Security Patterns

Class-Level Security

Apply security annotations at the class level for all methods:

@Service
@PreAuthorize("hasRole('USER')")
public class UserService {
    
    // All methods require USER role by default
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
    
    // Override class-level security
    @PreAuthorize("hasRole('ADMIN')")
    public void deleteUser(Long userId) {
        userRepository.deleteById(userId);
    }
    
    // No additional security beyond class level
    public User getCurrentUser(Authentication auth) {
        return userRepository.findByUsername(auth.getName());
    }
}

Security with Complex Expressions

Use complex SpEL expressions for sophisticated authorization logic:

@Service
public class ProjectService {
    
    @PreAuthorize("hasRole('ADMIN') or " +
                  "(hasRole('PROJECT_MANAGER') and @projectService.isProjectManager(authentication.name, #projectId)) or " +
                  "(hasRole('DEVELOPER') and @projectService.isProjectMember(authentication.name, #projectId))")
    public Project getProject(Long projectId) {
        return projectRepository.findById(projectId);
    }
    
    @PreAuthorize("@projectService.canEditProject(authentication, #project)")
    public Project updateProject(Project project) {
        return projectRepository.save(project);
    }
    
    public boolean canEditProject(Authentication auth, Project project) {
        String username = auth.getName();
        return hasRole(auth, "ADMIN") ||
               (hasRole(auth, "PROJECT_MANAGER") && isProjectManager(username, project.getId())) ||
               (hasRole(auth, "DEVELOPER") && isProjectLead(username, project.getId()));
    }
}

Reactive Method Security

Method security for reactive applications:

@Service
public class ReactiveDocumentService {
    
    @PreAuthorize("hasRole('USER')")
    public Mono<Document> getDocument(String documentId) {
        return documentRepository.findById(documentId);
    }
    
    @PreAuthorize("hasPermission(#document, 'WRITE')")
    public Mono<Document> saveDocument(Document document) {
        return documentRepository.save(document);
    }
    
    @PostFilter("hasPermission(filterObject, 'READ')")
    public Flux<Document> findAllDocuments() {
        return documentRepository.findAll();
    }
}

Install with Tessl CLI

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

docs

authentication-configuration.md

core-annotations.md

http-configurers.md

index.md

method-security.md

oauth2-configuration.md

security-builders.md

tile.json