diff --git a/servlet/java-configuration/saml2/login/build.gradle b/servlet/java-configuration/saml2/login/build.gradle
index 2f02269..da355e3 100644
--- a/servlet/java-configuration/saml2/login/build.gradle
+++ b/servlet/java-configuration/saml2/login/build.gradle
@@ -55,10 +55,10 @@ dependencies {
testImplementation "org.springframework:spring-test"
testImplementation "org.springframework.security:spring-security-test"
testImplementation("org.junit.jupiter:junit-jupiter-api")
+ testImplementation "org.seleniumhq.selenium:htmlunit-driver:2.44.0"
+ testImplementation 'org.hamcrest:hamcrest:2.2'
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine")
-
- integTestImplementation "org.seleniumhq.selenium:htmlunit-driver:2.44.0"
}
tasks.withType(Test).configureEach {
diff --git a/servlet/java-configuration/saml2/login/src/integTest/java/example/LocalHostWebClient.java b/servlet/java-configuration/saml2/login/src/integTest/java/example/LocalHostWebClient.java
new file mode 100644
index 0000000..8cefa23
--- /dev/null
+++ b/servlet/java-configuration/saml2/login/src/integTest/java/example/LocalHostWebClient.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 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 java.io.IOException;
+
+import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException;
+import com.gargoylesoftware.htmlunit.Page;
+import com.gargoylesoftware.htmlunit.WebClient;
+
+import org.springframework.core.env.Environment;
+import org.springframework.util.Assert;
+
+/**
+ * {@link WebClient} will automatically prefix relative URLs with
+ * localhost:${local.server.port}
.
+ *
+ * @author Phillip Webb
+ * @since 1.4.0
+ */
+public class LocalHostWebClient extends WebClient {
+
+ private final Environment environment;
+
+ public LocalHostWebClient(Environment environment) {
+ Assert.notNull(environment, "Environment must not be null");
+ this.environment = environment;
+ }
+
+ @Override
+ public
P getPage(String url) throws IOException, FailingHttpStatusCodeException { + if (url.startsWith("/")) { + String port = this.environment.getProperty("local.server.port", "8080"); + url = "http://localhost:" + port + url; + } + return super.getPage(url); + } + +} diff --git a/servlet/java-configuration/saml2/login/src/integTest/java/example/Saml2JavaConfigurationITests.java b/servlet/java-configuration/saml2/login/src/integTest/java/example/Saml2JavaConfigurationITests.java new file mode 100644 index 0000000..3cd5ac1 --- /dev/null +++ b/servlet/java-configuration/saml2/login/src/integTest/java/example/Saml2JavaConfigurationITests.java @@ -0,0 +1,100 @@ +/* + * Copyright 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 java.io.IOException; + +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.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.core.env.Environment; +import org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.context.web.WebAppConfiguration; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.htmlunit.MockMvcWebClientBuilder; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +@ExtendWith(SpringExtension.class) +@ContextConfiguration(classes = ApplicationConfiguration.class) +@WebAppConfiguration +public class Saml2JavaConfigurationITests { + + private MockMvc mvc; + + private WebClient webClient; + + @Autowired + WebApplicationContext webApplicationContext; + + @Autowired + Environment environment; + + @BeforeEach + void setup() { + this.mvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext) + .apply(SecurityMockMvcConfigurers.springSecurity()).build(); + this.webClient = MockMvcWebClientBuilder.mockMvcSetup(this.mvc) + .withDelegate(new LocalHostWebClient(this.environment)).build(); + this.webClient.getCookieManager().clearCookies(); + } + + @Test + void authenticationAttemptWhenValidThenShowsUserEmailAddress() throws Exception { + HtmlPage relyingParty = performLogin(); + Assertions.assertThat(relyingParty.asText()).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(); + Assertions.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(); + Assertions.assertThat(loginPage.getUrl().getFile()).isEqualTo("/login?logout"); + } + + private HtmlPage performLogin() throws IOException { + HtmlPage login = this.webClient.getPage("/"); + HtmlForm form = login.getFormByName("f"); + HtmlInput username = form.getInputByName("username"); + HtmlInput password = form.getInputByName("password"); + HtmlSubmitInput submit = login.getHtmlElementById("submit_button"); + username.setValueAttribute("user"); + password.setValueAttribute("password"); + return submit.click(); + } + +} diff --git a/servlet/java-configuration/saml2/login/src/main/java/example/SecurityConfiguration.java b/servlet/java-configuration/saml2/login/src/main/java/example/SecurityConfiguration.java index fd05fc1..50daa56 100644 --- a/servlet/java-configuration/saml2/login/src/main/java/example/SecurityConfiguration.java +++ b/servlet/java-configuration/saml2/login/src/main/java/example/SecurityConfiguration.java @@ -32,8 +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.web.DefaultRelyingPartyRegistrationResolver; -import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver; import org.springframework.security.web.SecurityFilterChain; @EnableWebSecurity @@ -56,12 +54,6 @@ public class SecurityConfiguration { return http.build(); } - @Bean - RelyingPartyRegistrationResolver relyingPartyRegistrationResolver( - RelyingPartyRegistrationRepository registrations) { - return new DefaultRelyingPartyRegistrationResolver(registrations); - } - @Bean RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() { RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations