Skip to content

Commit f1bc239

Browse files
committed
Add Spring Security auto-configuration
This commit adds two new auto-configuration classes that provide the relevant Spring Security infrastructure for GraphQL applications: * a `ThreadLocalAccessor` that propagates the security context in Spring MVC applications * `DataFetcherExceptionResolver` implementations that resolve security exception from data fetchers, for both MVC and WebFlux Closes gh-81
1 parent 58d65d7 commit f1bc239

File tree

9 files changed

+560
-8
lines changed

9 files changed

+560
-8
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ configure(moduleProjects) {
3838
mavenBom "io.projectreactor:reactor-bom:2020.0.7"
3939
mavenBom "org.springframework:spring-framework-bom:5.3.7"
4040
mavenBom "org.springframework.data:spring-data-bom:2021.0.1"
41-
mavenBom "org.springframework.security:spring-security-bom:5.5.0"
41+
mavenBom "org.springframework.security:spring-security-bom:5.5.1"
4242
mavenBom "org.junit:junit-bom:5.7.2"
4343
}
4444
dependencies {

graphql-spring-boot-starter/build.gradle

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ dependencies {
3838
compileOnly 'io.micrometer:micrometer-core'
3939
compileOnly 'org.springframework.boot:spring-boot-actuator-autoconfigure'
4040

41+
compileOnly 'org.springframework.security:spring-security-config'
42+
compileOnly 'org.springframework.security:spring-security-web'
43+
4144
compileOnly project(':spring-graphql-test')
4245
compileOnly 'org.springframework.boot:spring-boot-test'
4346

@@ -57,6 +60,9 @@ dependencies {
5760
testImplementation 'org.apache.tomcat.embed:tomcat-embed-websocket'
5861
testImplementation 'org.springframework.boot:spring-boot-actuator-autoconfigure'
5962
testImplementation 'io.micrometer:micrometer-core'
63+
testImplementation 'org.springframework.security:spring-security-config'
64+
testImplementation 'org.springframework.security:spring-security-web'
65+
testImplementation 'org.springframework.security:spring-security-test'
6066
testImplementation 'org.springframework.boot:spring-boot-starter-test'
6167
}
6268

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
/*
2+
* Copyright 2020-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.boot.security;
18+
19+
import graphql.GraphQL;
20+
21+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
22+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
23+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
24+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
25+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
26+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
27+
import org.springframework.context.annotation.Bean;
28+
import org.springframework.context.annotation.Configuration;
29+
import org.springframework.graphql.boot.GraphQlWebFluxAutoConfiguration;
30+
import org.springframework.graphql.security.ReactiveSecurityDataFetcherExceptionResolver;
31+
import org.springframework.graphql.web.webflux.GraphQlHttpHandler;
32+
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
33+
34+
/**
35+
* {@link EnableAutoConfiguration Auto-configuration} for enabling Security support
36+
* for Spring GraphQL with WebFlux.
37+
*
38+
* @author Brian Clozel
39+
* @since 1.0.0
40+
*/
41+
@Configuration(proxyBeanMethods = false)
42+
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.REACTIVE)
43+
@ConditionalOnClass({GraphQL.class, GraphQlHttpHandler.class, EnableWebFluxSecurity.class})
44+
@ConditionalOnBean(GraphQlHttpHandler.class)
45+
@AutoConfigureAfter(GraphQlWebFluxAutoConfiguration.class)
46+
public class GraphQlWebFluxSecurityAutoConfiguration {
47+
48+
@Bean
49+
@ConditionalOnMissingBean
50+
public ReactiveSecurityDataFetcherExceptionResolver reactiveSecurityDataFetcherExceptionResolver() {
51+
return new ReactiveSecurityDataFetcherExceptionResolver();
52+
}
53+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2020-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.graphql.boot.security;
18+
19+
import graphql.GraphQL;
20+
21+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
22+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
23+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
24+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
25+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
26+
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
27+
import org.springframework.context.annotation.Bean;
28+
import org.springframework.context.annotation.Configuration;
29+
import org.springframework.graphql.boot.GraphQlWebMvcAutoConfiguration;
30+
import org.springframework.graphql.security.SecurityContextThreadLocalAccessor;
31+
import org.springframework.graphql.security.SecurityDataFetcherExceptionResolver;
32+
import org.springframework.graphql.web.webmvc.GraphQlHttpHandler;
33+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
34+
35+
/**
36+
* {@link EnableAutoConfiguration Auto-configuration} for enabling Security support
37+
* for Spring GraphQL with MVC.
38+
*
39+
* @author Brian Clozel
40+
* @since 1.0.0
41+
*/
42+
@Configuration(proxyBeanMethods = false)
43+
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
44+
@ConditionalOnClass({GraphQL.class, GraphQlHttpHandler.class, EnableWebSecurity.class})
45+
@ConditionalOnBean(GraphQlHttpHandler.class)
46+
@AutoConfigureAfter(GraphQlWebMvcAutoConfiguration.class)
47+
public class GraphQlWebMvcSecurityAutoConfiguration {
48+
49+
@Bean
50+
@ConditionalOnMissingBean
51+
public SecurityDataFetcherExceptionResolver securityDataFetcherExceptionResolver() {
52+
return new SecurityDataFetcherExceptionResolver();
53+
}
54+
55+
@Bean
56+
@ConditionalOnMissingBean
57+
public SecurityContextThreadLocalAccessor securityContextThreadLocalAccessor() {
58+
return new SecurityContextThreadLocalAccessor();
59+
}
60+
61+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright 2020-2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Auto-configuration classes to configure
19+
* {@link org.springframework.graphql.security.SecurityDataFetcherExceptionResolver},
20+
* {@link org.springframework.graphql.security.SecurityContextThreadLocalAccessor} for Security support.
21+
*/
22+
@NonNullApi
23+
@NonNullFields
24+
package org.springframework.graphql.boot.security;
25+
26+
import org.springframework.lang.NonNullApi;
27+
import org.springframework.lang.NonNullFields;

graphql-spring-boot-starter/src/main/resources/META-INF/spring.factories

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
2-
org.springframework.graphql.boot.actuate.metrics.GraphQlMetricsAutoConfiguration,\
32
org.springframework.graphql.boot.GraphQlAutoConfiguration,\
43
org.springframework.graphql.boot.GraphQlServiceAutoConfiguration,\
54
org.springframework.graphql.boot.GraphQlWebFluxAutoConfiguration,\
6-
org.springframework.graphql.boot.GraphQlWebMvcAutoConfiguration
5+
org.springframework.graphql.boot.GraphQlWebMvcAutoConfiguration,\
6+
org.springframework.graphql.boot.actuate.metrics.GraphQlMetricsAutoConfiguration,\
7+
org.springframework.graphql.boot.security.GraphQlWebFluxSecurityAutoConfiguration,\
8+
org.springframework.graphql.boot.security.GraphQlWebMvcSecurityAutoConfiguration
79

810
# Spring Test @AutoConfigureGraphQlTester
911
org.springframework.graphql.boot.test.tester.AutoConfigureGraphQlTester=\

graphql-spring-boot-starter/src/test/java/org/springframework/graphql/boot/GraphQlDataFetchers.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import graphql.schema.DataFetcher;
2323
import reactor.core.publisher.Flux;
2424

25+
import org.springframework.lang.Nullable;
26+
2527
public final class GraphQlDataFetchers {
2628

2729
private static List<Book> books = Arrays.asList(new Book("book-1", "GraphQL for beginners", 100, "John GraphQL"),
@@ -33,13 +35,20 @@ private GraphQlDataFetchers() {
3335
}
3436

3537
public static DataFetcher getBookByIdDataFetcher() {
36-
return (environment) -> books.stream().filter((book) -> book.getId().equals(environment.getArgument("id")))
37-
.findFirst().orElse(null);
38+
return (environment) -> getBookById(environment.getArgument("id"));
39+
}
40+
41+
public static DataFetcher getBooksOnSaleDataFetcher() {
42+
return (environment) -> getBooksOnSale(environment.getArgument("minPages"));
43+
}
44+
45+
@Nullable
46+
public static Book getBookById(String id) {
47+
return books.stream().filter((book) -> book.getId().equals(id)).findFirst().orElse(null);
3848
}
3949

40-
public static DataFetcher getBooksOnSale() {
41-
return (environment) -> Flux.fromIterable(books)
42-
.filter((book) -> book.getPageCount() >= (int) environment.getArgument("minPages"));
50+
public static Flux<Book> getBooksOnSale(int minPages) {
51+
return Flux.fromIterable(books).filter((book) -> book.getPageCount() >= minPages);
4352
}
4453

4554
}

0 commit comments

Comments
 (0)