0
# Security Context Annotations
1
2
Core testing annotations for declarative security context management, providing method and class-level authentication setup without complex configuration. These annotations integrate with Spring Test's `TestExecutionListener` framework to automatically establish security contexts before test execution.
3
4
## Capabilities
5
6
### @WithMockUser
7
8
Creates a mock authenticated user with customizable username, password, roles, and authorities.
9
10
```java { .api }
11
/**
12
* Creates a mock authenticated user for testing
13
* Can be applied to test methods or test classes
14
*/
15
@Target({ElementType.METHOD, ElementType.TYPE})
16
@Retention(RetentionPolicy.RUNTIME)
17
@Inherited
18
@Documented
19
@WithSecurityContext(factory = WithMockUserSecurityContextFactory.class)
20
public @interface WithMockUser {
21
/** Username for the mock user (default: "user") */
22
String value() default "user";
23
24
/** Username for the mock user (takes precedence over value()) */
25
String username() default "";
26
27
/** Password for the mock user (default: "password") */
28
String password() default "password";
29
30
/** User roles, automatically prefixed with "ROLE_" (default: {"USER"}) */
31
String[] roles() default {"USER"};
32
33
/** Granted authorities, not automatically prefixed */
34
String[] authorities() default {};
35
36
/** When to establish the security context */
37
TestExecutionEvent setupBefore() default TestExecutionEvent.TEST_METHOD;
38
}
39
```
40
41
**Usage Examples:**
42
43
```java
44
// Method-level with default user
45
@Test
46
@WithMockUser
47
public void testWithDefaultUser() {
48
// Test runs with username="user", roles={"USER"}
49
}
50
51
// Custom username and roles
52
@Test
53
@WithMockUser(username = "admin", roles = {"ADMIN", "USER"})
54
public void testWithAdmin() {
55
// Test runs with admin privileges
56
}
57
58
// Using authorities instead of roles
59
@Test
60
@WithMockUser(authorities = {"READ_PRIVILEGES", "WRITE_PRIVILEGES"})
61
public void testWithCustomAuthorities() {
62
// Test runs with specific authorities (no ROLE_ prefix)
63
}
64
65
// Class-level annotation applies to all methods
66
@WithMockUser(roles = "MANAGER")
67
public class ManagerTests {
68
@Test
69
public void testManagerFeature() {
70
// Inherits manager role from class annotation
71
}
72
73
@Test
74
@WithAnonymousUser // Override class-level annotation
75
public void testAnonymousAccess() {
76
// Runs as anonymous user
77
}
78
}
79
```
80
81
### @WithAnonymousUser
82
83
Creates an anonymous authentication for testing scenarios where no authentication is present.
84
85
```java { .api }
86
/**
87
* Creates anonymous authentication for testing
88
* Can be applied to test methods or test classes
89
*/
90
@Target({ElementType.METHOD, ElementType.TYPE})
91
@Retention(RetentionPolicy.RUNTIME)
92
@Inherited
93
@Documented
94
@WithSecurityContext(factory = WithAnonymousUserSecurityContextFactory.class)
95
public @interface WithAnonymousUser {
96
/** When to establish the security context */
97
TestExecutionEvent setupBefore() default TestExecutionEvent.TEST_METHOD;
98
}
99
```
100
101
**Usage Examples:**
102
103
```java
104
@Test
105
@WithAnonymousUser
106
public void testAnonymousAccess() {
107
// Test runs with anonymous authentication
108
// Useful for testing public endpoints or access denied scenarios
109
}
110
111
// Override class-level security annotation
112
@WithMockUser(roles = "USER")
113
public class UserTests {
114
@Test
115
@WithAnonymousUser
116
public void testPublicEndpoint() {
117
// Overrides class-level @WithMockUser
118
}
119
}
120
```
121
122
### @WithUserDetails
123
124
Loads a user via `UserDetailsService` for more realistic testing scenarios using actual user data.
125
126
```java { .api }
127
/**
128
* Loads user via UserDetailsService for testing
129
* Requires a UserDetailsService bean in the test context
130
*/
131
@Target({ElementType.METHOD, ElementType.TYPE})
132
@Retention(RetentionPolicy.RUNTIME)
133
@Inherited
134
@Documented
135
@WithSecurityContext(factory = WithUserDetailsSecurityContextFactory.class)
136
public @interface WithUserDetails {
137
/** Username to lookup via UserDetailsService (default: "user") */
138
String value() default "user";
139
140
/** Specific UserDetailsService bean name to use */
141
String userDetailsServiceBeanName() default "";
142
143
/** When to establish the security context */
144
TestExecutionEvent setupBefore() default TestExecutionEvent.TEST_METHOD;
145
}
146
```
147
148
**Usage Examples:**
149
150
```java
151
@Test
152
@WithUserDetails("john.doe@example.com")
153
public void testWithRealUser() {
154
// Loads user "john.doe@example.com" via UserDetailsService
155
// Uses actual user data including roles and authorities
156
}
157
158
@Test
159
@WithUserDetails(value = "admin", userDetailsServiceBeanName = "customUserDetailsService")
160
public void testWithCustomService() {
161
// Uses specific UserDetailsService bean
162
}
163
```
164
165
### @SecurityTestExecutionListeners
166
167
Meta-annotation that enables only Spring Security test execution listeners, useful when testing security features without a full application context.
168
169
```java { .api }
170
/**
171
* Meta-annotation that enables Spring Security TestExecutionListeners
172
* Use when testing security without full Spring context setup
173
*/
174
@Target(ElementType.TYPE)
175
@Retention(RetentionPolicy.RUNTIME)
176
@Inherited
177
@Documented
178
@TestExecutionListeners(
179
inheritListeners = false,
180
listeners = {
181
WithSecurityContextTestExecutionListener.class,
182
ReactorContextTestExecutionListener.class
183
}
184
)
185
public @interface SecurityTestExecutionListeners {
186
}
187
```
188
189
**Usage Examples:**
190
191
```java
192
// Use when you only need security testing without full Spring Boot context
193
@SecurityTestExecutionListeners
194
public class SecurityUnitTests {
195
196
@Test
197
@WithMockUser(roles = "USER")
198
public void testSecurityLogic() {
199
// Test security-related logic without full application context
200
// Only security test execution listeners are enabled
201
}
202
}
203
204
// Useful for lightweight security testing
205
@SecurityTestExecutionListeners
206
public class AuthenticationUnitTests {
207
208
@Test
209
@WithUserDetails("testuser")
210
public void testUserDetailsLogic() {
211
// Tests user details without loading full Spring context
212
// Performance benefits for focused security tests
213
}
214
}
215
```
216
217
### @WithSecurityContext
218
219
Meta-annotation for creating custom security context annotations with custom factory implementations.
220
221
```java { .api }
222
/**
223
* Meta-annotation for creating custom security context annotations
224
* Requires a factory implementation
225
*/
226
@Target({ElementType.ANNOTATION_TYPE})
227
@Retention(RetentionPolicy.RUNTIME)
228
@Inherited
229
@Documented
230
public @interface WithSecurityContext {
231
/** Factory class that creates the SecurityContext */
232
Class<? extends WithSecurityContextFactory<? extends Annotation>> factory();
233
234
/** When to establish the security context */
235
TestExecutionEvent setupBefore() default TestExecutionEvent.TEST_METHOD;
236
}
237
```
238
239
**Usage Examples:**
240
241
```java
242
// Custom annotation definition
243
@Target({ElementType.METHOD, ElementType.TYPE})
244
@Retention(RetentionPolicy.RUNTIME)
245
@WithSecurityContext(factory = WithCustomUserSecurityContextFactory.class)
246
public @interface WithCustomUser {
247
String username() default "customUser";
248
String department() default "IT";
249
}
250
251
// Custom factory implementation
252
public class WithCustomUserSecurityContextFactory
253
implements WithSecurityContextFactory<WithCustomUser> {
254
255
@Override
256
public SecurityContext createSecurityContext(WithCustomUser annotation) {
257
SecurityContext context = SecurityContextHolder.createEmptyContext();
258
259
// Create custom authentication with department-specific authorities
260
List<GrantedAuthority> authorities = Arrays.asList(
261
new SimpleGrantedAuthority("ROLE_USER"),
262
new SimpleGrantedAuthority("DEPT_" + annotation.department().toUpperCase())
263
);
264
265
UsernamePasswordAuthenticationToken auth =
266
new UsernamePasswordAuthenticationToken(
267
annotation.username(),
268
"password",
269
authorities
270
);
271
272
context.setAuthentication(auth);
273
return context;
274
}
275
}
276
277
// Usage of custom annotation
278
@Test
279
@WithCustomUser(username = "alice", department = "FINANCE")
280
public void testCustomUser() {
281
// Test runs with custom user having ROLE_USER and DEPT_FINANCE authorities
282
}
283
```
284
285
## Supporting Classes
286
287
### WithSecurityContextFactory Interface
288
289
Factory interface for creating security contexts from annotations.
290
291
```java { .api }
292
/**
293
* Factory interface for creating SecurityContext from annotation
294
* @param <A> The annotation type this factory handles
295
*/
296
public interface WithSecurityContextFactory<A extends Annotation> {
297
/**
298
* Create SecurityContext from the provided annotation
299
* @param annotation The annotation instance with configuration
300
* @return SecurityContext to be used for the test
301
*/
302
SecurityContext createSecurityContext(A annotation);
303
}
304
```
305
306
### Built-in Factory Implementations
307
308
```java { .api }
309
// Factory for @WithMockUser
310
public class WithMockUserSecurityContextFactory
311
implements WithSecurityContextFactory<WithMockUser> {
312
public SecurityContext createSecurityContext(WithMockUser withUser);
313
}
314
315
// Factory for @WithAnonymousUser
316
public class WithAnonymousUserSecurityContextFactory
317
implements WithSecurityContextFactory<WithAnonymousUser> {
318
public SecurityContext createSecurityContext(WithAnonymousUser withAnonymousUser);
319
}
320
321
// Factory for @WithUserDetails
322
public class WithUserDetailsSecurityContextFactory
323
implements WithSecurityContextFactory<WithUserDetails> {
324
public SecurityContext createSecurityContext(WithUserDetails withUserDetails);
325
}
326
```
327
328
### TestExecutionEvent Enum
329
330
Defines when the security context should be established during test execution.
331
332
```java { .api }
333
/**
334
* Defines when SecurityContext should be established
335
*/
336
public enum TestExecutionEvent {
337
/** Before test method execution (default) */
338
TEST_METHOD,
339
340
/** Before test execution, after setup methods */
341
TEST_EXECUTION
342
}
343
```
344
345
## Integration with Spring Test
346
347
### WithSecurityContextTestExecutionListener
348
349
The test execution listener that processes security context annotations.
350
351
```java { .api }
352
/**
353
* TestExecutionListener that processes @WithSecurityContext annotations
354
* Order: 10000 (runs after most other listeners)
355
*/
356
public class WithSecurityContextTestExecutionListener implements TestExecutionListener {
357
// Processes annotations before test method/execution
358
// Clears security context after test completion
359
}
360
```
361
362
### Annotation Processing Order
363
364
1. **Class-level annotations** are processed first
365
2. **Method-level annotations** override class-level settings
366
3. **Security context** is established based on `setupBefore` value
367
4. **Test execution** proceeds with established context
368
5. **Context cleanup** occurs after test completion
369
370
## Common Patterns
371
372
### Method Override Pattern
373
374
```java
375
@WithMockUser(roles = "USER") // Class-level default
376
public class SecurityTests {
377
378
@Test
379
public void testUserFeature() {
380
// Uses class-level USER role
381
}
382
383
@Test
384
@WithMockUser(roles = "ADMIN") // Override for this method
385
public void testAdminFeature() {
386
// Uses ADMIN role
387
}
388
389
@Test
390
@WithAnonymousUser // Override to anonymous
391
public void testPublicAccess() {
392
// No authentication
393
}
394
}
395
```
396
397
### Parameterized Tests
398
399
```java
400
@ParameterizedTest
401
@ValueSource(strings = {"user1", "user2", "admin"})
402
@WithUserDetails // Uses parameter value as username
403
public void testMultipleUsers(String username) {
404
// Test runs for each username via UserDetailsService
405
}
406
```
407
408
### Nested Test Classes
409
410
```java
411
@WithMockUser(roles = "USER")
412
public class SecurityNestedTests {
413
414
@Nested
415
@WithMockUser(roles = "ADMIN") // Overrides parent class annotation
416
class AdminTests {
417
@Test
418
public void testAdminFeature() {
419
// Runs with ADMIN role
420
}
421
}
422
423
@Nested
424
class UserTests {
425
@Test
426
public void testUserFeature() {
427
// Inherits USER role from parent class
428
}
429
}
430
}
431
```