10 Commits

Author SHA1 Message Date
Marcus Da Coregio 7d9bf3ecd4 Add Gradle Enterprise plugin
Issue gh-94
2022-09-16 08:55:56 -03:00
Marcus Da Coregio 46b4e25e7a Accept gradle Terms of Service
Issue gh-94
2022-09-16 08:55:56 -03:00
Marcus Da Coregio fb1a0e96c0 Add new task that runs all subproject's tests 2022-09-16 08:55:55 -03:00
Marcus Da Coregio bb7b822ada Add init script to be used in Spring Security CI
Issue https://github.com/spring-projects/spring-security/issues/10344
2022-05-11 16:05:42 -03:00
Eleftheria Stein 23b80ce2d8 Prevent gradle cache on tests
Closes gh-54
2021-12-20 13:53:33 -06:00
Eleftheria Stein 9d13cfee7b Temporarily disable tests on SAML2 samples
Issue gh-55
2021-12-20 13:53:22 -06:00
Marcus Da Coregio 5db444a305 Remove remaining usage of WebSecurityConfigurerAdapter 2021-12-15 09:31:22 -03:00
Marcus Da Coregio 90e38e4670 Increase timeout for WebTestClient
Sometimes the tests fail with the message Timeout on blocking read for 5000000000 NANOSECONDS
2021-12-10 14:29:36 -03:00
Marcus Da Coregio f3d83b373c Fix broken links
Issue gh-53
2021-12-10 14:13:06 -03:00
Marcus Da Coregio e78a1f73ef Use Spring Security 5.6.0 2021-12-10 14:12:11 -03:00
135 changed files with 577 additions and 8537 deletions
+1 -1
View File
@@ -4,5 +4,5 @@
<component name="FrameworkDetectionExcludesConfiguration">
<file type="web" url="file://$PROJECT_DIR$" />
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="temurin-11" project-jdk-type="JavaSDK" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK" />
</project>
+2 -2
View File
@@ -1,5 +1,5 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
org.gradle.jvmargs=-Xmx3g -XX:MaxPermSize=2048m -XX:+HeapDumpOnOutOfMemoryError
org.gradle.parallel=true
org.gradle.caching=true
+1 -2
View File
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
+1 -2
View File
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
+2 -2
View File
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
+1 -2
View File
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
+1 -2
View File
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -26,4 +25,4 @@ dependencies {
tasks.withType(Test).configureEach {
useJUnitPlatform()
outputs.upToDateWhen { false }
}
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -23,4 +22,4 @@ dependencies {
tasks.withType(Test).configureEach {
useJUnitPlatform()
outputs.upToDateWhen { false }
}
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -26,4 +25,4 @@ dependencies {
tasks.withType(Test).configureEach {
useJUnitPlatform()
outputs.upToDateWhen { false }
}
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -1 +1 @@
spring-security.version=5.8.0-SNAPSHOT
spring-security.version=5.6.0
@@ -4,18 +4,17 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
dependencies {
aspect platform("org.springframework:spring-framework-bom:5.3.13")
aspect platform("org.springframework.security:spring-security-bom:5.8.0-SNAPSHOT")
aspect platform("org.springframework:spring-framework-bom:5.3.0")
aspect platform("org.springframework.security:spring-security-bom:5.4.0-SNAPSHOT")
aspect "org.springframework.security:spring-security-aspects"
implementation platform("org.springframework:spring-framework-bom:5.3.13")
implementation platform("org.springframework.security:spring-security-bom:5.8.0-SNAPSHOT")
implementation platform("org.springframework:spring-framework-bom:5.3.0")
implementation platform("org.springframework.security:spring-security-bom:5.6.0")
implementation platform("org.junit:junit-bom:5.7.0")
implementation "org.springframework.security:spring-security-config"
@@ -8,14 +8,13 @@ plugins {
apply from: "gradle/gretty.gradle"
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
dependencies {
implementation platform("org.springframework:spring-framework-bom:5.3.13")
implementation platform("org.springframework.security:spring-security-bom:5.8.0-SNAPSHOT")
implementation platform("org.springframework:spring-framework-bom:5.3.0")
implementation platform("org.springframework.security:spring-security-bom:5.6.0")
implementation platform("org.junit:junit-bom:5.7.0")
implementation "org.springframework.security:spring-security-config"
@@ -8,14 +8,13 @@ plugins {
apply from: "gradle/gretty.gradle"
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
dependencies {
implementation platform("org.springframework:spring-framework-bom:5.3.13")
implementation platform("org.springframework.security:spring-security-bom:5.8.0-SNAPSHOT")
implementation platform("org.springframework:spring-framework-bom:5.3.0")
implementation platform("org.springframework.security:spring-security-bom:5.6.0")
implementation platform("org.junit:junit-bom:5.7.0")
implementation "org.springframework.security:spring-security-config"
@@ -36,4 +35,4 @@ dependencies {
tasks.withType(Test).configureEach {
useJUnitPlatform()
outputs.upToDateWhen { false }
}
}
@@ -8,14 +8,13 @@ plugins {
apply from: "gradle/gretty.gradle"
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
dependencies {
implementation platform("org.springframework:spring-framework-bom:5.3.13")
implementation platform("org.springframework.security:spring-security-bom:5.8.0-SNAPSHOT")
implementation platform("org.springframework:spring-framework-bom:5.3.0")
implementation platform("org.springframework.security:spring-security-bom:5.6.0")
implementation platform("org.junit:junit-bom:5.7.0")
implementation "org.springframework.security:spring-security-config"
@@ -8,14 +8,13 @@ plugins {
apply from: "gradle/gretty.gradle"
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
dependencies {
implementation platform("org.springframework:spring-framework-bom:5.3.13")
implementation platform("org.springframework.security:spring-security-bom:5.8.0-SNAPSHOT")
implementation platform("org.springframework:spring-framework-bom:5.3.0")
implementation platform("org.springframework.security:spring-security-bom:5.6.0")
implementation platform("org.junit:junit-bom:5.7.0")
implementation "org.springframework.security:spring-security-config"
@@ -8,14 +8,13 @@ plugins {
apply from: "gradle/gretty.gradle"
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
dependencies {
implementation platform("org.springframework:spring-framework-bom:5.3.13")
implementation platform("org.springframework.security:spring-security-bom:5.8.0-SNAPSHOT")
implementation platform("org.springframework:spring-framework-bom:5.3.0")
implementation platform("org.springframework.security:spring-security-bom:5.6.0")
implementation platform("org.junit:junit-bom:5.7.0")
implementation "org.hsqldb:hsqldb:2.5.1"
@@ -8,14 +8,13 @@ plugins {
apply from: "gradle/gretty.gradle"
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
dependencies {
implementation platform("org.springframework:spring-framework-bom:5.3.13")
implementation platform("org.springframework.security:spring-security-bom:5.8.0-SNAPSHOT")
implementation platform("org.springframework:spring-framework-bom:5.3.0")
implementation platform("org.springframework.security:spring-security-bom:5.6.0")
implementation platform("org.junit:junit-bom:5.7.0")
implementation "org.springframework.security:spring-security-config"
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2016 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.
@@ -17,29 +17,39 @@ package example;
import org.springframework.context.annotation.Bean;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.ldap.EmbeddedLdapServerContextSourceFactoryBean;
import org.springframework.security.config.ldap.LdapBindAuthenticationManagerFactory;
import org.springframework.security.ldap.userdetails.PersonContextMapper;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.authentication.BindAuthenticator;
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
import org.springframework.security.ldap.authentication.LdapAuthenticator;
import org.springframework.security.ldap.server.UnboundIdContainer;
@EnableWebSecurity
public class SecurityConfiguration {
@Bean
public EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean = EmbeddedLdapServerContextSourceFactoryBean
.fromEmbeddedLdapServer();
contextSourceFactoryBean.setPort(0);
return contextSourceFactoryBean;
UnboundIdContainer ldapContainer() {
UnboundIdContainer result = new UnboundIdContainer("dc=springframework,dc=org", "classpath:users.ldif");
result.setPort(0);
return result;
}
@Bean
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
factory.setUserDnPatterns("uid={0},ou=people");
factory.setUserDetailsContextMapper(new PersonContextMapper());
return factory.createAuthenticationManager();
DefaultSpringSecurityContextSource contextSource(UnboundIdContainer container) {
return new DefaultSpringSecurityContextSource(
"ldap://localhost:" + container.getPort() + "/dc=springframework,dc=org");
}
@Bean
BindAuthenticator authenticator(BaseLdapPathContextSource contextSource) {
BindAuthenticator authenticator = new BindAuthenticator(contextSource);
authenticator.setUserDnPatterns(new String[] { "uid={0},ou=people" });
return authenticator;
}
@Bean
LdapAuthenticationProvider authenticationProvider(LdapAuthenticator authenticator) {
return new LdapAuthenticationProvider(authenticator);
}
}
@@ -8,14 +8,13 @@ plugins {
//apply from: "gradle/gretty.gradle"
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
dependencies {
implementation platform("org.springframework:spring-framework-bom:5.3.13")
implementation platform("org.springframework.security:spring-security-bom:5.8.0-SNAPSHOT")
implementation platform("org.springframework:spring-framework-bom:5.3.0")
implementation platform("org.springframework.security:spring-security-bom:5.6.0")
implementation platform("org.junit:junit-bom:5.7.0")
implementation "org.springframework.security:spring-security-config"
+4 -5
View File
@@ -4,15 +4,14 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
dependencies {
implementation platform("org.springframework:spring-framework-bom:5.3.13")
implementation platform("org.springframework.data:spring-data-releasetrain:Neumann-SR5")
implementation platform("org.springframework.security:spring-security-bom:5.8.0-SNAPSHOT")
implementation platform("org.springframework:spring-framework-bom:5.3.11")
implementation platform("org.springframework.data:spring-data-releasetrain:Neumann-SR9")
implementation platform("org.springframework.security:spring-security-bom:5.6.0")
implementation platform("org.junit:junit-bom:5.7.0")
implementation "org.springframework.security:spring-security-config"
@@ -8,14 +8,13 @@ plugins {
apply from: "gradle/gretty.gradle"
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
dependencies {
implementation platform("org.springframework:spring-framework-bom:5.3.13")
implementation platform("org.springframework.security:spring-security-bom:5.8.0-SNAPSHOT")
implementation platform("org.springframework:spring-framework-bom:5.3.0")
implementation platform("org.springframework.security:spring-security-bom:5.6.0")
implementation platform("org.junit:junit-bom:5.7.0")
implementation "org.springframework.security:spring-security-config"
@@ -8,14 +8,13 @@ plugins {
apply from: "gradle/gretty.gradle"
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
dependencies {
implementation platform("org.springframework:spring-framework-bom:5.3.13")
implementation platform("org.springframework.security:spring-security-bom:5.8.0-SNAPSHOT")
implementation platform("org.springframework:spring-framework-bom:5.3.0")
implementation platform("org.springframework.security:spring-security-bom:5.6.0")
implementation platform("org.junit:junit-bom:5.7.0")
implementation "org.springframework.security:spring-security-config"
@@ -8,14 +8,13 @@ plugins {
apply from: "gradle/gretty.gradle"
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
dependencies {
implementation platform("org.springframework:spring-framework-bom:5.3.13")
implementation platform("org.springframework.security:spring-security-bom:5.8.0-SNAPSHOT")
implementation platform("org.springframework:spring-framework-bom:5.3.0")
implementation platform("org.springframework.security:spring-security-bom:5.6.0")
implementation platform("org.junit:junit-bom:5.7.0")
implementation "org.springframework.security:spring-security-config"
@@ -8,14 +8,13 @@ plugins {
apply from: "gradle/gretty.gradle"
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
dependencies {
implementation platform("org.springframework:spring-framework-bom:5.3.13")
implementation platform("org.springframework.security:spring-security-bom:5.8.0-SNAPSHOT")
implementation platform("org.springframework:spring-framework-bom:5.3.0")
implementation platform("org.springframework.security:spring-security-bom:5.6.0")
implementation platform("org.junit:junit-bom:5.7.0")
implementation "org.springframework.security:spring-security-config"
@@ -12,18 +12,18 @@ The https://docs.spring.io/spring-security/reference/servlet/saml2/logout.html[S
=== SAML 2.0 Login
`saml2Login()` provides a very simple implementation of a Service Provider that can receive a SAML 2.0 Response via the HTTP-POST and HTTP-REDIRECT bindings against the https://developer.okta.com/docs/guides/build-sso-integration/saml2/main/[Okta SAML 2.0 IDP] reference implementation.
`saml2Login()` provides a very simple implementation of a Service Provider that can receive a SAML 2.0 Response via the HTTP-POST and HTTP-REDIRECT bindings against the SimpleSAMLphp SAML 2.0 reference implementation.
The following features are implemented in the MVP:
1. Receive and validate a SAML 2.0 Response containing an assertion, and create a corresponding authentication in Spring Security
2. Send a SAML 2.0 AuthNRequest to an Identity Provider
3. Provide a framework for components used in SAML 2.0 authentication that can be swapped by configuration
4. Work against the Okta SAML 2.0 IDP reference implementation
4. Work against the SimpleSAMLphp reference implementation
=== SAML 2.0 Single Logout
`saml2Logout()` supports RP- and AP-initiated SAML 2.0 Single Logout via the HTTP-POST and HTTP-REDIRECT bindings against the https://developer.okta.com/docs/guides/build-sso-integration/saml2/main/[Okta SAML 2.0 IDP] reference implementation.
`saml2Logout()` supports RP- and AP-initiated SAML 2.0 Single Logout via the HTTP-POST and HTTP-REDIRECT bindings against the SimpleSAMLphp SAML 2.0 reference implementation.
On this sample, the SAML 2.0 Logout is using the HTTP-POST binding.
@@ -31,21 +31,20 @@ You can refer to the https://docs.spring.io/spring-security/reference/servlet/sa
== Run the Sample
=== Start up the Sample Boot Application
```
./gradlew :spring-security-samples-boot-saml2login:bootRun
```
=== Start up the application
You should run the application war in a servlet container like Tomcat
=== Open a Browser
http://localhost:8080/
You will be redirect to the Okta SAML 2.0 IDP
You will be redirect to the SimpleSAMLphp IDP
=== Type in your credentials
```
User: testuser@spring.security.saml
Password: 12345678
User: user
Password: password
```
@@ -24,8 +24,7 @@ plugins {
apply from: "gradle/gretty.gradle"
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://build.shibboleth.net/nexus/content/repositories/releases/" }
}
@@ -37,7 +36,7 @@ dependencies {
implementation "org.opensaml:opensaml-saml-impl:4.1.1"
}
implementation platform("org.springframework:spring-framework-bom:5.3.11")
implementation platform("org.springframework.security:spring-security-bom:5.8.0-SNAPSHOT")
implementation platform("org.springframework.security:spring-security-bom:5.6.0")
implementation platform("org.junit:junit-bom:5.7.0")
implementation "org.springframework.security:spring-security-config"
@@ -16,17 +16,15 @@
package example;
import java.util.ArrayList;
import java.util.List;
import java.io.IOException;
import com.gargoylesoftware.htmlunit.ElementNotFoundException;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlInput;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.html.HtmlPasswordInput;
import com.gargoylesoftware.htmlunit.html.HtmlSubmitInput;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
@@ -42,8 +40,6 @@ import org.springframework.test.web.servlet.htmlunit.MockMvcWebClientBuilder;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = ApplicationConfiguration.class)
@WebAppConfiguration
@@ -70,58 +66,35 @@ public class Saml2JavaConfigurationITests {
@Test
void authenticationAttemptWhenValidThenShowsUserEmailAddress() throws Exception {
performLogin();
HtmlPage home = (HtmlPage) this.webClient.getCurrentWindow().getEnclosedPage();
assertThat(home.asText()).contains("You're email address is testuser@spring.security.saml");
HtmlPage relyingParty = performLogin();
Assertions.assertThat(relyingParty.asText()).contains("You're email address is testuser@spring.security.saml");
}
@Test
void logoutWhenRelyingPartyInitiatedLogoutThenLoginPageWithLogoutParam() throws Exception {
performLogin();
HtmlPage home = (HtmlPage) this.webClient.getCurrentWindow().getEnclosedPage();
HtmlElement rpLogoutButton = home.getHtmlElementById("rp_logout_button");
HtmlPage relyingParty = performLogin();
HtmlElement rpLogoutButton = relyingParty.getHtmlElementById("rp_logout_button");
HtmlPage loginPage = rpLogoutButton.click();
this.webClient.waitForBackgroundJavaScript(10000);
List<String> urls = new ArrayList<>();
urls.add(loginPage.getUrl().getFile());
urls.add(((HtmlPage) this.webClient.getCurrentWindow().getEnclosedPage()).getUrl().getFile());
assertThat(urls).withFailMessage(() -> {
// @formatter:off
String builder = loginPage.asXml()
+ "\n\n\n"
+ "Enclosing Page"
+ "\n\n\n"
+ ((HtmlPage) this.webClient.getCurrentWindow().getEnclosedPage()).asXml();
// @formatter:on
return builder;
}).contains("/login?logout");
Assertions.assertThat(loginPage.getUrl().getFile()).isEqualTo("/login?logout");
}
private void performLogin() throws Exception {
@Test
void logoutWhenAssertingPartyInitiatedLogoutThenLoginPageWithLogoutParam() throws Exception {
HtmlPage relyingParty = performLogin();
HtmlElement apLogoutButton = relyingParty.getHtmlElementById("ap_logout_button");
HtmlPage loginPage = apLogoutButton.click();
Assertions.assertThat(loginPage.getUrl().getFile()).isEqualTo("/login?logout");
}
private HtmlPage performLogin() throws IOException {
HtmlPage login = this.webClient.getPage("/");
this.webClient.waitForBackgroundJavaScript(10000);
HtmlForm form = findForm(login);
HtmlForm form = login.getFormByName("f");
HtmlInput username = form.getInputByName("username");
HtmlPasswordInput password = form.getInputByName("password");
HtmlSubmitInput submit = login.getHtmlElementById("okta-signin-submit");
username.type("testuser@spring.security.saml");
password.type("12345678");
submit.click();
this.webClient.waitForBackgroundJavaScript(10000);
}
private HtmlForm findForm(HtmlPage login) {
for (HtmlForm form : login.getForms()) {
try {
if (form.getId().equals("form19")) {
return form;
}
}
catch (ElementNotFoundException ex) {
// Continue
}
}
throw new IllegalStateException("Could not resolve login form");
HtmlInput password = form.getInputByName("password");
HtmlSubmitInput submit = login.getHtmlElementById("submit_button");
username.setValueAttribute("user");
password.setValueAttribute("password");
return submit.click();
}
}
@@ -31,7 +31,7 @@ public class IndexController {
@GetMapping("/")
public String index(Model model, @AuthenticationPrincipal Saml2AuthenticatedPrincipal principal) {
String emailAddress = principal.getFirstAttribute("email");
String emailAddress = principal.getFirstAttribute("emailAddress");
model.addAttribute("emailAddress", emailAddress);
model.addAttribute("userAttributes", principal.getAttributes());
return "index";
@@ -32,7 +32,6 @@ import org.springframework.security.saml2.provider.service.registration.InMemory
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.registration.RelyingPartyRegistrations;
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
import org.springframework.security.web.SecurityFilterChain;
@EnableWebSecurity
@@ -58,16 +57,13 @@ public class SecurityConfiguration {
@Bean
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations
.fromMetadataLocation("https://dev-05937739.okta.com/app/exk46xofd8NZvFCpS5d7/sso/saml/metadata")
.fromMetadataLocation("https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/metadata.php")
.registrationId("one")
.decryptionX509Credentials(
(c) -> c.add(Saml2X509Credential.decryption(this.privateKey, relyingPartyCertificate())))
.signingX509Credentials(
(c) -> c.add(Saml2X509Credential.signing(this.privateKey, relyingPartyCertificate())))
.singleLogoutServiceLocation(
"https://dev-05937739.okta.com/app/dev-05937739_springgsecuritysaml2idp_1/exk46xofd8NZvFCpS5d7/slo/saml")
.singleLogoutServiceResponseLocation("http://localhost:8080/logout/saml2/slo")
.singleLogoutServiceBinding(Saml2MessageBinding.POST).build();
.build();
return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration);
}
@@ -36,6 +36,11 @@
</button>
</form>
</li>
<li class="nav-item">
<a id="ap_logout_button" class="nav-link" href="https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/SingleLogoutService.php?ReturnTo=http://localhost:8080/login?logout">
AP-initiated Logout
</a>
</li>
</ul>
</div>
<main role="main" class="container">
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
+1 -2
View File
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -5,8 +5,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
+1 -2
View File
@@ -5,8 +5,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2020 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.
@@ -18,10 +18,13 @@ package example;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.ldap.core.ContextSource;
import org.springframework.ldap.core.support.BaseLdapPathContextSource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.ldap.EmbeddedLdapServerContextSourceFactoryBean;
import org.springframework.security.config.ldap.LdapBindAuthenticationManagerFactory;
import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
import org.springframework.security.ldap.authentication.BindAuthenticator;
import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
import org.springframework.security.ldap.authentication.LdapAuthenticator;
import org.springframework.security.ldap.server.UnboundIdContainer;
import org.springframework.security.ldap.userdetails.PersonContextMapper;
/**
@@ -33,19 +36,30 @@ import org.springframework.security.ldap.userdetails.PersonContextMapper;
public class SecurityConfig {
@Bean
public EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean() {
EmbeddedLdapServerContextSourceFactoryBean contextSourceFactoryBean = EmbeddedLdapServerContextSourceFactoryBean
.fromEmbeddedLdapServer();
contextSourceFactoryBean.setPort(0);
return contextSourceFactoryBean;
UnboundIdContainer ldapContainer() {
UnboundIdContainer container = new UnboundIdContainer("dc=springframework,dc=org", "classpath:users.ldif");
container.setPort(0);
return container;
}
@Bean
AuthenticationManager authenticationManager(BaseLdapPathContextSource contextSource) {
LdapBindAuthenticationManagerFactory factory = new LdapBindAuthenticationManagerFactory(contextSource);
factory.setUserDnPatterns("uid={0},ou=people");
factory.setUserDetailsContextMapper(new PersonContextMapper());
return factory.createAuthenticationManager();
ContextSource contextSource(UnboundIdContainer container) {
int port = container.getPort();
return new DefaultSpringSecurityContextSource("ldap://localhost:" + port + "/dc=springframework,dc=org");
}
@Bean
BindAuthenticator authenticator(BaseLdapPathContextSource contextSource) {
BindAuthenticator authenticator = new BindAuthenticator(contextSource);
authenticator.setUserDnPatterns(new String[] { "uid={0},ou=people" });
return authenticator;
}
@Bean
LdapAuthenticationProvider authenticationProvider(LdapAuthenticator authenticator) {
LdapAuthenticationProvider provider = new LdapAuthenticationProvider(authenticator);
provider.setUserDetailsContextMapper(new PersonContextMapper());
return provider;
}
}
@@ -6,14 +6,13 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.security:spring-security-oauth2-authorization-server:0.2.3'
implementation 'org.springframework.security:spring-security-oauth2-authorization-server:0.2.0'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -23,4 +22,4 @@ dependencies {
tasks.withType(Test).configureEach {
useJUnitPlatform()
outputs.upToDateWhen { false }
}
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -22,8 +22,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -39,4 +38,4 @@ dependencies {
tasks.withType(Test).configureEach {
useJUnitPlatform()
outputs.upToDateWhen { false }
}
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -22,8 +22,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -22,8 +22,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -40,4 +39,4 @@ dependencies {
tasks.withType(Test).configureEach {
useJUnitPlatform()
outputs.upToDateWhen { false }
}
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -22,8 +22,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -39,4 +38,4 @@ dependencies {
tasks.withType(Test).configureEach {
useJUnitPlatform()
outputs.upToDateWhen { false }
}
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -22,8 +22,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
}
@@ -44,4 +43,4 @@ dependencies {
tasks.withType(Test).configureEach {
useJUnitPlatform()
outputs.upToDateWhen { false }
}
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
@@ -12,18 +12,18 @@ The https://docs.spring.io/spring-security/reference/servlet/saml2/logout.html[S
=== SAML 2.0 Login
`saml2Login()` provides a very simple implementation of a Service Provider that can receive a SAML 2.0 Response via the HTTP-POST and HTTP-REDIRECT bindings against the https://developer.okta.com/docs/guides/build-sso-integration/saml2/main/[Okta SAML 2.0 IDP] reference implementation.
`saml2Login()` provides a very simple implementation of a Service Provider that can receive a SAML 2.0 Response via the HTTP-POST and HTTP-REDIRECT bindings against the SimpleSAMLphp SAML 2.0 reference implementation.
The following features are implemented in the MVP:
1. Receive and validate a SAML 2.0 Response containing an assertion, and create a corresponding authentication in Spring Security
2. Send a SAML 2.0 AuthNRequest to an Identity Provider
3. Provide a framework for components used in SAML 2.0 authentication that can be swapped by configuration
4. Work against the Okta SAML 2.0 IDP reference implementation
4. Work against the SimpleSAMLphp reference implementation
=== SAML 2.0 Single Logout
`saml2Logout()` supports RP- and AP-initiated SAML 2.0 Single Logout via the HTTP-POST and HTTP-REDIRECT bindings against the https://developer.okta.com/docs/guides/build-sso-integration/saml2/main/[Okta SAML 2.0 IDP] reference implementation.
`saml2Logout()` supports RP- and AP-initiated SAML 2.0 Single Logout via the HTTP-POST and HTTP-REDIRECT bindings against the SimpleSAMLphp SAML 2.0 reference implementation.
On this sample, the SAML 2.0 Logout is using the HTTP-POST binding.
@@ -33,20 +33,19 @@ You can refer to the https://docs.spring.io/spring-security/reference/servlet/sa
=== Start up the Sample Boot Application
```
./gradlew :servlet:spring-boot:java:saml2:login-single-tenant:bootRun
./gradlew :spring-security-samples-boot-saml2login:bootRun
```
=== Open a Browser
http://localhost:8080/
You will be redirect to the Okta SAML 2.0 IDP
You will be redirect to the SimpleSAMLphp IDP
=== Type in your credentials
```
User: testuser@spring.security.saml
Password: 12345678
User: user
Password: password
```
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://build.shibboleth.net/nexus/content/repositories/releases/" }
}
@@ -24,7 +23,7 @@ dependencies {
implementation 'org.springframework.security:spring-security-saml2-service-provider'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
testImplementation 'net.sourceforge.htmlunit:htmlunit:2.44.0'
testImplementation 'net.sourceforge.htmlunit:htmlunit'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
}
@@ -32,4 +31,4 @@ dependencies {
tasks.withType(Test).configureEach {
useJUnitPlatform()
outputs.upToDateWhen { false }
}
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
File diff suppressed because one or more lines are too long
@@ -27,7 +27,7 @@ public class IndexController {
@GetMapping("/")
public String index(Model model, @AuthenticationPrincipal Saml2AuthenticatedPrincipal principal) {
String emailAddress = principal.getFirstAttribute("email");
String emailAddress = principal.getFirstAttribute("emailAddress");
model.addAttribute("emailAddress", emailAddress);
model.addAttribute("userAttributes", principal.getAttributes());
return "index";
@@ -16,26 +16,13 @@
package example;
import java.io.InputStream;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.provider.service.metadata.OpenSamlMetadataResolver;
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.registration.RelyingPartyRegistrations;
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter;
@@ -52,7 +39,7 @@ public class SecurityConfiguration {
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.saml2Login(Customizer.withDefaults())
.saml2Login((saml2) -> saml2.loginProcessingUrl("/login/saml2/sso"))
.saml2Logout(Customizer.withDefaults());
// @formatter:on
@@ -62,7 +49,7 @@ public class SecurityConfiguration {
@Bean
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver(
RelyingPartyRegistrationRepository registrations) {
return new DefaultRelyingPartyRegistrationResolver((id) -> registrations.findByRegistrationId("two"));
return new DefaultRelyingPartyRegistrationResolver((id) -> registrations.findByRegistrationId("metadata"));
}
@Bean
@@ -78,29 +65,4 @@ public class SecurityConfiguration {
return filter;
}
@Bean
RelyingPartyRegistrationRepository repository(
@Value("classpath:credentials/rp-private.key") RSAPrivateKey privateKey) {
RelyingPartyRegistration two = RelyingPartyRegistrations
.fromMetadataLocation("https://dev-05937739.okta.com/app/exk4842vmapcMkohr5d7/sso/saml/metadata")
.registrationId("two")
.signingX509Credentials(
(c) -> c.add(Saml2X509Credential.signing(privateKey, relyingPartyCertificate())))
.singleLogoutServiceLocation(
"https://dev-05937739.okta.com/app/dev-05937739_springsecuritysaml2idptwo_1/exk4842vmapcMkohr5d7/slo/saml")
.singleLogoutServiceResponseLocation("http://localhost:8080/logout/saml2/slo")
.singleLogoutServiceBinding(Saml2MessageBinding.POST).build();
return new InMemoryRelyingPartyRegistrationRepository(two);
}
X509Certificate relyingPartyCertificate() {
Resource resource = new ClassPathResource("credentials/rp-certificate.crt");
try (InputStream is = resource.getInputStream()) {
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(is);
}
catch (Exception ex) {
throw new UnsupportedOperationException(ex);
}
}
}
@@ -1,2 +1,17 @@
spring:
security:
saml2:
relyingparty:
registration:
metadata:
entity-id: "{baseUrl}/saml2/metadata"
acs.location: "{baseUrl}/login/saml2/sso"
signing.credentials:
- private-key-location: classpath:credentials/rp-private.key
certificate-location: classpath:credentials/rp-certificate.crt
identityprovider:
metadata-uri: https://simplesamlphp.apps.pcfone.io/saml2/idp/metadata.php
logging.level:
org.springframework.security: TRACE
@@ -36,6 +36,11 @@
</button>
</form>
</li>
<li class="nav-item">
<a id="ap_logout_button" class="nav-link" href="https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/SingleLogoutService.php?ReturnTo=http://localhost:8080/login?logout">
AP-initiated Logout
</a>
</li>
</ul>
</div>
<main role="main" class="container">
@@ -12,18 +12,18 @@ The https://docs.spring.io/spring-security/reference/servlet/saml2/logout.html[S
=== SAML 2.0 Login
`saml2Login()` provides a very simple implementation of a Service Provider that can receive a SAML 2.0 Response via the HTTP-POST and HTTP-REDIRECT bindings against the https://developer.okta.com/docs/guides/build-sso-integration/saml2/main/[Okta SAML 2.0 IDP] reference implementation.
`saml2Login()` provides a very simple implementation of a Service Provider that can receive a SAML 2.0 Response via the HTTP-POST and HTTP-REDIRECT bindings against the SimpleSAMLphp SAML 2.0 reference implementation.
The following features are implemented in the MVP:
1. Receive and validate a SAML 2.0 Response containing an assertion, and create a corresponding authentication in Spring Security
2. Send a SAML 2.0 AuthNRequest to an Identity Provider
3. Provide a framework for components used in SAML 2.0 authentication that can be swapped by configuration
4. Work against the Okta SAML 2.0 IDP reference implementation
4. Work against the SimpleSAMLphp reference implementation
=== SAML 2.0 Single Logout
`saml2Logout()` supports RP- and AP-initiated SAML 2.0 Single Logout via the HTTP-POST and HTTP-REDIRECT bindings against the https://developer.okta.com/docs/guides/build-sso-integration/saml2/main/[Okta SAML 2.0 IDP] reference implementation.
`saml2Logout()` supports RP- and AP-initiated SAML 2.0 Single Logout via the HTTP-POST and HTTP-REDIRECT bindings against the SimpleSAMLphp SAML 2.0 reference implementation.
On this sample, the SAML 2.0 Logout is using the HTTP-POST binding.
@@ -33,19 +33,19 @@ You can refer to the https://docs.spring.io/spring-security/reference/servlet/sa
=== Start up the Sample Boot Application
```
./gradlew :servlet:spring-boot:java:saml2:login:bootRun
./gradlew :spring-security-samples-boot-saml2login:bootRun
```
=== Open a Browser
http://localhost:8080/
You will be redirect to the Okta SAML 2.0 IDP
You will be redirect to the SimpleSAMLphp IDP
=== Type in your credentials
```
User: testuser@spring.security.saml
Password: 12345678
User: user
Password: password
```
@@ -1,22 +1,21 @@
plugins {
id 'org.springframework.boot' version '2.7.1'
id 'org.springframework.boot' version '2.5.2'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id "nebula.integtest" version "8.2.0"
id 'java'
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://build.shibboleth.net/nexus/content/repositories/releases/" }
}
dependencies {
constraints {
implementation "org.opensaml:opensaml-core:4.2.0"
implementation "org.opensaml:opensaml-saml-api:4.2.0"
implementation "org.opensaml:opensaml-saml-impl:4.2.0"
implementation "org.opensaml:opensaml-core:4.1.1"
implementation "org.opensaml:opensaml-saml-api:4.1.1"
implementation "org.opensaml:opensaml-saml-impl:4.1.1"
}
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
@@ -32,4 +31,4 @@ dependencies {
tasks.withType(Test).configureEach {
useJUnitPlatform()
outputs.upToDateWhen { false }
}
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
File diff suppressed because one or more lines are too long
@@ -27,7 +27,7 @@ public class IndexController {
@GetMapping("/")
public String index(Model model, @AuthenticationPrincipal Saml2AuthenticatedPrincipal principal) {
String emailAddress = principal.getFirstAttribute("email");
String emailAddress = principal.getFirstAttribute("emailAddress");
model.addAttribute("emailAddress", emailAddress);
model.addAttribute("userAttributes", principal.getAttributes());
return "index";
@@ -0,0 +1,62 @@
/*
* Copyright 2002-2021 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 example;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.saml2.provider.service.metadata.OpenSamlMetadataResolver;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.Saml2MetadataFilter;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class SecurityConfiguration {
@Bean
SecurityFilterChain app(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeHttpRequests((authorize) -> authorize
.anyRequest().authenticated()
)
.saml2Login(Customizer.withDefaults())
.saml2Logout(Customizer.withDefaults());
// @formatter:on
return http.build();
}
@Bean
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver(
RelyingPartyRegistrationRepository registrations) {
return new DefaultRelyingPartyRegistrationResolver(registrations);
}
@Bean
FilterRegistrationBean<Saml2MetadataFilter> metadata(RelyingPartyRegistrationResolver registrations) {
Saml2MetadataFilter metadata = new Saml2MetadataFilter(registrations, new OpenSamlMetadataResolver());
FilterRegistrationBean<Saml2MetadataFilter> filter = new FilterRegistrationBean<>(metadata);
filter.setOrder(-101);
return filter;
}
}
@@ -1,16 +1,20 @@
logging.level:
org.springframework.security: TRACE
spring:
security:
saml2:
relyingparty:
registration:
one:
signing.credentials:
signing.credentials: &rp-metadata
- private-key-location: classpath:credentials/rp-private.key
certificate-location: classpath:credentials/rp-certificate.crt
singlelogout:
binding: POST
url: "{baseUrl}/logout/saml2/slo"
assertingparty.metadata-uri: https://dev-05937739.okta.com/app/exk46xofd8NZvFCpS5d7/sso/saml/metadata
identityprovider:
metadata-uri: https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/metadata.php
two:
signing.credentials: *rp-metadata
decryption.credentials: *rp-metadata
identityprovider:
metadata-uri: https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/metadata.php
logging.level:
org.springframework.security: TRACE
@@ -36,6 +36,11 @@
</button>
</form>
</li>
<li class="nav-item">
<a id="ap_logout_button" class="nav-link" href="https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/SingleLogoutService.php?ReturnTo=http://localhost:8080/login?logout">
AP-initiated Logout
</a>
</li>
</ul>
</div>
<main role="main" class="container">
@@ -1,4 +1,4 @@
= SAML 2.0 Refreshable Metadata
= SAML 2.0 Login & Logout Sample
This guide provides instructions on setting up this SAML 2.0 Login & Logout sample application.
It uses https://simplesamlphp.org/[SimpleSAMLphp] as its asserting party.
@@ -12,18 +12,18 @@ The https://docs.spring.io/spring-security/reference/servlet/saml2/logout.html[S
=== SAML 2.0 Login
`saml2Login()` provides a very simple implementation of a Service Provider that can receive a SAML 2.0 Response via the HTTP-POST and HTTP-REDIRECT bindings against the https://developer.okta.com/docs/guides/build-sso-integration/saml2/main/[Okta SAML 2.0 IDP] reference implementation.
`saml2Login()` provides a very simple implementation of a Service Provider that can receive a SAML 2.0 Response via the HTTP-POST and HTTP-REDIRECT bindings against the SimpleSAMLphp SAML 2.0 reference implementation.
The following features are implemented in the MVP:
1. Receive and validate a SAML 2.0 Response containing an assertion, and create a corresponding authentication in Spring Security
2. Send a SAML 2.0 AuthNRequest to an Identity Provider
3. Provide a framework for components used in SAML 2.0 authentication that can be swapped by configuration
4. Work against the Okta SAML 2.0 IDP reference implementation
4. Work against the SimpleSAMLphp reference implementation
=== SAML 2.0 Single Logout
`saml2Logout()` supports RP- and AP-initiated SAML 2.0 Single Logout via the HTTP-POST and HTTP-REDIRECT bindings against the https://developer.okta.com/docs/guides/build-sso-integration/saml2/main/[Okta SAML 2.0 IDP] reference implementation.
`saml2Logout()` supports RP- and AP-initiated SAML 2.0 Single Logout via the HTTP-POST and HTTP-REDIRECT bindings against the SimpleSAMLphp SAML 2.0 reference implementation.
On this sample, the SAML 2.0 Logout is using the HTTP-POST binding.
@@ -45,14 +45,12 @@ This particular implementation uses a `@Scheduled` annotation to update its meta
http://localhost:8080/
You will be redirect to the Okta SAML 2.0 IDP
You will be redirect to the SimpleSAMLphp IDP
=== Type in your credentials
```
User: testuser@spring.security.saml
Password: 12345678
User: user
Password: password
```
@@ -6,8 +6,7 @@ plugins {
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
jcenter()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://build.shibboleth.net/nexus/content/repositories/releases/" }
}
@@ -24,7 +23,7 @@ dependencies {
implementation 'org.springframework.security:spring-security-saml2-service-provider'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
testImplementation 'net.sourceforge.htmlunit:htmlunit:2.44.0'
testImplementation 'net.sourceforge.htmlunit:htmlunit'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
}
@@ -32,4 +31,4 @@ dependencies {
tasks.withType(Test).configureEach {
useJUnitPlatform()
outputs.upToDateWhen { false }
}
}
@@ -1,2 +1,2 @@
version=5.8.0-SNAPSHOT
spring-security.version=5.8.0-SNAPSHOT
version=5.6.0
spring-security.version=5.6.0
File diff suppressed because one or more lines are too long
@@ -27,7 +27,7 @@ public class IndexController {
@GetMapping("/")
public String index(Model model, @AuthenticationPrincipal Saml2AuthenticatedPrincipal principal) {
String emailAddress = principal.getFirstAttribute("email");
String emailAddress = principal.getFirstAttribute("emailAddress");
model.addAttribute("emailAddress", emailAddress);
model.addAttribute("userAttributes", principal.getAttributes());
return "index";

Some files were not shown because too many files have changed in this diff Show More