mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-15 01:07:30 +08:00
Add auto-config for Spring Security's SAML support
Closes gh-18260 Co-authored-by: Phillip Webb <pwebb@pivotal.io>
This commit is contained in:
parent
71f8347c81
commit
22ed56ac52
@ -682,6 +682,11 @@
|
||||
<artifactId>spring-security-oauth2-resource-server</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-saml2-service-provider</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-web</artifactId>
|
||||
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.boot.autoconfigure.security.saml2;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionMessage;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
|
||||
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
|
||||
import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyProperties.Registration;
|
||||
import org.springframework.boot.context.properties.bind.Bindable;
|
||||
import org.springframework.boot.context.properties.bind.Binder;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
/**
|
||||
* Condition that matches if any {@code spring.security.saml2.relyingparty.registration}
|
||||
* properties are defined.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class RegistrationConfiguredCondition extends SpringBootCondition {
|
||||
|
||||
private static final String PROPERTY = "spring.security.saml2.relyingparty.registration";
|
||||
|
||||
private static final Bindable<Map<String, Registration>> STRING_REGISTRATION_MAP = Bindable.mapOf(String.class,
|
||||
Registration.class);
|
||||
|
||||
@Override
|
||||
public ConditionOutcome getMatchOutcome(ConditionContext context, AnnotatedTypeMetadata metadata) {
|
||||
ConditionMessage.Builder message = ConditionMessage.forCondition("Relying Party Registration Condition");
|
||||
Map<String, Registration> registrations = getRegistrations(context.getEnvironment());
|
||||
if (registrations.isEmpty()) {
|
||||
return ConditionOutcome.noMatch(message.didNotFind("any registrations").atAll());
|
||||
}
|
||||
return ConditionOutcome.match(message.found("registration", "registrations").items(registrations.keySet()));
|
||||
}
|
||||
|
||||
private Map<String, Registration> getRegistrations(Environment environment) {
|
||||
return Binder.get(environment).bind(PROPERTY, STRING_REGISTRATION_MAP).orElse(Collections.emptyMap());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.saml2;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||
|
||||
/**
|
||||
* {@link WebSecurityConfigurerAdapter} configuration for Spring Security's relying party
|
||||
* SAML support.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnBean(RelyingPartyRegistrationRepository.class)
|
||||
class Saml2LoginConfiguration {
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class Saml2LoginConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests((requests) -> requests.anyRequest().authenticated()).saml2Login();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.saml2;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for Spring Security's SAML 2.0
|
||||
* authentication support.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @since 2.2.0
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@ConditionalOnClass(RelyingPartyRegistrationRepository.class)
|
||||
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
|
||||
@Import({ Saml2RelyingPartyRegistrationConfiguration.class, Saml2LoginConfiguration.class })
|
||||
@AutoConfigureBefore(SecurityAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(Saml2RelyingPartyProperties.class)
|
||||
public class Saml2RelyingPartyAutoConfiguration {
|
||||
|
||||
}
|
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.saml2;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* SAML2 relying party properties.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
* @since 2.2.0
|
||||
*/
|
||||
@ConfigurationProperties("spring.security.saml2.relyingparty")
|
||||
public class Saml2RelyingPartyProperties {
|
||||
|
||||
/**
|
||||
* SAML2 relying party registrations.
|
||||
*/
|
||||
private Map<String, Registration> registration = new LinkedHashMap<>();
|
||||
|
||||
public Map<String, Registration> getRegistration() {
|
||||
return this.registration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a SAML Relying Party.
|
||||
*/
|
||||
public static class Registration {
|
||||
|
||||
private final Signing signing = new Signing();
|
||||
|
||||
/**
|
||||
* Remote SAML Identity Provider.
|
||||
*/
|
||||
private Identityprovider identityprovider = new Identityprovider();
|
||||
|
||||
public Signing getSigning() {
|
||||
return this.signing;
|
||||
}
|
||||
|
||||
Identityprovider getIdentityprovider() {
|
||||
return this.identityprovider;
|
||||
}
|
||||
|
||||
public static class Signing {
|
||||
|
||||
/**
|
||||
* Credentials used for signing and decrypting the SAML authentication
|
||||
* request.
|
||||
*/
|
||||
private List<Credential> credentials = new ArrayList<>();
|
||||
|
||||
public List<Credential> getCredentials() {
|
||||
return this.credentials;
|
||||
}
|
||||
|
||||
public static class Credential {
|
||||
|
||||
/**
|
||||
* Private key used for signing or decrypting.
|
||||
*/
|
||||
private Resource privateKeyLocation;
|
||||
|
||||
/**
|
||||
* Relying Party X509Certificate shared with the identity provider.
|
||||
*/
|
||||
private Resource certificateLocation;
|
||||
|
||||
public Resource getPrivateKeyLocation() {
|
||||
return this.privateKeyLocation;
|
||||
}
|
||||
|
||||
public void setPrivateKeyLocation(Resource privateKey) {
|
||||
this.privateKeyLocation = privateKey;
|
||||
}
|
||||
|
||||
public Resource getCertificateLocation() {
|
||||
return this.certificateLocation;
|
||||
}
|
||||
|
||||
public void setCertificateLocation(Resource certificate) {
|
||||
this.certificateLocation = certificate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a remote Identity Provider.
|
||||
*/
|
||||
public static class Identityprovider {
|
||||
|
||||
/**
|
||||
* Unique identifier for the identity provider.
|
||||
*/
|
||||
private String entityId;
|
||||
|
||||
/**
|
||||
* Remote endpoint to send authentication requests to.
|
||||
*/
|
||||
private String ssoUrl;
|
||||
|
||||
private Verification verification = new Verification();
|
||||
|
||||
public String getEntityId() {
|
||||
return this.entityId;
|
||||
}
|
||||
|
||||
public void setEntityId(String entityId) {
|
||||
this.entityId = entityId;
|
||||
}
|
||||
|
||||
public String getSsoUrl() {
|
||||
return this.ssoUrl;
|
||||
}
|
||||
|
||||
public void setSsoUrl(String ssoUrl) {
|
||||
this.ssoUrl = ssoUrl;
|
||||
}
|
||||
|
||||
public Verification getVerification() {
|
||||
return this.verification;
|
||||
}
|
||||
|
||||
public static class Verification {
|
||||
|
||||
/**
|
||||
* Credentials used for verification of incoming SAML messages.
|
||||
*/
|
||||
private List<Credential> credentials = new ArrayList<>();
|
||||
|
||||
public List<Credential> getCredentials() {
|
||||
return this.credentials;
|
||||
}
|
||||
|
||||
public static class Credential {
|
||||
|
||||
/**
|
||||
* Locations of the X.509 certificate used for verification of incoming
|
||||
* SAML messages.
|
||||
*/
|
||||
private Resource certificate;
|
||||
|
||||
public Resource getCertificateLocation() {
|
||||
return this.certificate;
|
||||
}
|
||||
|
||||
public void setCertificateLocation(Resource certificate) {
|
||||
this.certificate = certificate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.saml2;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.security.cert.CertificateFactory;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyProperties.Identityprovider.Verification;
|
||||
import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyProperties.Registration;
|
||||
import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyProperties.Registration.Signing;
|
||||
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.security.converter.RsaKeyConverters;
|
||||
import org.springframework.security.saml2.credentials.Saml2X509Credential;
|
||||
import org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType;
|
||||
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link Configuration @Configuration} used to map {@link Saml2RelyingPartyProperties} to
|
||||
* relying party registrations in a {@link RelyingPartyRegistrationRepository}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Conditional(RegistrationConfiguredCondition.class)
|
||||
@ConditionalOnMissingBean(RelyingPartyRegistrationRepository.class)
|
||||
class Saml2RelyingPartyRegistrationConfiguration {
|
||||
|
||||
@Bean
|
||||
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository(Saml2RelyingPartyProperties properties) {
|
||||
List<RelyingPartyRegistration> registrations = properties.getRegistration().entrySet().stream()
|
||||
.map(this::asRegistration).collect(Collectors.toList());
|
||||
return new InMemoryRelyingPartyRegistrationRepository(registrations);
|
||||
}
|
||||
|
||||
private RelyingPartyRegistration asRegistration(Map.Entry<String, Registration> entry) {
|
||||
return asRegistration(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
private RelyingPartyRegistration asRegistration(String id, Registration properties) {
|
||||
RelyingPartyRegistration.Builder builder = RelyingPartyRegistration.withRegistrationId(id);
|
||||
builder.assertionConsumerServiceUrlTemplate(
|
||||
"{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI);
|
||||
builder.idpWebSsoUrl(properties.getIdentityprovider().getSsoUrl());
|
||||
builder.remoteIdpEntityId(properties.getIdentityprovider().getEntityId());
|
||||
builder.credentials((credentials) -> credentials.addAll(asCredentials(properties)));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private List<Saml2X509Credential> asCredentials(Registration properties) {
|
||||
List<Saml2X509Credential> credentials = new ArrayList<>();
|
||||
properties.getSigning().getCredentials().stream().map(this::asSigningCredential).forEach(credentials::add);
|
||||
properties.getIdentityprovider().getVerification().getCredentials().stream().map(this::asVerificationCredential)
|
||||
.forEach(credentials::add);
|
||||
return credentials;
|
||||
}
|
||||
|
||||
private Saml2X509Credential asSigningCredential(Signing.Credential properties) {
|
||||
RSAPrivateKey privateKey = readPrivateKey(properties.getPrivateKeyLocation());
|
||||
X509Certificate certificate = readCertificate(properties.getCertificateLocation());
|
||||
return new Saml2X509Credential(privateKey, certificate, Saml2X509CredentialType.SIGNING,
|
||||
Saml2X509CredentialType.DECRYPTION);
|
||||
}
|
||||
|
||||
private Saml2X509Credential asVerificationCredential(Verification.Credential properties) {
|
||||
X509Certificate certificate = readCertificate(properties.getCertificateLocation());
|
||||
return new Saml2X509Credential(certificate, Saml2X509CredentialType.ENCRYPTION,
|
||||
Saml2X509CredentialType.VERIFICATION);
|
||||
}
|
||||
|
||||
private RSAPrivateKey readPrivateKey(Resource location) {
|
||||
Assert.state(location != null, "No private key location specified");
|
||||
Assert.state(location.exists(), "Private key location '" + location + "' does not exist");
|
||||
try (InputStream inputStream = location.getInputStream()) {
|
||||
return RsaKeyConverters.pkcs8().convert(inputStream);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private X509Certificate readCertificate(Resource location) {
|
||||
Assert.state(location != null, "No certificate location specified");
|
||||
Assert.state(location.exists(), "Certificate location '" + location + "' does not exist");
|
||||
try (InputStream inputStream = location.getInputStream()) {
|
||||
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(inputStream);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalArgumentException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -109,6 +109,7 @@ org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoCo
|
||||
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.reactive.ReactiveSecurityAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.reactive.ReactiveUserDetailsServiceAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.sendgrid.SendGridAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.session.SessionAutoConfiguration,\
|
||||
org.springframework.boot.autoconfigure.security.oauth2.client.servlet.OAuth2ClientAutoConfiguration,\
|
||||
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.autoconfigure.security.saml2;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
|
||||
import org.springframework.boot.test.context.FilteredClassLoader;
|
||||
import org.springframework.boot.test.context.assertj.AssertableWebApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.BeanIds;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
|
||||
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
|
||||
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter;
|
||||
import org.springframework.security.web.FilterChainProxy;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
/**
|
||||
* Tests for {@link Saml2RelyingPartyAutoConfiguration}.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
public class Saml2RelyingPartyAutoConfigurationTests {
|
||||
|
||||
private static final String PREFIX = "spring.security.saml2.relyingparty.registration";
|
||||
|
||||
private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner().withConfiguration(
|
||||
AutoConfigurations.of(Saml2RelyingPartyAutoConfiguration.class, SecurityAutoConfiguration.class));
|
||||
|
||||
@Test
|
||||
void autoConfigurationShouldBeConditionalOnRelyingPartyRegistrationRepositoryClass() {
|
||||
this.contextRunner.withPropertyValues(getPropertyValues()).withClassLoader(new FilteredClassLoader(
|
||||
"org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository"))
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(RelyingPartyRegistrationRepository.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void autoConfigurationShouldBeConditionalOnServletWebApplication() {
|
||||
new ApplicationContextRunner()
|
||||
.withConfiguration(AutoConfigurations.of(Saml2RelyingPartyAutoConfiguration.class))
|
||||
.withPropertyValues(getPropertyValues())
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(RelyingPartyRegistrationRepository.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void relyingPartyRegistrationRepositoryBeanShouldNotBeCreatedWhenPropertiesAbsent() {
|
||||
this.contextRunner
|
||||
.run((context) -> assertThat(context).doesNotHaveBean(RelyingPartyRegistrationRepository.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void relyingPartyRegistrationRepositoryBeanShouldBeCreatedWhenPropertiesPresent() {
|
||||
this.contextRunner.withPropertyValues(getPropertyValues()).run((context) -> {
|
||||
RelyingPartyRegistrationRepository repository = context.getBean(RelyingPartyRegistrationRepository.class);
|
||||
RelyingPartyRegistration registration = repository.findByRegistrationId("foo");
|
||||
assertThat(registration.getIdpWebSsoUrl())
|
||||
.isEqualTo("https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php");
|
||||
assertThat(registration.getRemoteIdpEntityId())
|
||||
.isEqualTo("https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php");
|
||||
assertThat(registration.getAssertionConsumerServiceUrlTemplate())
|
||||
.isEqualTo("{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI);
|
||||
assertThat(registration.getSigningCredentials()).isNotNull();
|
||||
assertThat(registration.getVerificationCredentials()).isNotNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void relyingPartyRegistrationRepositoryShouldBeConditionalOnMissingBean() {
|
||||
this.contextRunner.withPropertyValues(getPropertyValues())
|
||||
.withUserConfiguration(RegistrationRepositoryConfiguration.class).run((context) -> {
|
||||
assertThat(context).hasSingleBean(RelyingPartyRegistrationRepository.class);
|
||||
assertThat(context).hasBean("testRegistrationRepository");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void samlLoginShouldBeConfigured() {
|
||||
this.contextRunner.withPropertyValues(getPropertyValues())
|
||||
.run((context) -> assertThat(hasFilter(context, Saml2WebSsoAuthenticationFilter.class)).isTrue());
|
||||
}
|
||||
|
||||
private String[] getPropertyValues() {
|
||||
return new String[] {
|
||||
PREFIX + ".foo.signing.credentials[0].private-key-location=classpath:saml/private-key-location",
|
||||
PREFIX + ".foo.signing.credentials[0].certificate-location=classpath:saml/certificate-location",
|
||||
PREFIX + ".foo.identityprovider.sso-url=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php",
|
||||
PREFIX + ".foo.identityprovider.entity-id=https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php",
|
||||
PREFIX + ".foo.identityprovider.verification.credentials[0].certificate-location=classpath:saml/certificate-location" };
|
||||
}
|
||||
|
||||
private boolean hasFilter(AssertableWebApplicationContext context, Class<? extends Filter> filter) {
|
||||
FilterChainProxy filterChain = (FilterChainProxy) context.getBean(BeanIds.SPRING_SECURITY_FILTER_CHAIN);
|
||||
List<SecurityFilterChain> filterChains = filterChain.getFilterChains();
|
||||
List<Filter> filters = filterChains.get(0).getFilters();
|
||||
return filters.stream().anyMatch(filter::isInstance);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class RegistrationRepositoryConfiguration {
|
||||
|
||||
@Bean
|
||||
RelyingPartyRegistrationRepository testRegistrationRepository() {
|
||||
return mock(RelyingPartyRegistrationRepository.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYD
|
||||
VQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYD
|
||||
VQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwX
|
||||
c2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0Bw
|
||||
aXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJ
|
||||
BgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAa
|
||||
BgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQD
|
||||
DBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlr
|
||||
QHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62
|
||||
E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz
|
||||
2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWW
|
||||
RDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQ
|
||||
nX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5
|
||||
cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gph
|
||||
iJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5
|
||||
ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTAD
|
||||
AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduO
|
||||
nRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+v
|
||||
ZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLu
|
||||
xbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6z
|
||||
V9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3
|
||||
lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,16 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE
|
||||
VUBxvH6Uuiy/MhZT7TV0ZNjyAF2ExA1gpn3aUxx6jYK5UnrpxRRE/KbeLucYbOhK
|
||||
cDECt77Rggz5TStrOta0BQTvfluRyoQtmQ5Nkt6Vqg7O2ZapFt7k64Sal7AftzH6
|
||||
Q2BxWN1y04bLdDrH4jipqRj/2qEFAgMBAAECgYEAj4ExY1jjdN3iEDuOwXuRB+Nn
|
||||
x7pC4TgntE2huzdKvLJdGvIouTArce8A6JM5NlTBvm69mMepvAHgcsiMH1zGr5J5
|
||||
wJz23mGOyhM1veON41/DJTVG+cxq4soUZhdYy3bpOuXGMAaJ8QLMbQQoivllNihd
|
||||
vwH0rNSK8LTYWWPZYIECQQDxct+TFX1VsQ1eo41K0T4fu2rWUaxlvjUGhK6HxTmY
|
||||
8OMJptunGRJL1CUjIb45Uz7SP8TPz5FwhXWsLfS182kRAkEA3l+Qd9C9gdpUh1uX
|
||||
oPSNIxn5hFUrSTW1EwP9QH9vhwb5Vr8Jrd5ei678WYDLjUcx648RjkjhU9jSMzIx
|
||||
EGvYtQJBAMm/i9NR7IVyyNIgZUpz5q4LI21rl1r4gUQuD8vA36zM81i4ROeuCly0
|
||||
KkfdxR4PUfnKcQCX11YnHjk9uTFj75ECQEFY/gBnxDjzqyF35hAzrYIiMPQVfznt
|
||||
YX/sDTE2AdVBVGaMj1Cb51bPHnNC6Q5kXKQnj/YrLqRQND09Q7ParX0CQQC5NxZr
|
||||
9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM
|
||||
INrtuLp4YHbgk1mi
|
||||
-----END PRIVATE KEY-----
|
@ -3239,6 +3239,35 @@ However, this functionality is available from the {spring-security-oauth2}[Sprin
|
||||
Until then, you can use the `spring-security-oauth2-autoconfigure` module to easily set up an OAuth 2.0 authorization server; see its https://docs.spring.io/spring-security-oauth2-boot[documentation] for instructions.
|
||||
|
||||
|
||||
[[boot-features-security-saml]]
|
||||
=== SAML 2.0
|
||||
|
||||
|
||||
|
||||
[[boot-features-security-saml2-relying-party]]
|
||||
==== Relying Party
|
||||
If you have `spring-security-saml2-service-provider` on your classpath, you can take advantage of some auto-configuration to make it easy to set up a SAML 2.0 Relying Party.
|
||||
This configuration makes use of the properties under `Saml2RelyingPartyProperties`.
|
||||
|
||||
A relying party registration represents a paired configuration between an Identity Provider, IDP, and a Service Provider, SP.
|
||||
You can register multiple relying parties under the `spring.security.saml2.relyingparty` prefix, as shown in the following example:
|
||||
|
||||
[source,properties,indent=0,configprops]
|
||||
----
|
||||
spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].private-key-location=path-to-private-key
|
||||
spring.security.saml2.relyingparty.registration.my-relying-party1.signing.credentials[0].certificate-location=path-to-certificate
|
||||
spring.security.saml2.relyingparty.registration.my-relying-party1.identityprovider.verification.credentials[0].certificate-location=path-to-verification-cert
|
||||
spring.security.saml2.relyingparty.registration.my-relying-party1.identityprovider.entity-id=remote-idp-entity-id1
|
||||
spring.security.saml2.relyingparty.registration.my-relying-party1.identityprovider.sso-url=https://remoteidp1.sso.url
|
||||
|
||||
spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].private-key-location=path-to-private-key
|
||||
spring.security.saml2.relyingparty.registration.my-relying-party2.signing.credentials[0].certificate-location=path-to-certificate
|
||||
spring.security.saml2.relyingparty.registration.my-relying-party2.identityprovider.verification.credentials[0].certificate-location=path-to-other-verification-cert
|
||||
spring.security.saml2.relyingparty.registration.my-relying-party2.identityprovider.entity-id=remote-idp-entity-id2
|
||||
spring.security.saml2.relyingparty.registration.my-relying-party2.identityprovider.sso-url=https://remoteidp2.sso.url
|
||||
----
|
||||
|
||||
|
||||
|
||||
[[boot-features-security-actuator]]
|
||||
=== Actuator Security
|
||||
|
@ -71,6 +71,7 @@
|
||||
<module>spring-boot-smoke-test-reactive-oauth2-client</module>
|
||||
<module>spring-boot-smoke-test-reactive-oauth2-resource-server</module>
|
||||
<module>spring-boot-smoke-test-rsocket</module>
|
||||
<module>spring-boot-smoke-test-saml2-service-provider</module>
|
||||
<module>spring-boot-smoke-test-secure</module>
|
||||
<module>spring-boot-smoke-test-secure-jersey</module>
|
||||
<module>spring-boot-smoke-test-secure-webflux</module>
|
||||
|
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-smoke-tests</artifactId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<artifactId>spring-boot-smoke-test-saml2-service-provider</artifactId>
|
||||
<name>Spring Boot SAML2 Service Provider Smoke Test</name>
|
||||
<description>Spring Boot SAML2 Service Provider Smoke Test</description>
|
||||
<properties>
|
||||
<main.basedir>${basedir}/../../..</main.basedir>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<!-- Compile -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-config</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.security</groupId>
|
||||
<artifactId>spring-security-saml2-service-provider</artifactId>
|
||||
</dependency>
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.saml2.serviceprovider;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class ExampleController {
|
||||
|
||||
@RequestMapping("/")
|
||||
public String email(Principal principal) {
|
||||
return "Hello " + principal.getName();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.saml2.serviceprovider;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class SampleSaml2RelyingPartyApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(SampleSaml2RelyingPartyApplication.class);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
spring:
|
||||
security:
|
||||
saml2:
|
||||
relyingparty:
|
||||
registration:
|
||||
simplesamlphp:
|
||||
signing:
|
||||
credentials:
|
||||
- private-key-location: "classpath:saml/privatekey.txt"
|
||||
certificate-location: "classpath:saml/certificate.txt"
|
||||
identityprovider:
|
||||
verification:
|
||||
credentials:
|
||||
- certificate-location: "classpath:saml/certificate.txt"
|
||||
entity-id: simplesaml
|
||||
sso-url: https://simplesaml-for-spring-saml/SSOService.php
|
||||
okta:
|
||||
signing:
|
||||
credentials:
|
||||
- private-key-location: "classpath:saml/privatekey.txt"
|
||||
certificate-location: "classpath:saml/certificate.txt"
|
||||
identityprovider:
|
||||
verification:
|
||||
credentials:
|
||||
- certificate-location: "classpath:saml/certificate.txt"
|
||||
entity-id: okta-id-1234
|
||||
sso-url: https://okta-for-spring/saml2/idp/SSOService.php
|
@ -0,0 +1,24 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYD
|
||||
VQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYD
|
||||
VQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwX
|
||||
c2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0Bw
|
||||
aXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJ
|
||||
BgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAa
|
||||
BgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQD
|
||||
DBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlr
|
||||
QHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62
|
||||
E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz
|
||||
2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWW
|
||||
RDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQ
|
||||
nX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5
|
||||
cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gph
|
||||
iJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5
|
||||
ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTAD
|
||||
AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduO
|
||||
nRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+v
|
||||
ZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLu
|
||||
xbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6z
|
||||
V9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3
|
||||
lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk
|
||||
-----END CERTIFICATE-----
|
@ -0,0 +1,16 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBANG7v8QjQGU3MwQE
|
||||
VUBxvH6Uuiy/MhZT7TV0ZNjyAF2ExA1gpn3aUxx6jYK5UnrpxRRE/KbeLucYbOhK
|
||||
cDECt77Rggz5TStrOta0BQTvfluRyoQtmQ5Nkt6Vqg7O2ZapFt7k64Sal7AftzH6
|
||||
Q2BxWN1y04bLdDrH4jipqRj/2qEFAgMBAAECgYEAj4ExY1jjdN3iEDuOwXuRB+Nn
|
||||
x7pC4TgntE2huzdKvLJdGvIouTArce8A6JM5NlTBvm69mMepvAHgcsiMH1zGr5J5
|
||||
wJz23mGOyhM1veON41/DJTVG+cxq4soUZhdYy3bpOuXGMAaJ8QLMbQQoivllNihd
|
||||
vwH0rNSK8LTYWWPZYIECQQDxct+TFX1VsQ1eo41K0T4fu2rWUaxlvjUGhK6HxTmY
|
||||
8OMJptunGRJL1CUjIb45Uz7SP8TPz5FwhXWsLfS182kRAkEA3l+Qd9C9gdpUh1uX
|
||||
oPSNIxn5hFUrSTW1EwP9QH9vhwb5Vr8Jrd5ei678WYDLjUcx648RjkjhU9jSMzIx
|
||||
EGvYtQJBAMm/i9NR7IVyyNIgZUpz5q4LI21rl1r4gUQuD8vA36zM81i4ROeuCly0
|
||||
KkfdxR4PUfnKcQCX11YnHjk9uTFj75ECQEFY/gBnxDjzqyF35hAzrYIiMPQVfznt
|
||||
YX/sDTE2AdVBVGaMj1Cb51bPHnNC6Q5kXKQnj/YrLqRQND09Q7ParX0CQQC5NxZr
|
||||
9jKqhHj8yQD6PlXTsY4Occ7DH6/IoDenfdEVD5qlet0zmd50HatN2Jiqm5ubN7CM
|
||||
INrtuLp4YHbgk1mi
|
||||
-----END PRIVATE KEY-----
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2012-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package smoketest.saml2.serviceprovider;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.web.client.TestRestTemplate;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
class SampleSaml2RelyingPartyApplicationTests {
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@Autowired
|
||||
private TestRestTemplate restTemplate;
|
||||
|
||||
@Test
|
||||
void everythingShouldRedirectToLogin() {
|
||||
ResponseEntity<String> entity = this.restTemplate.getForEntity("/", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.FOUND);
|
||||
assertThat(entity.getHeaders().getLocation()).isEqualTo(URI.create("http://localhost:" + this.port + "/login"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void loginShouldHaveAllIdentityProvidersToChooseFrom() {
|
||||
ResponseEntity<String> entity = this.restTemplate.getForEntity("/login", String.class);
|
||||
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(entity.getBody()).contains("/saml2/authenticate/simplesamlphp");
|
||||
assertThat(entity.getBody()).contains("/saml2/authenticate/okta");
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user