Skip to content

Commit 22c8f63

Browse files
clevertensionjzheaux
authored andcommitted
review phase2
1 parent 570eb01 commit 22c8f63

File tree

5 files changed

+180
-21
lines changed

5 files changed

+180
-21
lines changed

core/src/main/java/org/springframework/security/core/annotation/CurrentSecurityContext.java

+11-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* https://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -28,11 +28,19 @@
2828
* @author Dan Zheng
2929
* @since 5.2
3030
*
31+
* <p>
3132
* See: <a href=
3233
* "{@docRoot}/org/springframework/security/web/bind/support/CurrentSecurityContextArgumentResolver.html"
33-
* > CurrentSecurityContextArgumentResolver </a>
34+
* > CurrentSecurityContextArgumentResolver</a> For Servlet
35+
* </p>
36+
*
37+
* <p>
38+
* See: <a href=
39+
* "{@docRoot}/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolver.html"
40+
* > CurrentSecurityContextArgumentResolver</a> For WebFlux
41+
* </p>
3442
*/
35-
@Target({ ElementType.PARAMETER })
43+
@Target({ ElementType.PARAMETER, ElementType.ANNOTATION_TYPE })
3644
@Retention(RetentionPolicy.RUNTIME)
3745
@Documented
3846
public @interface CurrentSecurityContext {

web/src/main/java/org/springframework/security/web/bind/support/CurrentSecurityContextArgumentResolver.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* https://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -28,6 +28,7 @@
2828
import org.springframework.security.core.context.SecurityContext;
2929
import org.springframework.security.core.context.SecurityContextHolder;
3030
import org.springframework.stereotype.Controller;
31+
import org.springframework.util.Assert;
3132
import org.springframework.util.StringUtils;
3233
import org.springframework.web.bind.support.WebDataBinderFactory;
3334
import org.springframework.web.context.request.NativeWebRequest;
@@ -142,6 +143,7 @@ public Object resolveArgument(MethodParameter parameter,
142143
* @param beanResolver the {@link BeanResolver} to use
143144
*/
144145
public void setBeanResolver(BeanResolver beanResolver) {
146+
Assert.notNull(beanResolver, "beanResolver cannot be null");
145147
this.beanResolver = beanResolver;
146148
}
147149

web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolver.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* https://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -29,6 +29,7 @@
2929
import org.springframework.security.core.annotation.CurrentSecurityContext;
3030
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
3131
import org.springframework.security.core.context.SecurityContext;
32+
import org.springframework.util.Assert;
3233
import org.springframework.util.StringUtils;
3334
import org.springframework.web.reactive.BindingContext;
3435
import org.springframework.web.reactive.result.method.HandlerMethodArgumentResolverSupport;
@@ -57,6 +58,7 @@ public CurrentSecurityContextArgumentResolver(ReactiveAdapterRegistry adapterReg
5758
* @param beanResolver the {@link BeanResolver} to use
5859
*/
5960
public void setBeanResolver(BeanResolver beanResolver) {
61+
Assert.notNull(beanResolver, "beanResolver cannot be null");
6062
this.beanResolver = beanResolver;
6163
}
6264

web/src/test/java/org/springframework/security/web/bind/support/CurrentSecurityContextArgumentResolverTests.java

+81-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* https://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -15,6 +15,10 @@
1515
*/
1616
package org.springframework.security.web.bind.support;
1717

18+
import java.lang.annotation.ElementType;
19+
import java.lang.annotation.Retention;
20+
import java.lang.annotation.RetentionPolicy;
21+
import java.lang.annotation.Target;
1822
import java.lang.reflect.Method;
1923

2024
import org.junit.After;
@@ -162,6 +166,32 @@ public void resolveArgumentSecurityContextErrorOnInvalidTypeTrue() throws Except
162166
null, null));
163167
}
164168

169+
@Test
170+
public void metaAnnotationWhenCurrentCustomSecurityContextThenInjectSecurityContext() throws Exception {
171+
assertThat(resolver.resolveArgument(showCurrentCustomSecurityContext(), null, null, null))
172+
.isNotNull();
173+
}
174+
175+
@Test
176+
public void metaAnnotationWhenCurrentAuthenticationThenInjectAuthentication() throws Exception {
177+
String principal = "current_authentcation";
178+
setAuthenticationPrincipal(principal);
179+
Authentication auth1 = (Authentication) resolver.resolveArgument(showCurrentAuthentication(), null, null, null);
180+
assertThat(auth1.getPrincipal()).isEqualTo(principal);
181+
}
182+
183+
@Test
184+
public void metaAnnotationWhenCurrentSecurityWithErrorOnInvalidTypeThenInjectSecurityContext() throws Exception {
185+
assertThat(resolver.resolveArgument(showCurrentSecurityWithErrorOnInvalidType(), null, null, null))
186+
.isNotNull();
187+
}
188+
189+
@Test
190+
public void metaAnnotationWhenCurrentSecurityWithErrorOnInvalidTypeThenMisMatch() throws Exception {
191+
assertThatExceptionOfType(ClassCastException.class).isThrownBy(() -> resolver.resolveArgument(showCurrentSecurityWithErrorOnInvalidTypeMisMatch(), null,
192+
null, null));
193+
}
194+
165195
private MethodParameter showSecurityContextNoAnnotation() {
166196
return getMethodParameter("showSecurityContextNoAnnotation", String.class);
167197
}
@@ -206,6 +236,22 @@ private MethodParameter showSecurityContextErrorOnInvalidTypeTrue() {
206236
return getMethodParameter("showSecurityContextErrorOnInvalidTypeTrue", String.class);
207237
}
208238

239+
public MethodParameter showCurrentCustomSecurityContext() {
240+
return getMethodParameter("showCurrentCustomSecurityContext", SecurityContext.class);
241+
}
242+
243+
public MethodParameter showCurrentAuthentication() {
244+
return getMethodParameter("showCurrentAuthentication", Authentication.class);
245+
}
246+
247+
public MethodParameter showCurrentSecurityWithErrorOnInvalidType() {
248+
return getMethodParameter("showCurrentSecurityWithErrorOnInvalidType", SecurityContext.class);
249+
}
250+
251+
public MethodParameter showCurrentSecurityWithErrorOnInvalidTypeMisMatch() {
252+
return getMethodParameter("showCurrentSecurityWithErrorOnInvalidTypeMisMatch", String.class);
253+
}
254+
209255
private MethodParameter getMethodParameter(String methodName, Class<?>... paramTypes) {
210256
Method method = ReflectionUtils.findMethod(TestController.class, methodName,
211257
paramTypes);
@@ -248,6 +294,22 @@ public void showSecurityContextErrorOnInvalidTypeFalse(
248294
public void showSecurityContextErrorOnInvalidTypeTrue(
249295
@CurrentSecurityContext(errorOnInvalidType = true) String implicit) {
250296
}
297+
298+
public void showCurrentCustomSecurityContext(
299+
@CurrentCustomSecurityContext SecurityContext context) {
300+
}
301+
302+
public void showCurrentAuthentication(
303+
@CurrentAuthentication Authentication authentication) {
304+
}
305+
306+
public void showCurrentSecurityWithErrorOnInvalidType(
307+
@CurrentSecurityWithErrorOnInvalidType SecurityContext context) {
308+
}
309+
310+
public void showCurrentSecurityWithErrorOnInvalidTypeMisMatch(
311+
@CurrentSecurityWithErrorOnInvalidType String typeMisMatch) {
312+
}
251313
}
252314

253315
private void setAuthenticationPrincipal(Object principal) {
@@ -277,6 +339,24 @@ public void setAuthentication(Authentication authentication) {
277339
}
278340
}
279341

342+
@Target({ ElementType.PARAMETER })
343+
@Retention(RetentionPolicy.RUNTIME)
344+
@CurrentSecurityContext
345+
static @interface CurrentCustomSecurityContext {
346+
}
347+
348+
@Target({ ElementType.PARAMETER })
349+
@Retention(RetentionPolicy.RUNTIME)
350+
@CurrentSecurityContext(expression = "authentication")
351+
static @interface CurrentAuthentication {
352+
}
353+
354+
@Target({ ElementType.PARAMETER })
355+
@Retention(RetentionPolicy.RUNTIME)
356+
@CurrentSecurityContext(errorOnInvalidType = true)
357+
static @interface CurrentSecurityWithErrorOnInvalidType {
358+
}
359+
280360
private void setAuthenticationDetail(Object detail) {
281361
TestingAuthenticationToken tat = new TestingAuthenticationToken("user", "password",
282362
"ROLE_USER");

web/src/test/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolverTests.java

+82-15
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* you may not use this file except in compliance with the License.
66
* You may obtain a copy of the License at
77
*
8-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* https://www.apache.org/licenses/LICENSE-2.0
99
*
1010
* Unless required by applicable law or agreed to in writing, software
1111
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,13 +16,19 @@
1616

1717
package org.springframework.security.web.reactive.result.method.annotation;
1818

19+
import static org.assertj.core.api.Assertions.assertThat;
20+
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
21+
22+
import java.lang.annotation.ElementType;
23+
import java.lang.annotation.Retention;
24+
import java.lang.annotation.RetentionPolicy;
25+
import java.lang.annotation.Target;
26+
1927
import org.junit.Before;
2028
import org.junit.Test;
2129
import org.junit.runner.RunWith;
2230
import org.mockito.Mock;
2331
import org.mockito.junit.MockitoJUnitRunner;
24-
import reactor.core.publisher.Mono;
25-
import reactor.util.context.Context;
2632

2733
import org.springframework.core.MethodParameter;
2834
import org.springframework.core.ReactiveAdapterRegistry;
@@ -37,8 +43,8 @@
3743
import org.springframework.web.reactive.BindingContext;
3844
import org.springframework.web.server.ServerWebExchange;
3945

40-
import static org.assertj.core.api.Assertions.assertThat;
41-
import static org.junit.Assert.fail;
46+
import reactor.core.publisher.Mono;
47+
import reactor.util.context.Context;
4248

4349

4450
/**
@@ -172,11 +178,7 @@ public void resolveArgumentWithNullDepthProp1() throws Exception {
172178
Authentication auth = null;
173179
Context context = ReactiveSecurityContextHolder.withAuthentication(auth);
174180
Mono<Object> argument = resolver.resolveArgument(parameter, bindingContext, exchange);
175-
try {
176-
Mono<Object> obj = (Mono<Object>) argument.subscriberContext(context).block();
177-
fail("should not reach here");
178-
} catch(SpelEvaluationException e) {
179-
}
181+
assertThatExceptionOfType(SpelEvaluationException.class).isThrownBy(() -> argument.subscriberContext(context).block());
180182
ReactiveSecurityContextHolder.clearContext();
181183
}
182184

@@ -219,11 +221,50 @@ public void resolveArgumentErrorOnInvalidTypeWhenExplicitTrue() throws Exception
219221
Authentication auth = buildAuthenticationWithPrincipal("error_on_invalid_type_explicit_true");
220222
Context context = ReactiveSecurityContextHolder.withAuthentication(auth);
221223
Mono<Object> argument = resolver.resolveArgument(parameter, bindingContext, exchange);
222-
try {
223-
Mono<String> obj = (Mono<String>) argument.subscriberContext(context).block();
224-
fail("should not reach here");
225-
} catch(ClassCastException ex) {
226-
}
224+
assertThatExceptionOfType(ClassCastException.class).isThrownBy(() -> argument.subscriberContext(context).block());
225+
ReactiveSecurityContextHolder.clearContext();
226+
}
227+
228+
@Test
229+
public void metaAnnotationWhenDefaultSecurityContextThenInjectSecurityContext() throws Exception {
230+
MethodParameter parameter = ResolvableMethod.on(getClass()).named("currentCustomSecurityContext").build().arg(Mono.class, SecurityContext.class);
231+
Authentication auth = buildAuthenticationWithPrincipal("current_custom_security_context");
232+
Context context = ReactiveSecurityContextHolder.withAuthentication(auth);
233+
Mono<Object> argument = resolver.resolveArgument(parameter, bindingContext, exchange);
234+
SecurityContext securityContext = (SecurityContext) argument.subscriberContext(context).cast(Mono.class).block().block();
235+
assertThat(securityContext.getAuthentication()).isSameAs(auth);
236+
ReactiveSecurityContextHolder.clearContext();
237+
}
238+
239+
@Test
240+
public void metaAnnotationWhenCurrentAuthenticationThenInjectAuthentication() throws Exception {
241+
MethodParameter parameter = ResolvableMethod.on(getClass()).named("currentAuthentication").build().arg(Mono.class, Authentication.class);
242+
Authentication auth = buildAuthenticationWithPrincipal("current_authentication");
243+
Context context = ReactiveSecurityContextHolder.withAuthentication(auth);
244+
Mono<Object> argument = resolver.resolveArgument(parameter, bindingContext, exchange);
245+
Authentication authentication = (Authentication) argument.subscriberContext(context).cast(Mono.class).block().block();
246+
assertThat(authentication).isSameAs(auth);
247+
ReactiveSecurityContextHolder.clearContext();
248+
}
249+
250+
@Test
251+
public void metaAnnotationWhenCurrentSecurityWithErrorOnInvalidTypeThenInjectSecurityContext() throws Exception {
252+
MethodParameter parameter = ResolvableMethod.on(getClass()).named("currentSecurityWithErrorOnInvalidType").build().arg(Mono.class, SecurityContext.class);
253+
Authentication auth = buildAuthenticationWithPrincipal("current_security_with_error_on_invalid_type");
254+
Context context = ReactiveSecurityContextHolder.withAuthentication(auth);
255+
Mono<Object> argument = resolver.resolveArgument(parameter, bindingContext, exchange);
256+
SecurityContext securityContext = (SecurityContext) argument.subscriberContext(context).cast(Mono.class).block().block();
257+
assertThat(securityContext.getAuthentication()).isSameAs(auth);
258+
ReactiveSecurityContextHolder.clearContext();
259+
}
260+
261+
@Test
262+
public void metaAnnotationWhenCurrentSecurityWithErrorOnInvalidTypeThenMisMatch() throws Exception {
263+
MethodParameter parameter = ResolvableMethod.on(getClass()).named("currentSecurityWithErrorOnInvalidTypeMisMatch").build().arg(Mono.class, String.class);
264+
Authentication auth = buildAuthenticationWithPrincipal("current_security_with_error_on_invalid_type_mismatch");
265+
Context context = ReactiveSecurityContextHolder.withAuthentication(auth);
266+
Mono<Object> argument = resolver.resolveArgument(parameter, bindingContext, exchange);
267+
assertThatExceptionOfType(ClassCastException.class).isThrownBy(() -> argument.subscriberContext(context).cast(Mono.class).block().block());
227268
ReactiveSecurityContextHolder.clearContext();
228269
}
229270

@@ -245,6 +286,32 @@ void errorOnInvalidTypeWhenExplicitFalse(@CurrentSecurityContext(errorOnInvalidT
245286

246287
void errorOnInvalidTypeWhenExplicitTrue(@CurrentSecurityContext(errorOnInvalidType = true) Mono<String> implicit) {}
247288

289+
void currentCustomSecurityContext(@CurrentCustomSecurityContext Mono<SecurityContext> monoSecurityContext) {}
290+
291+
void currentAuthentication(@CurrentAuthentication Mono<Authentication> authentication) {}
292+
293+
void currentSecurityWithErrorOnInvalidType(@CurrentSecurityWithErrorOnInvalidType Mono<SecurityContext> monoSecurityContext) {}
294+
295+
void currentSecurityWithErrorOnInvalidTypeMisMatch(@CurrentSecurityWithErrorOnInvalidType Mono<String> typeMisMatch) {}
296+
297+
@Target({ ElementType.PARAMETER })
298+
@Retention(RetentionPolicy.RUNTIME)
299+
@CurrentSecurityContext
300+
static @interface CurrentCustomSecurityContext {
301+
}
302+
303+
@Target({ ElementType.PARAMETER })
304+
@Retention(RetentionPolicy.RUNTIME)
305+
@CurrentSecurityContext(expression = "authentication")
306+
static @interface CurrentAuthentication {
307+
}
308+
309+
@Target({ ElementType.PARAMETER })
310+
@Retention(RetentionPolicy.RUNTIME)
311+
@CurrentSecurityContext(errorOnInvalidType = true)
312+
static @interface CurrentSecurityWithErrorOnInvalidType {
313+
}
314+
248315
static class CustomSecurityContext implements SecurityContext {
249316
private Authentication authentication;
250317
public CustomSecurityContext(Authentication authentication) {

0 commit comments

Comments
 (0)