PluginBench
Skill
Review
Audit score 70

unit-test-security-authorization

giuseppe-trisciuoglio/developer-kit

Unit test Spring Security authorization with @PreAuthorize, @Secured, and role-based access control patterns.

What is unit-test-security-authorization?

Provides patterns for testing Spring Security method-level authorization annotations and role-based access control (RBAC). Use this skill when validating @PreAuthorize, @Secured, @RolesAllowed decorators and custom permission evaluators in unit tests.

  • Test @PreAuthorize and @Secured method-level security annotations
  • Validate role-based access control (RBAC) with @WithMockUser
  • Test custom permission evaluators and expression-based authorization
  • Verify access denied scenarios for unauthorized principals
  • Test @PostAuthorize and @RolesAllowed (JSR-250) annotations
  • Confirm security context is active and authorization is enforced

How to install unit-test-security-authorization

npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill unit-test-security-authorization
Prerequisites
  • spring-security-test dependency in test scope
  • @EnableMethodSecurity or @EnableGlobalMethodSecurity in test configuration
  • JUnit 5 or compatible test framework
  • Basic understanding of Spring Security annotations
Claude Code
Cursor
Windsurf
Cline

How to use unit-test-security-authorization

  1. 1.Add spring-security-test to test dependencies
  2. 2.Enable method security in test configuration with @EnableMethodSecurity
  3. 3.Use @WithMockUser(roles="ROLE_NAME") to set authenticated user context
  4. 4.Write test cases for both allow and deny scenarios
  5. 5.Use @WithUserDetails for expression-based security with custom principals
  6. 6.Assert AccessDeniedException is thrown for unauthorized access
  7. 7.Verify security is active by testing unauthenticated access

Use cases

Good for
  • Testing admin-only operations like deleteUser() with different roles
  • Validating expression-based security rules that check user ownership
  • Testing custom permission evaluators for document or resource access
  • Verifying that unauthorized users receive AccessDeniedException
  • Testing role-based workflows with multiple role combinations
Who it's for
  • Spring developers writing unit tests for secured services
  • QA engineers validating authorization logic
  • Security-focused teams implementing role-based access control
  • Developers migrating from manual to declarative security

unit-test-security-authorization FAQ

How do I test @PreAuthorize with different roles?

Use @WithMockUser(roles="ADMIN") on test methods to set the authenticated user's roles. Write separate test methods for each role to verify both allow and deny cases.

Why does my @PreAuthorize test pass when it should fail?

Verify that @EnableMethodSecurity is active on your test configuration. Without it, @PreAuthorize checks are silently bypassed. Also ensure you're calling the method through a proxy, not directly.

How do I test custom permission evaluators?

Create an Authentication object with UsernamePasswordAuthenticationToken, instantiate your permission evaluator, and call hasPermission(auth, resource, permission) directly in the test.

Can I test expression-based security like #userId == authentication.principal.id?

Yes, use @WithUserDetails with a custom UserDetailsService to provide a principal with the properties your SpEL expression needs.

What's the difference between @Secured and @PreAuthorize?

@Secured uses simple role names (ROLE_ADMIN), while @PreAuthorize supports complex SpEL expressions. @PreAuthorize is more flexible and recommended for new code.

Full instructions (SKILL.md)

Source of truth, from giuseppe-trisciuoglio/developer-kit.


name: unit-test-security-authorization description: Provides patterns for unit testing Spring Security with @PreAuthorize, @Secured, @RolesAllowed. Validates role-based access control and authorization policies. Use when testing security configurations and access control logic. allowed-tools: Read, Write, Bash, Glob, Grep

Unit Testing Security and Authorization

Overview

This skill provides patterns for unit testing Spring Security authorization logic using @PreAuthorize, @Secured, @RolesAllowed, and custom permission evaluators. It covers testing role-based access control (RBAC), expression-based authorization, custom permission evaluators, and verifying access denied scenarios without full Spring Security context.

When to Use

Use this skill when:

  • Testing @PreAuthorize and @Secured method-level security
  • Testing role-based access control (RBAC)
  • Testing custom permission evaluators
  • Verifying access denied scenarios
  • Testing authorization with authenticated principals
  • Want fast authorization tests without full Spring Security context

Instructions

Follow these steps to test Spring Security authorization:

1. Set Up Security Testing Dependencies

Add spring-security-test to your test dependencies:

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-test</artifactId>
  <scope>test</scope>
</dependency>

2. Enable Method Security in Test Configuration

@Configuration
@EnableMethodSecurity
class TestSecurityConfig { }

3. Test with @WithMockUser

@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminAccess() {
  assertThatCode(() -> service.deleteUser(1L))
    .doesNotThrowAnyException();
}

@Test
@WithMockUser(roles = "USER")
void shouldDenyUserAccess() {
  assertThatThrownBy(() -> service.deleteUser(1L))
    .isInstanceOf(AccessDeniedException.class);
}

4. Test Custom Permission Evaluators

@Test
void shouldGrantPermissionToOwner() {
  Authentication auth = new UsernamePasswordAuthenticationToken(
    "alice", null, List.of(new SimpleGrantedAuthority("ROLE_USER"))
  );
  Document doc = new Document(1L, "Test", new User("alice"));

  boolean result = evaluator.hasPermission(auth, doc, "WRITE");
  assertThat(result).isTrue();
}

5. Validate Security is Active

If tests pass unexpectedly, add this assertion to verify security is enforced:

@Test
void shouldRejectUnauthorizedWhenSecurityEnabled() {
  assertThatThrownBy(() -> service.deleteUser(1L))
    .isInstanceOf(AccessDeniedException.class);
}

Quick Reference

AnnotationDescriptionExample
@PreAuthorizePre-invocation authorization@PreAuthorize("hasRole('ADMIN')")
@PostAuthorizePost-invocation authorization@PostAuthorize("returnObject.owner == authentication.name")
@SecuredSimple role-based security@Secured("ROLE_ADMIN")
@RolesAllowedJSR-250 standard@RolesAllowed({"ADMIN", "MANAGER"})
@WithMockUserTest annotation@WithMockUser(roles = "ADMIN")

Examples

Basic @PreAuthorize Test

@Service
public class UserService {
  @PreAuthorize("hasRole('ADMIN')")
  public void deleteUser(Long userId) {
    // delete logic
  }
}

// Test
@Test
@WithMockUser(roles = "ADMIN")
void shouldAllowAdminToDeleteUser() {
  assertThatCode(() -> service.deleteUser(1L))
    .doesNotThrowAnyException();
}

@Test
@WithMockUser(roles = "USER")
void shouldDenyUserFromDeletingUser() {
  assertThatThrownBy(() -> service.deleteUser(1L))
    .isInstanceOf(AccessDeniedException.class);
}

Expression-Based Security Test

@PreAuthorize("#userId == authentication.principal.id")
public UserProfile getUserProfile(Long userId) {
  // get profile
}

// For custom principal properties, use @WithUserDetails with a custom UserDetailsService
@Test
@WithUserDetails("alice")
void shouldAllowUserToAccessOwnProfile() {
  assertThatCode(() -> service.getUserProfile(1L))
    .doesNotThrowAnyException();
}

Validation tip: If a security test passes unexpectedly, verify that @EnableMethodSecurity is active on the test configuration — a missing annotation causes all @PreAuthorize checks to be bypassed silently.

See references/basic-testing.md for more basic patterns and references/advanced-authorization.md for complex expressions and custom evaluators.

Best Practices

  1. Use @WithMockUser for setting authenticated user context
  2. Test both allow and deny cases for each security rule
  3. Test with different roles to verify role-based decisions
  4. Test expression-based security comprehensively
  5. Mock external dependencies (permission evaluators, etc.)
  6. Test anonymous access separately from authenticated access
  7. Use @EnableGlobalMethodSecurity in configuration for method-level security

Common Pitfalls

  • Forgetting to enable method security in test configuration
  • Not testing both allow and deny scenarios
  • Testing framework code instead of authorization logic
  • Not handling null authentication in tests
  • Mixing authentication and authorization tests unnecessarily

Constraints and Warnings

  • Method security requires proxy: @PreAuthorize works via proxies; direct method calls bypass security
  • @EnableGlobalMethodSecurity: Must be enabled for @PreAuthorize, @Secured to work
  • Role prefix: Spring adds "ROLE_" prefix automatically; use hasRole('ADMIN') not hasRole('ROLE_ADMIN')
  • Authentication context: Security context is thread-local; be careful with async tests
  • @WithMockUser limitations: Creates a simple Authentication; complex auth scenarios need custom setup
  • SpEL expressions: Complex SpEL in @PreAuthorize can be difficult to debug; test thoroughly
  • Performance impact: Method security adds overhead; consider security at layer boundaries

References

Setup and Configuration

Testing Patterns

Advanced Topics

Complete Examples

Related skills

More from giuseppe-trisciuoglio/developer-kit and the wider catalog.

UNunit-test-service-layer logo

unit-test-service-layer

giuseppe-trisciuoglio/developer-kit

Unit test service layer with Mockito: mock dependencies, verify interactions, test business logic in isolation.

1.4k installs
UNunit-test-utility-methods logo

unit-test-utility-methods

giuseppe-trisciuoglio/developer-kit

Test patterns for utility classes, static methods, and pure functions with edge case coverage.

1.4k installs
UNunit-test-wiremock-rest-api logo

unit-test-wiremock-rest-api

giuseppe-trisciuoglio/developer-kit

Unit test REST API integrations with WireMock stubs, request verification, and error simulation.

1.4k installs
WIwiremock-standalone-docker logo

wiremock-standalone-docker

giuseppe-trisciuoglio/developer-kit

Provides patterns and configurations for running WireMock as a standalone Docker container. Generates mock HTTP endpoints, creates stub mappings for testing, validates integration scenarios, and simulates error conditions. Use when you need to mock APIs, create a mock server, stub external services, simulate third-party APIs, or fake API responses for integration testing.

1.0k installsAudited
ZOzod-validation-utilities logo

zod-validation-utilities

giuseppe-trisciuoglio/developer-kit

Creates reusable Zod v4 schemas, validates API payloads, forms, and configuration input, transforms and coerces data safely, and handles validation errors with strong type inference for TypeScript applications. Use when designing validation layers, parsing `z.string()`, `z.object()`, or `z.email()` schemas, or implementing runtime type-safe data validation.

1.2k installsAudited
GLgluestack-ui-v4:components logo

gluestack-ui-v4:components

gluestack/agent-skills

Component usage patterns for gluestack-ui v4 - covers component selection, props vs className, compound patterns, icons, and provider setup.

694 installs