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