From 570eb01733cfcaed5696bb8ee5880e0be909ce3c Mon Sep 17 00:00:00 2001
From: Dan Zheng
Date: Sat, 2 Mar 2019 12:28:22 +0800
Subject: [PATCH] review phase1
---
.../WebMvcSecurityConfiguration.java | 3 +-
.../ServerHttpSecurityConfiguration.java | 3 +-
.../annotation/CurrentSecurityContext.java | 26 +++-----
...urrentSecurityContextArgumentResolver.java | 8 +--
...urrentSecurityContextArgumentResolver.java | 2 +-
...tSecurityContextArgumentResolverTests.java | 64 ++++++++++++++++---
...tSecurityContextArgumentResolverTests.java | 35 +++++++++-
7 files changed, 106 insertions(+), 35 deletions(-)
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java
index 707e8775f7..3c49395b99 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/configuration/WebMvcSecurityConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -40,6 +40,7 @@ import java.util.List;
* {@link HandlerMethodArgumentResolver}.
*
* @author Rob Winch
+ * @author Dan Zheng
* @since 3.2
*/
class WebMvcSecurityConfiguration implements WebMvcConfigurer, ApplicationContextAware {
diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java b/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java
index ae7ed2ede0..8cc8378f09 100644
--- a/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java
+++ b/config/src/main/java/org/springframework/security/config/annotation/web/reactive/ServerHttpSecurityConfiguration.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2018 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@ import org.springframework.web.reactive.result.method.annotation.ArgumentResolve
/**
* @author Rob Winch
+ * @author Dan Zheng
* @since 5.0
*/
@Configuration
diff --git a/core/src/main/java/org/springframework/security/core/annotation/CurrentSecurityContext.java b/core/src/main/java/org/springframework/security/core/annotation/CurrentSecurityContext.java
index fbbe2c95ed..da7596b559 100644
--- a/core/src/main/java/org/springframework/security/core/annotation/CurrentSecurityContext.java
+++ b/core/src/main/java/org/springframework/security/core/annotation/CurrentSecurityContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@ import java.lang.annotation.Target;
* argument.
*
* @author Dan Zheng
- * @since 5.2.x
+ * @since 5.2
*
* See:
+ * @CurrentSecurityContext(expression = "authentication") Authentication authentication
+ *
+ *
*
- * For example, perhaps the user wants to resolve a CustomUser object that is final
- * and is leveraging a UserDetailsService. This can be handled by returning an object
- * that looks like:
+ * if you want to retrieve more object from the authentcation, you can see the following the expression
*
*
*
- * public class CustomUserUserDetails extends User {
- * // ...
- * public CustomUser getCustomUser() {
- * return customUser;
- * }
- * }
- *
- *
- * Then the user can specify an annotation that looks like:
- *
- *
- * @CurrentSecurityContext(expression = "authentication")
+ * @CurrentSecurityContext(expression = "authentication.principal") Object principal
*
*
* @return the expression to use.
diff --git a/web/src/main/java/org/springframework/security/web/bind/support/CurrentSecurityContextArgumentResolver.java b/web/src/main/java/org/springframework/security/web/bind/support/CurrentSecurityContextArgumentResolver.java
index 634801f6f4..8a0832617c 100644
--- a/web/src/main/java/org/springframework/security/web/bind/support/CurrentSecurityContextArgumentResolver.java
+++ b/web/src/main/java/org/springframework/security/web/bind/support/CurrentSecurityContextArgumentResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2013 the original author or authors.
+ * Copyright 2002-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
*/
package org.springframework.security.web.bind.support;
+import java.lang.annotation.Annotation;
+
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.expression.BeanResolver;
@@ -32,8 +34,6 @@ import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
-import java.lang.annotation.Annotation;
-
/**
* Allows resolving the {@link SecurityContext} using the
* {@link CurrentSecurityContext} annotation. For example, the following
@@ -69,7 +69,7 @@ import java.lang.annotation.Annotation;
*
*
* @author Dan Zheng
- * @since 5.2.x
+ * @since 5.2
*/
public final class CurrentSecurityContextArgumentResolver
implements HandlerMethodArgumentResolver {
diff --git a/web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolver.java b/web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolver.java
index 20a75e32bd..bb4c61b27d 100644
--- a/web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolver.java
+++ b/web/src/main/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolver.java
@@ -40,7 +40,7 @@ import java.lang.annotation.Annotation;
/**
* Resolves the SecurityContext
* @author Dan Zheng
- * @since 5.2.x
+ * @since 5.2
*/
public class CurrentSecurityContextArgumentResolver extends HandlerMethodArgumentResolverSupport {
diff --git a/web/src/test/java/org/springframework/security/web/bind/support/CurrentSecurityContextArgumentResolverTests.java b/web/src/test/java/org/springframework/security/web/bind/support/CurrentSecurityContextArgumentResolverTests.java
index e0256ea8fa..739880f9ad 100644
--- a/web/src/test/java/org/springframework/security/web/bind/support/CurrentSecurityContextArgumentResolverTests.java
+++ b/web/src/test/java/org/springframework/security/web/bind/support/CurrentSecurityContextArgumentResolverTests.java
@@ -15,9 +15,12 @@
*/
package org.springframework.security.web.bind.support;
+import java.lang.reflect.Method;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
+
import org.springframework.core.MethodParameter;
import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.security.authentication.TestingAuthenticationToken;
@@ -29,15 +32,12 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.util.ReflectionUtils;
-import java.lang.reflect.Method;
-
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
-import static org.junit.Assert.fail;
/**
* @author Dan Zheng
- * @since 5.2.x
+ * @since 5.2
*
*/
public class CurrentSecurityContextArgumentResolverTests {
@@ -64,6 +64,22 @@ public class CurrentSecurityContextArgumentResolverTests {
assertThat(resolver.supportsParameter(showSecurityContextAnnotation())).isTrue();
}
+ @Test
+ public void resolveArgumentWithCustomSecurityContext() throws Exception {
+ String principal = "custom_security_context";
+ setAuthenticationPrincipalWithCustomSecurityContext(principal);
+ CustomSecurityContext customSecurityContext = (CustomSecurityContext) resolver.resolveArgument(showAnnotationWithCustomSecurityContext(), null, null, null);
+ assertThat(customSecurityContext.getAuthentication().getPrincipal()).isEqualTo(principal);
+ }
+
+ @Test
+ public void resolveArgumentWithCustomSecurityContextTypeMatch() throws Exception {
+ String principal = "custom_security_context_type_match";
+ setAuthenticationPrincipalWithCustomSecurityContext(principal);
+ CustomSecurityContext customSecurityContext = (CustomSecurityContext) resolver.resolveArgument(showAnnotationWithCustomSecurityContext(), null, null, null);
+ assertThat(customSecurityContext.getAuthentication().getPrincipal()).isEqualTo(principal);
+ }
+
@Test
public void resolveArgumentNullAuthentication() throws Exception {
SecurityContext context = SecurityContextHolder.getContext();
@@ -142,10 +158,8 @@ public class CurrentSecurityContextArgumentResolverTests {
public void resolveArgumentSecurityContextErrorOnInvalidTypeTrue() throws Exception {
String principal = "invalid_type_true";
setAuthenticationPrincipal(principal);
- try {
- resolver.resolveArgument(showSecurityContextErrorOnInvalidTypeTrue(), null, null, null);
- fail("should not reach here");
- } catch(ClassCastException ex) {}
+ assertThatExceptionOfType(ClassCastException.class).isThrownBy(() -> resolver.resolveArgument(showSecurityContextErrorOnInvalidTypeTrue(), null,
+ null, null));
}
private MethodParameter showSecurityContextNoAnnotation() {
@@ -156,6 +170,14 @@ public class CurrentSecurityContextArgumentResolverTests {
return getMethodParameter("showSecurityContextAnnotation", SecurityContext.class);
}
+ private MethodParameter showAnnotationWithCustomSecurityContext() {
+ return getMethodParameter("showAnnotationWithCustomSecurityContext", CustomSecurityContext.class);
+ }
+
+ private MethodParameter showAnnotationWithCustomSecurityContextTypeMatch() {
+ return getMethodParameter("showAnnotationWithCustomSecurityContextTypeMatch", SecurityContext.class);
+ }
+
private MethodParameter showSecurityContextAuthenticationAnnotation() {
return getMethodParameter("showSecurityContextAuthenticationAnnotation", Authentication.class);
}
@@ -197,6 +219,12 @@ public class CurrentSecurityContextArgumentResolverTests {
public void showSecurityContextAnnotation(@CurrentSecurityContext SecurityContext context) {
}
+ public void showAnnotationWithCustomSecurityContext(@CurrentSecurityContext CustomSecurityContext context) {
+ }
+
+ public void showAnnotationWithCustomSecurityContextTypeMatch(@CurrentSecurityContext(errorOnInvalidType = true) SecurityContext context) {
+ }
+
public void showSecurityContextAuthenticationAnnotation(@CurrentSecurityContext(expression = "authentication") Authentication authentication) {
}
@@ -229,6 +257,26 @@ public class CurrentSecurityContextArgumentResolverTests {
"ROLE_USER"));
}
+ private void setAuthenticationPrincipalWithCustomSecurityContext(Object principal) {
+ CustomSecurityContext csc = new CustomSecurityContext();
+ csc.setAuthentication(new TestingAuthenticationToken(principal, "password",
+ "ROLE_USER"));
+ SecurityContextHolder.setContext(csc);
+ }
+
+ static class CustomSecurityContext implements SecurityContext {
+ private Authentication authentication;
+ @Override
+ public Authentication getAuthentication() {
+ return authentication;
+ }
+
+ @Override
+ public void setAuthentication(Authentication authentication) {
+ this.authentication = authentication;
+ }
+ }
+
private void setAuthenticationDetail(Object detail) {
TestingAuthenticationToken tat = new TestingAuthenticationToken("user", "password",
"ROLE_USER");
diff --git a/web/src/test/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolverTests.java b/web/src/test/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolverTests.java
index a34560d926..e044f6dc75 100644
--- a/web/src/test/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolverTests.java
+++ b/web/src/test/java/org/springframework/security/web/reactive/result/method/annotation/CurrentSecurityContextArgumentResolverTests.java
@@ -21,6 +21,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
+import reactor.core.publisher.Mono;
+import reactor.util.context.Context;
+
import org.springframework.core.MethodParameter;
import org.springframework.core.ReactiveAdapterRegistry;
import org.springframework.expression.BeanResolver;
@@ -33,15 +36,14 @@ import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.web.method.ResolvableMethod;
import org.springframework.web.reactive.BindingContext;
import org.springframework.web.server.ServerWebExchange;
-import reactor.core.publisher.Mono;
-import reactor.util.context.Context;
+
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
/**
* @author Dan Zheng
- * @since 5.2.x
+ * @since 5.2
*/
@RunWith(MockitoJUnitRunner.class)
public class CurrentSecurityContextArgumentResolverTests {
@@ -98,6 +100,17 @@ public class CurrentSecurityContextArgumentResolverTests {
ReactiveSecurityContextHolder.clearContext();
}
+ @Test
+ public void resolveArgumentWithCustomSecurityContext() throws Exception {
+ MethodParameter parameter = ResolvableMethod.on(getClass()).named("customSecurityContext").build().arg(Mono.class, SecurityContext.class);
+ Authentication auth = buildAuthenticationWithPrincipal("hello");
+ Context context = ReactiveSecurityContextHolder.withSecurityContext(Mono.just(new CustomSecurityContext(auth)));
+ Mono argument = resolver.resolveArgument(parameter, bindingContext, exchange);
+ CustomSecurityContext securityContext = (CustomSecurityContext) argument.subscriberContext(context).cast(Mono.class).block().block();
+ assertThat(securityContext.getAuthentication()).isSameAs(auth);
+ ReactiveSecurityContextHolder.clearContext();
+ }
+
@Test
public void resolveArgumentWithNullAuthentication1() throws Exception {
MethodParameter parameter = ResolvableMethod.on(getClass()).named("securityContext").build().arg(Mono.class, SecurityContext.class);
@@ -216,6 +229,8 @@ public class CurrentSecurityContextArgumentResolverTests {
void securityContext(@CurrentSecurityContext Mono monoSecurityContext) {}
+ void customSecurityContext(@CurrentSecurityContext Mono monoSecurityContext) {}
+
void securityContextWithAuthentication(@CurrentSecurityContext(expression = "authentication") Mono authentication) {}
void securityContextWithDepthPropOptional(@CurrentSecurityContext(expression = "authentication?.principal") Mono principal) {}
@@ -230,7 +245,21 @@ public class CurrentSecurityContextArgumentResolverTests {
void errorOnInvalidTypeWhenExplicitTrue(@CurrentSecurityContext(errorOnInvalidType = true) Mono implicit) {}
+ static class CustomSecurityContext implements SecurityContext {
+ private Authentication authentication;
+ public CustomSecurityContext(Authentication authentication) {
+ this.authentication = authentication;
+ }
+ @Override
+ public Authentication getAuthentication() {
+ return authentication;
+ }
+ @Override
+ public void setAuthentication(Authentication authentication) {
+ this.authentication = authentication;
+ }
+ }
private Authentication buildAuthenticationWithPrincipal(Object principal) {
return new TestingAuthenticationToken(principal, "password",
"ROLE_USER");