Add property for disabling GraphQL schema introspection
Prior to this commit, the GraphQL schema assembled by the auto-configuration would provide no option for disabling the field introspection. While this feature is essential for many tools (including GraphiQL), some prefer disabling it because this allows clients to gather information about types and schema easily. This commit introduces a new `spring.graphql.schema.introspection.enabled` configuration property. Because potential attackers can still gather this information and this feature is a core concern in the GraphQL spec, introspection is enabled by default for Spring Boot applications. Closes gh-29248
This commit is contained in:
parent
728206dba0
commit
c5817f21eb
|
@ -24,6 +24,7 @@ import java.util.stream.Collectors;
|
|||
|
||||
import graphql.GraphQL;
|
||||
import graphql.execution.instrumentation.Instrumentation;
|
||||
import graphql.schema.visibility.NoIntrospectionGraphqlFieldVisibility;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
|
@ -77,6 +78,10 @@ public class GraphQlAutoConfiguration {
|
|||
.schemaResources(schemaResources.toArray(new Resource[0]))
|
||||
.exceptionResolvers(exceptionResolversProvider.orderedStream().collect(Collectors.toList()))
|
||||
.instrumentation(instrumentationsProvider.orderedStream().collect(Collectors.toList()));
|
||||
if (!properties.getSchema().getIntrospection().isEnabled()) {
|
||||
builder.configureRuntimeWiring((wiring) -> wiring
|
||||
.fieldVisibility(NoIntrospectionGraphqlFieldVisibility.NO_INTROSPECTION_FIELD_VISIBILITY));
|
||||
}
|
||||
wiringConfigurers.orderedStream().forEach(builder::configureRuntimeWiring);
|
||||
sourceCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
|
||||
try {
|
||||
|
|
|
@ -73,6 +73,8 @@ public class GraphQlProperties {
|
|||
*/
|
||||
private String[] fileExtensions = new String[] { ".graphqls", ".gqls" };
|
||||
|
||||
private final Introspection introspection = new Introspection();
|
||||
|
||||
private final Printer printer = new Printer();
|
||||
|
||||
public String[] getLocations() {
|
||||
|
@ -96,10 +98,31 @@ public class GraphQlProperties {
|
|||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
public Introspection getIntrospection() {
|
||||
return this.introspection;
|
||||
}
|
||||
|
||||
public Printer getPrinter() {
|
||||
return this.printer;
|
||||
}
|
||||
|
||||
public static class Introspection {
|
||||
|
||||
/**
|
||||
* Whether field introspection should be enabled at the schema level.
|
||||
*/
|
||||
private boolean enabled = true;
|
||||
|
||||
public boolean isEnabled() {
|
||||
return this.enabled;
|
||||
}
|
||||
|
||||
public void setEnabled(boolean enabled) {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Printer {
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,6 +21,8 @@ import graphql.execution.instrumentation.ChainedInstrumentation;
|
|||
import graphql.execution.instrumentation.Instrumentation;
|
||||
import graphql.schema.GraphQLSchema;
|
||||
import graphql.schema.idl.RuntimeWiring;
|
||||
import graphql.schema.visibility.DefaultGraphqlFieldVisibility;
|
||||
import graphql.schema.visibility.NoIntrospectionGraphqlFieldVisibility;
|
||||
import org.assertj.core.api.InstanceOfAssertFactories;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -145,6 +147,25 @@ class GraphQlAutoConfigurationTests {
|
|||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void fieldIntrospectionShouldBeEnabledByDefault() {
|
||||
this.contextRunner.run((context) -> {
|
||||
GraphQlSource graphQlSource = context.getBean(GraphQlSource.class);
|
||||
GraphQLSchema schema = graphQlSource.schema();
|
||||
assertThat(schema.getCodeRegistry().getFieldVisibility()).isInstanceOf(DefaultGraphqlFieldVisibility.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldDisableFieldIntrospection() {
|
||||
this.contextRunner.withPropertyValues("spring.graphql.schema.introspection.enabled:false").run((context) -> {
|
||||
GraphQlSource graphQlSource = context.getBean(GraphQlSource.class);
|
||||
GraphQLSchema schema = graphQlSource.schema();
|
||||
assertThat(schema.getCodeRegistry().getFieldVisibility())
|
||||
.isInstanceOf(NoIntrospectionGraphqlFieldVisibility.class);
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CustomGraphQlBuilderConfiguration {
|
||||
|
||||
|
|
|
@ -40,6 +40,8 @@ In the following sections, we'll consider this sample GraphQL schema, defining t
|
|||
include::{docs-resources}/graphql/schema.graphqls[]
|
||||
----
|
||||
|
||||
NOTE: By default, https://spec.graphql.org/draft/#sec-Introspection[field introspection] will be allowed on the schema as it is required for tools such as GraphiQL.
|
||||
If you wish to not expose information about the schema, you can disable introspection by setting configprop:spring.graphql.schema.introspection.enabled[] to `false`.
|
||||
|
||||
[[web.graphql.runtimewiring]]
|
||||
=== GraphQL RuntimeWiring
|
||||
|
|
Loading…
Reference in New Issue