From 36f1249fc64b55066200bbdd52f18bd8df13ec15 Mon Sep 17 00:00:00 2001 From: Phillip Webb Date: Wed, 20 Apr 2022 13:48:29 -0700 Subject: [PATCH] Polish --- ...usMetricsExportAutoConfigurationTests.java | 2 + .../DefaultGraphQlSchemaCondition.java | 1 - ...RSocketGraphQlClientAutoConfiguration.java | 7 +- .../saml2/Saml2RelyingPartyProperties.java | 1 + ...RelyingPartyRegistrationConfiguration.java | 107 ++++++++++++------ .../SpringBootWebSecurityConfiguration.java | 8 +- ...ml2RelyingPartyAutoConfigurationTests.java | 1 + .../src/docs/asciidoc/web/spring-graphql.adoc | 13 +-- .../GraphQlTesterAutoConfiguration.java | 3 +- 9 files changed, 92 insertions(+), 51 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfigurationTests.java b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfigurationTests.java index cafc333277..0edd771e67 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/src/test/java/org/springframework/boot/actuate/autoconfigure/metrics/export/prometheus/PrometheusMetricsExportAutoConfigurationTests.java @@ -295,6 +295,7 @@ class PrometheusMetricsExportAutoConfigurationTests { @Bean SpanContextSupplier spanContextSupplier() { return new SpanContextSupplier() { + @Override public String getTraceId() { return null; @@ -304,6 +305,7 @@ class PrometheusMetricsExportAutoConfigurationTests { public String getSpanId() { return null; } + }; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/DefaultGraphQlSchemaCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/DefaultGraphQlSchemaCondition.java index c3680eb276..53d3f1f0da 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/DefaultGraphQlSchemaCondition.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/DefaultGraphQlSchemaCondition.java @@ -58,7 +58,6 @@ class DefaultGraphQlSchemaCondition extends SpringBootCondition implements Confi boolean match = false; List messages = new ArrayList<>(2); ConditionMessage.Builder message = ConditionMessage.forCondition(ConditionalOnGraphQlSchema.class); - Binder binder = Binder.get(context.getEnvironment()); GraphQlProperties.Schema schema = binder.bind("spring.graphql.schema", GraphQlProperties.Schema.class) .orElse(new GraphQlProperties.Schema()); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/rsocket/RSocketGraphQlClientAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/rsocket/RSocketGraphQlClientAutoConfiguration.java index ff905fc633..63585b5559 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/rsocket/RSocketGraphQlClientAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/graphql/rsocket/RSocketGraphQlClientAutoConfiguration.java @@ -33,9 +33,10 @@ import org.springframework.util.MimeTypeUtils; /** * {@link EnableAutoConfiguration Auto-configuration} for {@link RSocketGraphQlClient}. - * This auto-configuration creates {@link RSocketGraphQlClient.Builder} prototype beans, - * as the builders are stateful and should not be reused to build client instances with - * different configurations. + * This auto-configuration creates + * {@link org.springframework.graphql.client.RSocketGraphQlClient.Builder + * RSocketGraphQlClient.Builder} prototype beans, as the builders are stateful and should + * not be reused to build client instances with different configurations. * * @author Brian Clozel * @since 2.7.0 diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyProperties.java index 73d74fdf9d..56ce6510aa 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyProperties.java @@ -30,6 +30,7 @@ import org.springframework.security.saml2.provider.service.registration.Saml2Mes * * @author Madhura Bhave * @author Phillip Webb + * @author Moritz Halbritter * @since 2.2.0 */ @ConfigurationProperties("spring.security.saml2.relyingparty") diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyRegistrationConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyRegistrationConfiguration.java index 66c2a5473a..6b22cea867 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyRegistrationConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyRegistrationConfiguration.java @@ -40,6 +40,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.Resource; +import org.springframework.core.log.LogMessage; import org.springframework.security.converter.RsaKeyConverters; import org.springframework.security.saml2.core.Saml2X509Credential; import org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType; @@ -49,6 +50,7 @@ import org.springframework.security.saml2.provider.service.registration.RelyingP import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.Builder; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrations; +import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -58,6 +60,7 @@ import org.springframework.util.StringUtils; * * @author Madhura Bhave * @author Phillip Webb + * @author Moritz Halbritter */ @Configuration(proxyBeanMethods = false) @Conditional(RegistrationConfiguredCondition.class) @@ -78,12 +81,11 @@ class Saml2RelyingPartyRegistrationConfiguration { } private RelyingPartyRegistration asRegistration(String id, Registration properties) { - boolean usingMetadata = StringUtils - .hasText(getFromAssertingParty(properties, id, "metadata-uri", AssertingParty::getMetadataUri)); - Builder builder = (usingMetadata) ? RelyingPartyRegistrations - .fromMetadataLocation( - getFromAssertingParty(properties, id, "metadata-uri", AssertingParty::getMetadataUri)) - .registrationId(id) : RelyingPartyRegistration.withRegistrationId(id); + AssertingPartyProperties assertingParty = new AssertingPartyProperties(properties, id); + boolean usingMetadata = StringUtils.hasText(assertingParty.getMetadataUri()); + Builder builder = (usingMetadata) + ? RelyingPartyRegistrations.fromMetadataLocation(assertingParty.getMetadataUri()).registrationId(id) + : RelyingPartyRegistration.withRegistrationId(id); builder.assertionConsumerServiceLocation(properties.getAcs().getLocation()); builder.assertionConsumerServiceBinding(properties.getAcs().getBinding()); builder.assertingPartyDetails(mapAssertingParty(properties, id, usingMetadata)); @@ -91,8 +93,8 @@ class Saml2RelyingPartyRegistrationConfiguration { .map(this::asSigningCredential).forEach(credentials::add)); builder.decryptionX509Credentials((credentials) -> properties.getDecryption().getCredentials().stream() .map(this::asDecryptionCredential).forEach(credentials::add)); - builder.assertingPartyDetails((details) -> details.verificationX509Credentials( - (credentials) -> getFromAssertingParty(properties, id, "verification", AssertingParty::getVerification) + builder.assertingPartyDetails( + (details) -> details.verificationX509Credentials((credentials) -> assertingParty.getVerification() .getCredentials().stream().map(this::asVerificationCredential).forEach(credentials::add))); builder.entityId(properties.getEntityId()); RelyingPartyRegistration registration = builder.build(); @@ -101,35 +103,15 @@ class Saml2RelyingPartyRegistrationConfiguration { return registration; } - @SuppressWarnings("deprecation") - private T getFromAssertingParty(Registration registration, String id, String name, - Function getter) { - T newValue = getter.apply(registration.getAssertingParty()); - if (newValue != null) { - return newValue; - } - T deprecatedValue = getter.apply(registration.getIdentityprovider()); - if (deprecatedValue != null) { - logger.warn(String.format( - "Property 'spring.security.saml2.relyingparty.registration.identityprovider.%1$s.%2$s' is deprecated, please use 'spring.security.saml2.relyingparty.registration.asserting-party.%1$s.%2$s' instead", - id, name)); - return deprecatedValue; - } - return newValue; - } - private Consumer mapAssertingParty(Registration registration, String id, boolean usingMetadata) { - PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); return (details) -> { - map.from(() -> getFromAssertingParty(registration, id, "entity-id", AssertingParty::getEntityId)) - .to(details::entityId); - map.from(() -> getFromAssertingParty(registration, id, "singlesignon.binding", - (property) -> property.getSinglesignon().getBinding())).to(details::singleSignOnServiceBinding); - map.from(() -> getFromAssertingParty(registration, id, "singlesignon.url", - (property) -> property.getSinglesignon().getUrl())).to(details::singleSignOnServiceLocation); - map.from(() -> getFromAssertingParty(registration, id, "singlesignon.sign-request", - (property) -> property.getSinglesignon().getSignRequest())).when((ignored) -> !usingMetadata) + AssertingPartyProperties assertingParty = new AssertingPartyProperties(registration, id); + PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); + map.from(assertingParty::getEntityId).to(details::entityId); + map.from(assertingParty::getSingleSignonBinding).to(details::singleSignOnServiceBinding); + map.from(assertingParty::getSingleSignonUrl).to(details::singleSignOnServiceLocation); + map.from(assertingParty::getSingleSignonSignRequest).when((ignored) -> !usingMetadata) .to(details::wantAuthnRequestsSigned); }; } @@ -181,4 +163,61 @@ class Saml2RelyingPartyRegistrationConfiguration { } } + /** + * Access to {@link AssertingParty} properties taking into account deprecations. + */ + private static class AssertingPartyProperties { + + private final Registration registration; + + private final String id; + + AssertingPartyProperties(Registration registration, String id) { + this.registration = registration; + this.id = id; + } + + String getMetadataUri() { + return get("metadata-uri", AssertingParty::getMetadataUri); + } + + Verification getVerification() { + return get("verification", AssertingParty::getVerification); + } + + String getEntityId() { + return get("entity-id", AssertingParty::getEntityId); + } + + Saml2MessageBinding getSingleSignonBinding() { + return get("singlesignon.binding", (property) -> property.getSinglesignon().getBinding()); + } + + String getSingleSignonUrl() { + return get("singlesignon.url", (property) -> property.getSinglesignon().getUrl()); + } + + Boolean getSingleSignonSignRequest() { + return get("singlesignon.sign-request", (property) -> property.getSinglesignon().getSignRequest()); + } + + @SuppressWarnings("deprecation") + private T get(String name, Function getter) { + T newValue = getter.apply(this.registration.getAssertingParty()); + if (newValue != null) { + return newValue; + } + T deprecatedValue = getter.apply(this.registration.getIdentityprovider()); + if (deprecatedValue != null) { + logger.warn(LogMessage.format( + "Property 'spring.security.saml2.relyingparty.registration.identityprovider.%1$s.%2$s' is deprecated, " + + "please use 'spring.security.saml2.relyingparty.registration.asserting-party.%1$s.%2$s' instead", + this.id, name)); + return deprecatedValue; + } + return newValue; + } + + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SpringBootWebSecurityConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SpringBootWebSecurityConfiguration.java index f389cb3d35..a0cde6f342 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SpringBootWebSecurityConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/servlet/SpringBootWebSecurityConfiguration.java @@ -16,8 +16,6 @@ package org.springframework.boot.autoconfigure.security.servlet; -import java.util.EnumSet; - import javax.servlet.DispatcherType; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; @@ -65,7 +63,9 @@ class SpringBootWebSecurityConfiguration { @Bean @Order(SecurityProperties.BASIC_AUTH_ORDER) SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception { - http.authorizeRequests().anyRequest().authenticated().and().formLogin().and().httpBasic(); + http.authorizeRequests().anyRequest().authenticated(); + http.formLogin(); + http.httpBasic(); return http.build(); } @@ -83,7 +83,7 @@ class SpringBootWebSecurityConfiguration { FilterRegistrationBean errorPageSecurityFilter(ApplicationContext context) { FilterRegistrationBean registration = new FilterRegistrationBean<>( new ErrorPageSecurityFilter(context)); - registration.setDispatcherTypes(EnumSet.of(DispatcherType.ERROR)); + registration.setDispatcherTypes(DispatcherType.ERROR); return registration; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java index 03a1306d7d..8f908de316 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/saml2/Saml2RelyingPartyAutoConfigurationTests.java @@ -53,6 +53,7 @@ import static org.mockito.Mockito.mock; * Tests for {@link Saml2RelyingPartyAutoConfiguration}. * * @author Madhura Bhave + * @author Moritz Halbritter */ class Saml2RelyingPartyAutoConfigurationTests { diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/web/spring-graphql.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/web/spring-graphql.adoc index 8062175b1f..16df046731 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/web/spring-graphql.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/web/spring-graphql.adoc @@ -31,7 +31,6 @@ Because GraphQL is transport-agnostic, you'll also need to have one or more addi [[web.graphql.schema]] === GraphQL Schema - A Spring GraphQL application requires a defined schema at startup. By default, you can write ".graphqls" or ".gqls" schema files under `src/main/resources/graphql/**` and Spring Boot will pick them up automatically. You can customize the locations with configprop:spring.graphql.schema.locations[] and the file extensions with configprop:spring.graphql.schema.file-extensions[]. @@ -46,9 +45,10 @@ 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 - The GraphQL Java `RuntimeWiring.Builder` can be used to register custom scalar types, directives, type resolvers, `DataFetcher`s, and more. You can declare `RuntimeWiringConfigurer` beans in your Spring config to get access to the `RuntimeWiring.Builder`. Spring Boot detects such beans and adds them to the {spring-graphql-docs}#execution-graphqlsource[GraphQlSource builder]. @@ -63,7 +63,6 @@ include::code:GreetingController[] [[web.graphql.data-query]] === Querydsl and QueryByExample Repositories support - Spring Data offers support for both Querydsl and QueryByExample repositories. Spring GraphQL can {spring-graphql-docs}#data[configure Querydsl and QueryByExample repositories as `DataFetcher`]. @@ -80,9 +79,10 @@ are detected by Spring Boot and considered as candidates for `DataFetcher` for m [[web.graphql.transports]] === Transports + + [[web.graphql.transports.http-websocket]] ==== HTTP and WebSocket - The GraphQL HTTP endpoint is at HTTP POST "/graphql" by default. The path can be customized with configprop:spring.graphql.path[]. The GraphQL WebSocket endpoint is off by default. To enable it: @@ -112,9 +112,9 @@ Spring Boot supports many configuration properties under the `spring.graphql.cor ---- + [[web.graphql.transports.rsocket]] ==== RSocket - RSocket is also supported as a transport, on top of WebSocket or TCP. Once the <>, we can configure our GraphQL handler on a particular route using configprop:spring.graphql.rsocket.mapping[]. For example, configuring that mapping as `"graphql"` means we can use that as a route when sending requests with the `RSocketGraphQlClient`. @@ -127,9 +127,9 @@ And then send a request: include::code:RSocketGraphQlClientExample[tag=request] + [[web.graphql.exception-handling]] === Exceptions Handling - Spring GraphQL enables applications to register one or more Spring `DataFetcherExceptionResolver` components that are invoked sequentially. The Exception must be resolved to a list of `graphql.GraphQLError` objects, see {spring-graphql-docs}#execution-exceptions[Spring GraphQL exception handling documentation]. Spring Boot will automatically detect `DataFetcherExceptionResolver` beans and register them with the `GraphQlSource.Builder`. @@ -138,7 +138,6 @@ Spring Boot will automatically detect `DataFetcherExceptionResolver` beans and r [[web.graphql.graphiql]] === GraphiQL and Schema printer - Spring GraphQL offers infrastructure for helping developers when consuming or developing a GraphQL API. Spring GraphQL ships with a default https://github.com/graphql/graphiql[GraphiQL] page that is exposed at `"/graphiql"` by default. diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/graphql/tester/GraphQlTesterAutoConfiguration.java b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/graphql/tester/GraphQlTesterAutoConfiguration.java index ab70033a16..1ed2087bcb 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/graphql/tester/GraphQlTesterAutoConfiguration.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/java/org/springframework/boot/test/autoconfigure/graphql/tester/GraphQlTesterAutoConfiguration.java @@ -51,8 +51,7 @@ public class GraphQlTesterAutoConfiguration { ObjectProvider objectMapperProvider) { ExecutionGraphQlServiceTester.Builder builder = ExecutionGraphQlServiceTester.builder(graphQlService); objectMapperProvider.ifAvailable((objectMapper) -> { - final MediaType[] mediaTypes = new MediaType[] { MediaType.APPLICATION_JSON, - MediaType.APPLICATION_GRAPHQL }; + MediaType[] mediaTypes = new MediaType[] { MediaType.APPLICATION_JSON, MediaType.APPLICATION_GRAPHQL }; builder.encoder(new Jackson2JsonEncoder(objectMapper, mediaTypes)); builder.decoder(new Jackson2JsonDecoder(objectMapper, mediaTypes)); });