Add SecurityDataFetcherExceptionResolver

This commit is contained in:
Rob Winch
2021-06-08 19:32:00 -05:00
parent 0db7ee2be3
commit b276a39902
2 changed files with 100 additions and 0 deletions

View File

@@ -0,0 +1,47 @@
package io.spring.sample.graphql;
import graphql.ErrorClassification;
import graphql.GraphQLError;
import graphql.GraphqlErrorBuilder;
import graphql.schema.DataFetchingEnvironment;
import org.springframework.graphql.execution.DataFetcherExceptionResolver;
import org.springframework.graphql.execution.ErrorType;
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;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.List;
@Component
public class SecurityDataFetcherExceptionResolver implements DataFetcherExceptionResolver {
private AuthenticationTrustResolver authenticationTrustResolver = new AuthenticationTrustResolverImpl();
@Override
public Mono<List<GraphQLError>> resolveException(Throwable exception, DataFetchingEnvironment environment) {
if (exception instanceof AuthenticationException) {
}
if (exception instanceof AccessDeniedException) {
return ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.filter(a -> !this.authenticationTrustResolver.isAnonymous(a))
.flatMap(anonymous -> forbidden(environment))
.switchIfEmpty(unauthorized(environment));
}
return Mono.empty();
}
private Mono<List<GraphQLError>> unauthorized(DataFetchingEnvironment environment) {
return Mono.fromCallable(() -> Arrays.asList(GraphqlErrorBuilder.newError(environment).errorType(ErrorType.UNAUTHORIZED).message("Unauthorized").build()));
}
private Mono<List<GraphQLError>> forbidden(DataFetchingEnvironment environment) {
return Mono.fromCallable(() -> Arrays.asList(GraphqlErrorBuilder.newError(environment).errorType(ErrorType.FORBIDDEN).message("Forbidden").build()));
}
}

View File

@@ -37,6 +37,59 @@ class SampleApplicationTests {
.build();
}
@Test
void printError() {
String query = "{" +
" employees{ " +
" name" +
" salary" +
" }" +
"}";
client.post().uri("")
.bodyValue("{ \"query\": \"" + query + "\"}")
.exchange()
.expectStatus().isOk()
.expectBody(String.class)
.consumeWith(System.out::println);
}
@Test
void anonoymousThenUnauthorized() {
String query = "{" +
" employees{ " +
" name" +
" salary" +
" }" +
"}";
client.post().uri("")
.bodyValue("{ \"query\": \"" + query + "\"}")
.exchange()
.expectStatus().isOk()
.expectBody().jsonPath("errors[0].extensions.classification").isEqualTo("UNAUTHORIZED");
}
@Test
void userRoleThenForbidden() {
String query = "{" +
" employees{ " +
" name" +
" salary" +
" }" +
"}";
client.post().uri("")
.headers(h -> h.setBasicAuth("rob", "rob"))
.bodyValue("{ \"query\": \"" + query + "\"}")
.exchange()
.expectStatus().isOk()
.expectBody().jsonPath("errors[0].extensions.classification").isEqualTo("FORBIDDEN");
}
@Test
void canQueryName() {
String query = "{" +