pull/30774/head
Phillip Webb 3 years ago
parent 71acc90da8
commit 36f1249fc6

@ -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;
}
};
}

@ -58,7 +58,6 @@ class DefaultGraphQlSchemaCondition extends SpringBootCondition implements Confi
boolean match = false;
List<ConditionMessage> 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());

@ -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

@ -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")

@ -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> T getFromAssertingParty(Registration registration, String id, String name,
Function<AssertingParty, T> 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<AssertingPartyDetails.Builder> 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> T get(String name, Function<AssertingParty, T> 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;
}
}
}

@ -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> errorPageSecurityFilter(ApplicationContext context) {
FilterRegistrationBean<ErrorPageSecurityFilter> registration = new FilterRegistrationBean<>(
new ErrorPageSecurityFilter(context));
registration.setDispatcherTypes(EnumSet.of(DispatcherType.ERROR));
registration.setDispatcherTypes(DispatcherType.ERROR);
return registration;
}

@ -53,6 +53,7 @@ import static org.mockito.Mockito.mock;
* Tests for {@link Saml2RelyingPartyAutoConfiguration}.
*
* @author Madhura Bhave
* @author Moritz Halbritter
*/
class Saml2RelyingPartyAutoConfigurationTests {

@ -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 <<messaging#messaging.rsocket.server-auto-configuration,RSocket server is configured>>, 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.

@ -51,8 +51,7 @@ public class GraphQlTesterAutoConfiguration {
ObjectProvider<ObjectMapper> 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));
});

Loading…
Cancel
Save