Browse Source

Update SAML 2.0 Login sample to use SAML 2.0 Logout

Closes gh-36
Josh Cummings 4 năm trước cách đây
mục cha
commit
cbd87c4e04

+ 15 - 2
servlet/spring-boot/java/saml2-login/README.adoc

@@ -1,12 +1,17 @@
-= SAML 2.0 Login Sample
+= SAML 2.0 Login & Logout Sample
 
-This guide provides instructions on setting up this SAML 2.0 Login sample application.
+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.
 
 The sample application uses Spring Boot and the `spring-security-saml2-service-provider`
 module which is new in Spring Security 5.2.
 
+The https://docs.spring.io/spring-security/site/docs/5.6.0-SNAPSHOT/reference/html5/#servlet-saml2login-logout[SAML 2.0 Logout feature] is new in Spring Security 5.6.
+
 == Goals
 
+=== 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 SimpleSAMLphp SAML 2.0 reference implementation.
 
 The following features are implemented in the MVP:
@@ -16,6 +21,14 @@ The following features are implemented in the MVP:
 3. Provide a framework for components used in SAML 2.0 authentication that can be swapped by configuration
 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 SimpleSAMLphp SAML 2.0 reference implementation.
+
+On this sample, the SAML 2.0 Logout is using the HTTP-POST binding.
+
+You can refer to the https://docs.spring.io/spring-security/site/docs/5.6.0-SNAPSHOT/reference/html5/#servlet-saml2login-logout[reference documentation] for more details about the RP- and AP-initiated SAML 2.0 Logout.
+
 == Run the Sample
 
 === Start up the Sample Boot Application

+ 31 - 3
servlet/spring-boot/java/saml2-login/src/integTest/java/example/Saml2LoginApplicationITests.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2020 the original author or authors.
+ * 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.
@@ -16,6 +16,7 @@
 
 package example;
 
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.LinkedHashMap;
 import java.util.List;
@@ -24,10 +25,12 @@ import java.util.Map;
 import javax.servlet.http.HttpSession;
 
 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.HtmlSubmitInput;
+import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 
 import org.springframework.beans.factory.annotation.Autowired;
@@ -63,6 +66,11 @@ public class Saml2LoginApplicationITests {
 	@Autowired
 	WebClient webClient;
 
+	@BeforeEach
+	void setup() {
+		this.webClient.getCookieManager().clearCookies();
+	}
+
 	@Test
 	void indexWhenSamlResponseThenShowsUserInformation() throws Exception {
 		HttpSession session = this.mvc.perform(get("http://localhost:8080/")).andExpect(status().is3xxRedirection())
@@ -79,6 +87,27 @@ public class Saml2LoginApplicationITests {
 
 	@Test
 	void authenticationAttemptWhenValidThenShowsUserEmailAddress() throws Exception {
+		HtmlPage relyingParty = performLogin();
+		assertThat(relyingParty.asNormalizedText()).contains("You're email address is testuser@spring.security.saml");
+	}
+
+	@Test
+	void logoutWhenRelyingPartyInitiatedLogoutThenLoginPageWithLogoutParam() throws Exception {
+		HtmlPage relyingParty = performLogin();
+		HtmlElement rpLogoutButton = relyingParty.getHtmlElementById("rp_logout_button");
+		HtmlPage loginPage = rpLogoutButton.click();
+		assertThat(loginPage.getUrl().getFile()).isEqualTo("/login?logout");
+	}
+
+	@Test
+	void logoutWhenAssertingPartyInitiatedLogoutThenLoginPageWithLogoutParam() throws Exception {
+		HtmlPage relyingParty = performLogin();
+		HtmlElement apLogoutButton = relyingParty.getHtmlElementById("ap_logout_button");
+		HtmlPage loginPage = apLogoutButton.click();
+		assertThat(loginPage.getUrl().getFile()).isEqualTo("/login?logout");
+	}
+
+	private HtmlPage performLogin() throws IOException {
 		HtmlPage assertingParty = this.webClient.getPage("/");
 		HtmlForm form = assertingParty.getFormByName("f");
 		HtmlInput username = form.getInputByName("username");
@@ -86,8 +115,7 @@ public class Saml2LoginApplicationITests {
 		HtmlSubmitInput submit = assertingParty.getHtmlElementById("submit_button");
 		username.setValueAttribute("user");
 		password.setValueAttribute("password");
-		HtmlPage relyingParty = submit.click();
-		assertThat(relyingParty.asText()).contains("You're email address is testuser@spring.security.saml");
+		return submit.click();
 	}
 
 }

+ 2 - 1
servlet/spring-boot/java/saml2-login/src/main/java/example/Saml2LoginApplication.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2020 the original author or authors.
+ * 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.
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package example;
 
 import org.springframework.boot.SpringApplication;

+ 42 - 0
servlet/spring-boot/java/saml2-login/src/main/java/example/SecurityConfiguration.java

@@ -0,0 +1,42 @@
+/*
+ * 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.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.web.SecurityFilterChain;
+
+@Configuration
+public class SecurityConfiguration {
+
+	@Bean
+	SecurityFilterChain app(HttpSecurity http) throws Exception {
+		// @formatter:off
+		http
+				.authorizeRequests((authorize) -> authorize
+					.anyRequest().authenticated()
+				)
+				.saml2Login(Customizer.withDefaults())
+				.saml2Logout(Customizer.withDefaults());
+		// @formatter:on
+
+		return http.build();
+	}
+
+}

+ 7 - 0
servlet/spring-boot/java/saml2-login/src/main/resources/application.yml

@@ -4,5 +4,12 @@ spring:
       relyingparty:
         registration:
           one:
+            signing.credentials:
+              - private-key-location: classpath:credentials/rp-private.key
+                certificate-location: classpath:credentials/rp-certificate.crt
             identityprovider:
               metadata-uri: https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/metadata.php
+
+
+logging.level:
+  org.springframework.security: TRACE

+ 31 - 17
servlet/spring-boot/java/saml2-login/src/main/resources/templates/index.html

@@ -1,5 +1,5 @@
 <!--
-  ~ Copyright 2002-2020 the original author or authors.
+  ~ 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.
@@ -17,30 +17,44 @@
 <!doctype html>
 <html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
 <head>
-    <title>Spring Security - SAML 2.0 Login</title>
+    <title>Spring Security - SAML 2.0 Login & Logout</title>
     <meta charset="utf-8" />
     <style>
         span, dt {
             font-weight: bold;
         }
     </style>
+    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
 </head>
 <body>
-<div>
-    <form th:action="@{/logout}" method="post">
-        <input type="submit" value="Logout" />
-    </form>
-    <a href="https://simplesaml-for-spring-saml.cfapps.io/module.php/core/authenticate.php?as=example-userpass&logout">
-        Log out of SimpleSAMLphp
-    </a>
+<div class="container">
+    <ul class="nav">
+        <li class="nav-item">
+            <form th:action="@{/logout}" method="post">
+                <button class="btn btn-primary" id="rp_logout_button" type="submit">
+                    RP-initiated Logout
+                </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">
+        <h1 class="mt-5">SAML 2.0 Login & Single Logout with Spring Security</h1>
+        <p class="lead">You are successfully logged in as <span sec:authentication="name"></span></p>
+        <p class="lead">You're email address is <span th:text="${emailAddress}"></span></p>
+        <h2 class="mt-2">All Your Attributes</h2>
+        <dl th:each="userAttribute : ${userAttributes}">
+            <dt th:text="${userAttribute.key}"></dt>
+            <dd th:text="${userAttribute.value}"></dd>
+        </dl>
+
+        <h6>Visit the <a href="https://docs.spring.io/spring-security/site/docs/current/reference/html5/#servlet-saml2" target="_blank">SAML 2.0 Login & Logout</a> documentation for more details.</h6>
+    </main>
 </div>
-<h1>SAML 2.0 Login with Spring Security</h1>
-<p>You are successfully logged in as <span sec:authentication="name"></span></p>
-<p>You're email address is <span th:text="${emailAddress}"></span></p>
-<h2>All Your Attributes</h2>
-<dl th:each="userAttribute : ${userAttributes}">
-    <dt th:text="${userAttribute.key}"></dt>
-    <dd th:text="${userAttribute.value}"></dd>
-</dl>
 </body>
 </html>