Correct order of authentication resolvers
Closes gh-982
This commit is contained in:
@@ -277,6 +277,10 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
|
||||
resolvers.addResolver(new ArgumentsMethodArgumentResolver(argumentBinder));
|
||||
resolvers.addResolver(new ContextValueMethodArgumentResolver());
|
||||
resolvers.addResolver(new LocalContextValueMethodArgumentResolver());
|
||||
if (springSecurityPresent) {
|
||||
ApplicationContext context = obtainApplicationContext();
|
||||
resolvers.addResolver(new AuthenticationPrincipalArgumentResolver(new BeanFactoryResolver(context)));
|
||||
}
|
||||
|
||||
// Type based
|
||||
resolvers.addResolver(new DataFetchingEnvironmentMethodArgumentResolver());
|
||||
@@ -284,9 +288,7 @@ public class AnnotatedControllerConfigurer implements ApplicationContextAware, I
|
||||
addSubrangeMethodArgumentResolver(resolvers);
|
||||
addSortMethodArgumentResolver(resolvers);
|
||||
if (springSecurityPresent) {
|
||||
ApplicationContext context = obtainApplicationContext();
|
||||
resolvers.addResolver(new PrincipalMethodArgumentResolver());
|
||||
resolvers.addResolver(new AuthenticationPrincipalArgumentResolver(new BeanFactoryResolver(context)));
|
||||
}
|
||||
if (KotlinDetector.isKotlinPresent()) {
|
||||
resolvers.addResolver(new ContinuationHandlerMethodArgumentResolver());
|
||||
|
||||
@@ -44,7 +44,9 @@ import org.springframework.graphql.execution.DataFetcherExceptionResolver;
|
||||
import org.springframework.graphql.execution.ErrorType;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.security.authentication.TestingAuthenticationToken;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextImpl;
|
||||
@@ -79,7 +81,7 @@ public class SchemaMappingPrincipalMethodArgumentResolverTests {
|
||||
|
||||
@Test
|
||||
void supportsParameter() {
|
||||
Method method = ClassUtils.getMethod(SchemaMappingPrincipalMethodArgumentResolverTests.class, "handle", (Class<?>[]) null);
|
||||
Method method = ClassUtils.getMethod(getClass(), "handle", (Class<?>[]) null);
|
||||
assertThat(this.resolver.supportsParameter(new MethodParameter(method, 0))).isTrue();
|
||||
assertThat(this.resolver.supportsParameter(new MethodParameter(method, 1))).isTrue();
|
||||
assertThat(this.resolver.supportsParameter(new MethodParameter(method, 2))).isFalse();
|
||||
@@ -121,10 +123,10 @@ public class SchemaMappingPrincipalMethodArgumentResolverTests {
|
||||
@Test
|
||||
void nonNullPrincipalRequiresSecurityContext() {
|
||||
DataFetcherExceptionResolver exceptionResolver =
|
||||
DataFetcherExceptionResolver.forSingleError((ex, env) -> GraphqlErrorBuilder.newError(env)
|
||||
.message("Resolved error: " + ex.getMessage())
|
||||
.errorType(ErrorType.UNAUTHORIZED)
|
||||
.build());
|
||||
DataFetcherExceptionResolver.forSingleError((ex, env) -> GraphqlErrorBuilder.newError(env)
|
||||
.message("Resolved error: " + ex.getMessage())
|
||||
.errorType(ErrorType.UNAUTHORIZED)
|
||||
.build());
|
||||
|
||||
Mono<ExecutionGraphQlResponse> responseMono = executeAsync(
|
||||
"type Query { greetingMono: String }", "{ greetingMono }",
|
||||
@@ -217,20 +219,47 @@ public class SchemaMappingPrincipalMethodArgumentResolverTests {
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Nested
|
||||
class AuthenticationPrincipalTests {
|
||||
|
||||
@Test // gh-982
|
||||
void query() {
|
||||
Authentication authentication = new UsernamePasswordAuthenticationToken(new GraphQlPrincipal(), null);
|
||||
SecurityContextHolder.setContext(new SecurityContextImpl(authentication));
|
||||
try {
|
||||
String field = "greetingAuthenticationPrincipal";
|
||||
Mono<ExecutionGraphQlResponse> responseMono = executeAsync(
|
||||
"type Query { " + field + " : String }", "{ " + field + " }", threadLocalContextWriter);
|
||||
|
||||
String greeting = ResponseHelper.forResponse(responseMono).toEntity(field, String.class);
|
||||
assertThat(greeting).isEqualTo("Hello");
|
||||
assertThat(greetingController.principal()).isSameAs(authentication.getPrincipal());
|
||||
}
|
||||
finally {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private Mono<ExecutionGraphQlResponse> executeAsync(
|
||||
String schema, String document, Function<Context, Context> contextWriter) {
|
||||
|
||||
return executeAsync(schema, document, contextWriter, null);
|
||||
}
|
||||
|
||||
private Mono<ExecutionGraphQlResponse> executeAsync(
|
||||
String schema, String document, Function<Context, Context> contextWriter, @Nullable DataFetcherExceptionResolver exceptionResolver) {
|
||||
String schema, String document, Function<Context, Context> contextWriter,
|
||||
@Nullable DataFetcherExceptionResolver exceptionResolver) {
|
||||
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.registerBean(GreetingController.class, () -> greetingController);
|
||||
context.refresh();
|
||||
|
||||
GraphQlSetup graphQlSetup = GraphQlSetup.schemaContent(schema)
|
||||
.runtimeWiringForAnnotatedControllers(context);
|
||||
GraphQlSetup graphQlSetup =
|
||||
GraphQlSetup.schemaContent(schema).runtimeWiringForAnnotatedControllers(context);
|
||||
|
||||
if (exceptionResolver != null) {
|
||||
graphQlSetup.exceptionResolver(exceptionResolver);
|
||||
@@ -288,6 +317,22 @@ public class SchemaMappingPrincipalMethodArgumentResolverTests {
|
||||
return Flux.just("Hello", "Hi");
|
||||
}
|
||||
|
||||
@QueryMapping
|
||||
String greetingAuthenticationPrincipal(@AuthenticationPrincipal GraphQlPrincipal principal) {
|
||||
this.principal = principal;
|
||||
return "Hello";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static final class GraphQlPrincipal implements Principal {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user