unit-test-security-authorization

Unit Testing Security and Authorization

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "unit-test-security-authorization" with this command: npx skills add giuseppe-trisciuoglio/developer-kit/giuseppe-trisciuoglio-developer-kit-unit-test-security-authorization

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>

  1. Enable Method Security in Test Configuration

@Configuration @EnableMethodSecurity class TestSecurityConfig { }

  1. 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); }

  1. 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(); }

  1. 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

Annotation Description Example

@PreAuthorize

Pre-invocation authorization @PreAuthorize("hasRole('ADMIN')")

@PostAuthorize

Post-invocation authorization @PostAuthorize("returnObject.owner == authentication.name")

@Secured

Simple role-based security @Secured("ROLE_ADMIN")

@RolesAllowed

JSR-250 standard @RolesAllowed({"ADMIN", "MANAGER"})

@WithMockUser

Test 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

  • Use @WithMockUser for setting authenticated user context

  • Test both allow and deny cases for each security rule

  • Test with different roles to verify role-based decisions

  • Test expression-based security comprehensively

  • Mock external dependencies (permission evaluators, etc.)

  • Test anonymous access separately from authenticated access

  • 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

  • references/setup.md - Maven/Gradle dependencies and security configuration

Testing Patterns

  • references/basic-testing.md - Basic patterns for @PreAuthorize , @Secured , MockMvc testing, and parameterized tests

Advanced Topics

  • references/advanced-authorization.md - Expression-based authorization, custom permission evaluators, SpEL expressions

Complete Examples

  • references/complete-examples.md - Before/after examples showing transition from manual to declarative security

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Security

spring-boot-security-jwt

No summary provided by upstream source.

Repository SourceNeeds Review
Security

typescript-security-review

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

shadcn-ui

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

tailwind-css-patterns

No summary provided by upstream source.

Repository SourceNeeds Review