|
45 | 45 | import org.springframework.graphql.execution.ErrorType;
|
46 | 46 | import org.springframework.lang.Nullable;
|
47 | 47 | import org.springframework.security.authentication.TestingAuthenticationToken;
|
| 48 | +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; |
48 | 49 | import org.springframework.security.core.Authentication;
|
| 50 | +import org.springframework.security.core.annotation.AuthenticationPrincipal; |
49 | 51 | import org.springframework.security.core.context.ReactiveSecurityContextHolder;
|
50 | 52 | import org.springframework.security.core.context.SecurityContextHolder;
|
51 | 53 | import org.springframework.security.core.context.SecurityContextImpl;
|
@@ -82,7 +84,7 @@ public class SchemaMappingPrincipalMethodArgumentResolverTests {
|
82 | 84 |
|
83 | 85 | @Test
|
84 | 86 | void supportsParameter() {
|
85 |
| - Method method = ClassUtils.getMethod(SchemaMappingPrincipalMethodArgumentResolverTests.class, "handle", (Class<?>[]) null); |
| 87 | + Method method = ClassUtils.getMethod(getClass(), "handle", (Class<?>[]) null); |
86 | 88 | assertThat(this.resolver.supportsParameter(new MethodParameter(method, 0))).isTrue();
|
87 | 89 | assertThat(this.resolver.supportsParameter(new MethodParameter(method, 1))).isTrue();
|
88 | 90 | assertThat(this.resolver.supportsParameter(new MethodParameter(method, 2))).isFalse();
|
@@ -124,10 +126,10 @@ void nullablePrincipalDoesntRequireSecurityContext() {
|
124 | 126 | @Test
|
125 | 127 | void nonNullPrincipalRequiresSecurityContext() {
|
126 | 128 | DataFetcherExceptionResolver exceptionResolver =
|
127 |
| - DataFetcherExceptionResolver.forSingleError((ex, env) -> GraphqlErrorBuilder.newError(env) |
128 |
| - .message("Resolved error: " + ex.getMessage()) |
129 |
| - .errorType(ErrorType.UNAUTHORIZED) |
130 |
| - .build()); |
| 129 | + DataFetcherExceptionResolver.forSingleError((ex, env) -> GraphqlErrorBuilder.newError(env) |
| 130 | + .message("Resolved error: " + ex.getMessage()) |
| 131 | + .errorType(ErrorType.UNAUTHORIZED) |
| 132 | + .build()); |
131 | 133 |
|
132 | 134 | Mono<ExecutionGraphQlResponse> responseMono = executeAsync(
|
133 | 135 | "type Query { greetingMono: String }", "{ greetingMono }",
|
@@ -220,20 +222,47 @@ private void testSubscription(Function<Context, Context> contextModifier) {
|
220 | 222 |
|
221 | 223 | }
|
222 | 224 |
|
| 225 | + |
| 226 | + @Nested |
| 227 | + class AuthenticationPrincipalTests { |
| 228 | + |
| 229 | + @Test // gh-982 |
| 230 | + void query() { |
| 231 | + Authentication authentication = new UsernamePasswordAuthenticationToken(new GraphQlPrincipal(), null); |
| 232 | + SecurityContextHolder.setContext(new SecurityContextImpl(authentication)); |
| 233 | + try { |
| 234 | + String field = "greetingAuthenticationPrincipal"; |
| 235 | + Mono<ExecutionGraphQlResponse> responseMono = executeAsync( |
| 236 | + "type Query { " + field + " : String }", "{ " + field + " }", threadLocalContextWriter); |
| 237 | + |
| 238 | + String greeting = ResponseHelper.forResponse(responseMono).toEntity(field, String.class); |
| 239 | + assertThat(greeting).isEqualTo("Hello"); |
| 240 | + assertThat(greetingController.principal()).isSameAs(authentication.getPrincipal()); |
| 241 | + } |
| 242 | + finally { |
| 243 | + SecurityContextHolder.clearContext(); |
| 244 | + } |
| 245 | + } |
| 246 | + |
| 247 | + } |
| 248 | + |
| 249 | + |
223 | 250 | private Mono<ExecutionGraphQlResponse> executeAsync(
|
224 | 251 | String schema, String document, Function<Context, Context> contextWriter) {
|
| 252 | + |
225 | 253 | return executeAsync(schema, document, contextWriter, null);
|
226 | 254 | }
|
227 | 255 |
|
228 | 256 | private Mono<ExecutionGraphQlResponse> executeAsync(
|
229 |
| - String schema, String document, Function<Context, Context> contextWriter, @Nullable DataFetcherExceptionResolver exceptionResolver) { |
| 257 | + String schema, String document, Function<Context, Context> contextWriter, |
| 258 | + @Nullable DataFetcherExceptionResolver exceptionResolver) { |
230 | 259 |
|
231 | 260 | AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
232 | 261 | context.registerBean(GreetingController.class, () -> greetingController);
|
233 | 262 | context.refresh();
|
234 | 263 |
|
235 |
| - GraphQlSetup graphQlSetup = GraphQlSetup.schemaContent(schema) |
236 |
| - .runtimeWiringForAnnotatedControllers(context); |
| 264 | + GraphQlSetup graphQlSetup = |
| 265 | + GraphQlSetup.schemaContent(schema).runtimeWiringForAnnotatedControllers(context); |
237 | 266 |
|
238 | 267 | if (exceptionResolver != null) {
|
239 | 268 | graphQlSetup.exceptionResolver(exceptionResolver);
|
@@ -291,6 +320,22 @@ Flux<String> greetingSubscription(Principal principal) {
|
291 | 320 | return Flux.just("Hello", "Hi");
|
292 | 321 | }
|
293 | 322 |
|
| 323 | + @QueryMapping |
| 324 | + String greetingAuthenticationPrincipal(@AuthenticationPrincipal GraphQlPrincipal principal) { |
| 325 | + this.principal = principal; |
| 326 | + return "Hello"; |
| 327 | + } |
| 328 | + |
| 329 | + } |
| 330 | + |
| 331 | + |
| 332 | + private static final class GraphQlPrincipal implements Principal { |
| 333 | + |
| 334 | + @Override |
| 335 | + public String getName() { |
| 336 | + return ""; |
| 337 | + } |
| 338 | + |
294 | 339 | }
|
295 | 340 |
|
296 | 341 | }
|
0 commit comments