|
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