diff --git a/spring-graphql/src/main/java/org/springframework/graphql/security/ReactiveSecurityDataFetcherExceptionResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/ReactiveSecurityDataFetcherExceptionResolver.java similarity index 70% rename from spring-graphql/src/main/java/org/springframework/graphql/security/ReactiveSecurityDataFetcherExceptionResolver.java rename to spring-graphql/src/main/java/org/springframework/graphql/execution/ReactiveSecurityDataFetcherExceptionResolver.java index dd1db5ae..b5033664 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/security/ReactiveSecurityDataFetcherExceptionResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/ReactiveSecurityDataFetcherExceptionResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 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. @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.graphql.security; +package org.springframework.graphql.execution; import java.util.Collections; import java.util.List; @@ -22,9 +22,9 @@ import graphql.GraphQLError; import graphql.schema.DataFetchingEnvironment; import reactor.core.publisher.Mono; -import org.springframework.graphql.execution.DataFetcherExceptionResolver; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.authentication.AuthenticationTrustResolver; +import org.springframework.security.authentication.AuthenticationTrustResolverImpl; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.ReactiveSecurityContextHolder; @@ -40,36 +40,32 @@ import org.springframework.security.core.context.ReactiveSecurityContextHolder; */ public class ReactiveSecurityDataFetcherExceptionResolver implements DataFetcherExceptionResolver { - private final ExceptionResolverDelegate resolverDelegate = new ExceptionResolverDelegate(); + private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); /** * Set the resolver to use to check if an authentication is anonymous that * in turn determines whether {@code AccessDeniedException} is classified * as "unauthorized" or "forbidden". - * @param resolver the resolver to use + * @param trustResolver the resolver to use */ - public void setAuthenticationTrustResolver(AuthenticationTrustResolver resolver) { - this.resolverDelegate.setAuthenticationTrustResolver(resolver); + public void setAuthenticationTrustResolver(AuthenticationTrustResolver trustResolver) { + this.trustResolver = trustResolver; } @Override - public Mono> resolveException(Throwable ex, DataFetchingEnvironment env) { + public Mono> resolveException(Throwable ex, DataFetchingEnvironment environment) { if (ex instanceof AuthenticationException) { - GraphQLError error = this.resolverDelegate.resolveUnauthorized(env); + GraphQLError error = SecurityExceptionResolverUtils.resolveUnauthorized(environment); return Mono.just(Collections.singletonList(error)); } if (ex instanceof AccessDeniedException) { return ReactiveSecurityContextHolder.getContext() - .map(context -> { - GraphQLError error = this.resolverDelegate.resolveAccessDenied(env, context); - return Collections.singletonList(error); - }) - .switchIfEmpty(Mono.fromCallable(() -> { - GraphQLError error = this.resolverDelegate.resolveUnauthorized(env); - return Collections.singletonList(error); - })); + .map(context -> Collections.singletonList( + SecurityExceptionResolverUtils.resolveAccessDenied(environment, this.trustResolver, context))) + .switchIfEmpty(Mono.fromCallable(() -> Collections.singletonList( + SecurityExceptionResolverUtils.resolveUnauthorized(environment)))); } return Mono.empty(); } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/security/SecurityContextThreadLocalAccessor.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityContextThreadLocalAccessor.java similarity index 58% rename from spring-graphql/src/main/java/org/springframework/graphql/security/SecurityContextThreadLocalAccessor.java rename to spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityContextThreadLocalAccessor.java index 66becbfb..84134680 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/security/SecurityContextThreadLocalAccessor.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityContextThreadLocalAccessor.java @@ -1,8 +1,22 @@ -package org.springframework.graphql.security; +/* + * Copyright 2002-2022 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. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.graphql.execution; import java.util.Map; -import org.springframework.graphql.execution.ThreadLocalAccessor; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; diff --git a/spring-graphql/src/main/java/org/springframework/graphql/security/SecurityDataFetcherExceptionResolver.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityDataFetcherExceptionResolver.java similarity index 76% rename from spring-graphql/src/main/java/org/springframework/graphql/security/SecurityDataFetcherExceptionResolver.java rename to spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityDataFetcherExceptionResolver.java index 7844199a..2aabd3c1 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/security/SecurityDataFetcherExceptionResolver.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityDataFetcherExceptionResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 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. @@ -13,14 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.graphql.security; +package org.springframework.graphql.execution; import graphql.GraphQLError; import graphql.schema.DataFetchingEnvironment; -import org.springframework.graphql.execution.DataFetcherExceptionResolverAdapter; import org.springframework.security.access.AccessDeniedException; import org.springframework.security.authentication.AuthenticationTrustResolver; +import org.springframework.security.authentication.AuthenticationTrustResolverImpl; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; @@ -36,7 +36,7 @@ import org.springframework.security.core.context.SecurityContextHolder; */ public class SecurityDataFetcherExceptionResolver extends DataFetcherExceptionResolverAdapter { - private final ExceptionResolverDelegate resolverDelegate = new ExceptionResolverDelegate(); + private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl(); public SecurityDataFetcherExceptionResolver() { @@ -48,21 +48,21 @@ public class SecurityDataFetcherExceptionResolver extends DataFetcherExceptionRe * Set the resolver to use to check if an authentication is anonymous that * in turn determines whether {@code AccessDeniedException} is classified * as "unauthorized" or "forbidden". - * @param resolver the resolver to use + * @param trustResolver the resolver to use */ - public void setAuthenticationTrustResolver(AuthenticationTrustResolver resolver) { - this.resolverDelegate.setAuthenticationTrustResolver(resolver); + public void setAuthenticationTrustResolver(AuthenticationTrustResolver trustResolver) { + this.trustResolver = trustResolver; } @Override - protected GraphQLError resolveToSingleError(Throwable ex, DataFetchingEnvironment env) { + protected GraphQLError resolveToSingleError(Throwable ex, DataFetchingEnvironment environment) { if (ex instanceof AuthenticationException) { - return this.resolverDelegate.resolveUnauthorized(env); + return SecurityExceptionResolverUtils.resolveUnauthorized(environment); } if (ex instanceof AccessDeniedException) { SecurityContext securityContext = SecurityContextHolder.getContext(); - return this.resolverDelegate.resolveAccessDenied(env, securityContext); + return SecurityExceptionResolverUtils.resolveAccessDenied(environment, this.trustResolver, securityContext); } return null; } diff --git a/spring-graphql/src/main/java/org/springframework/graphql/security/ExceptionResolverDelegate.java b/spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityExceptionResolverUtils.java similarity index 60% rename from spring-graphql/src/main/java/org/springframework/graphql/security/ExceptionResolverDelegate.java rename to spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityExceptionResolverUtils.java index ea523aa1..dd84e95a 100644 --- a/spring-graphql/src/main/java/org/springframework/graphql/security/ExceptionResolverDelegate.java +++ b/spring-graphql/src/main/java/org/springframework/graphql/execution/SecurityExceptionResolverUtils.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2021 the original author or authors. + * Copyright 2002-2022 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. @@ -13,17 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.springframework.graphql.security; +package org.springframework.graphql.execution; import graphql.GraphQLError; import graphql.GraphqlErrorBuilder; import graphql.schema.DataFetchingEnvironment; -import org.springframework.graphql.execution.ErrorType; import org.springframework.security.authentication.AuthenticationTrustResolver; -import org.springframework.security.authentication.AuthenticationTrustResolverImpl; import org.springframework.security.core.context.SecurityContext; -import org.springframework.util.Assert; /** * Package private delegate class shared by the reactive and non-reactive resolver types. @@ -31,25 +28,19 @@ import org.springframework.util.Assert; * @author Rossen Stoyanchev * @since 1.0.0 */ -class ExceptionResolverDelegate { +class SecurityExceptionResolverUtils { - private AuthenticationTrustResolver resolver = new AuthenticationTrustResolverImpl(); - - - public void setAuthenticationTrustResolver(AuthenticationTrustResolver resolver) { - Assert.notNull(resolver, "AuthenticationTrustResolver is required"); - this.resolver = resolver; - } - - public GraphQLError resolveUnauthorized(DataFetchingEnvironment environment) { + static GraphQLError resolveUnauthorized(DataFetchingEnvironment environment) { return GraphqlErrorBuilder.newError(environment) .errorType(ErrorType.UNAUTHORIZED) .message("Unauthorized") .build(); } - public GraphQLError resolveAccessDenied(DataFetchingEnvironment env, SecurityContext securityContext) { - return this.resolver.isAnonymous(securityContext.getAuthentication()) ? + static GraphQLError resolveAccessDenied( + DataFetchingEnvironment env, AuthenticationTrustResolver resolver, SecurityContext securityContext) { + + return resolver.isAnonymous(securityContext.getAuthentication()) ? resolveUnauthorized(env) : GraphqlErrorBuilder.newError(env) .errorType(ErrorType.FORBIDDEN) diff --git a/spring-graphql/src/main/java/org/springframework/graphql/security/package-info.java b/spring-graphql/src/main/java/org/springframework/graphql/security/package-info.java deleted file mode 100644 index 2a0fa51d..00000000 --- a/spring-graphql/src/main/java/org/springframework/graphql/security/package-info.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2020-2021 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. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * Spring Security support for GraphQL. - */ -@NonNullApi -@NonNullFields -package org.springframework.graphql.security; - -import org.springframework.lang.NonNullApi; -import org.springframework.lang.NonNullFields; diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/BatchMappingPrincipalMethodArgumentResolverTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/BatchMappingPrincipalMethodArgumentResolverTests.java index e13f906a..f22cae41 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/BatchMappingPrincipalMethodArgumentResolverTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/BatchMappingPrincipalMethodArgumentResolverTests.java @@ -35,7 +35,7 @@ import org.springframework.graphql.RequestInput; import org.springframework.graphql.RequestOutput; import org.springframework.graphql.data.method.annotation.BatchMapping; import org.springframework.graphql.execution.ReactorContextManager; -import org.springframework.graphql.security.SecurityContextThreadLocalAccessor; +import org.springframework.graphql.execution.SecurityContextThreadLocalAccessor; import org.springframework.lang.Nullable; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication; diff --git a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingPrincipalMethodArgumentResolverTests.java b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingPrincipalMethodArgumentResolverTests.java index e0d0644d..0230da37 100644 --- a/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingPrincipalMethodArgumentResolverTests.java +++ b/spring-graphql/src/test/java/org/springframework/graphql/data/method/annotation/support/SchemaMappingPrincipalMethodArgumentResolverTests.java @@ -39,7 +39,7 @@ import org.springframework.graphql.data.method.annotation.QueryMapping; import org.springframework.graphql.data.method.annotation.SubscriptionMapping; import org.springframework.graphql.execution.ExecutionGraphQlService; import org.springframework.graphql.execution.ReactorContextManager; -import org.springframework.graphql.security.SecurityContextThreadLocalAccessor; +import org.springframework.graphql.execution.SecurityContextThreadLocalAccessor; import org.springframework.lang.Nullable; import org.springframework.security.authentication.TestingAuthenticationToken; import org.springframework.security.core.Authentication;