From b6cb65bbff33292a04abb4abe289cb0bb868b080 Mon Sep 17 00:00:00 2001 From: Duane May Date: Mon, 8 Jul 2024 18:14:51 -0400 Subject: [PATCH] wip: Identity Zone data for default zone Signed-off-by: Duane May Signed-off-by: Peter Chen --- server/build.gradle | 1 + .../IdentityZoneConfigurationBootstrap.java | 2 + .../provider/saml/SamlMetadataEndpoint.java | 68 +++++------ ...entityZoneConfigurationBootstrapTests.java | 11 +- .../saml/SamlMetadataEndpointTest.java | 108 ++++++++++++++++++ .../uaa/integration/feature/SamlLoginIT.java | 60 +++++----- 6 files changed, 184 insertions(+), 66 deletions(-) create mode 100644 server/src/test/java/org/cloudfoundry/identity/uaa/provider/saml/SamlMetadataEndpointTest.java diff --git a/server/build.gradle b/server/build.gradle index f9a2c289933..6efd1517b1c 100644 --- a/server/build.gradle +++ b/server/build.gradle @@ -112,6 +112,7 @@ dependencies { testImplementation(libraries.jsonPathAssert) testImplementation(libraries.guavaTestLib) + testImplementation(libraries.xmlUnit) implementation(libraries.commonsIo) } diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/impl/config/IdentityZoneConfigurationBootstrap.java b/server/src/main/java/org/cloudfoundry/identity/uaa/impl/config/IdentityZoneConfigurationBootstrap.java index baaeaf5ebf2..96e8ca1ccf3 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/impl/config/IdentityZoneConfigurationBootstrap.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/impl/config/IdentityZoneConfigurationBootstrap.java @@ -86,6 +86,8 @@ public void afterPropertiesSet() throws InvalidIdentityZoneDetailsException { definition.getLinks().getSelfService().setSelfServiceLinksEnabled(selfServiceLinksEnabled); definition.getLinks().setHomeRedirect(homeRedirect); definition.getSamlConfig().setCertificate(samlSpCertificate); + // TODO: This needs to pull from the default saml config + definition.getSamlConfig().setWantAssertionSigned(false); definition.getSamlConfig().setPrivateKey(samlSpPrivateKey); definition.getSamlConfig().setPrivateKeyPassword(samlSpPrivateKeyPassphrase); definition.getSamlConfig().setDisableInResponseToCheck(disableSamlInResponseToCheck); diff --git a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/SamlMetadataEndpoint.java b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/SamlMetadataEndpoint.java index 37374c341bf..9410152b331 100644 --- a/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/SamlMetadataEndpoint.java +++ b/server/src/main/java/org/cloudfoundry/identity/uaa/provider/saml/SamlMetadataEndpoint.java @@ -1,7 +1,9 @@ package org.cloudfoundry.identity.uaa.provider.saml; import org.cloudfoundry.identity.uaa.zone.IdentityZone; +import org.cloudfoundry.identity.uaa.zone.SamlConfig; import org.cloudfoundry.identity.uaa.zone.ZoneAware; +import org.cloudfoundry.identity.uaa.zone.beans.IdentityZoneManager; import org.opensaml.saml.common.xml.SAMLConstants; import org.opensaml.saml.saml2.metadata.EntityDescriptor; import org.opensaml.saml.saml2.metadata.SPSSODescriptor; @@ -11,14 +13,11 @@ import org.springframework.security.saml2.provider.service.metadata.Saml2MetadataResolver; 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.web.DefaultRelyingPartyRegistrationResolver; -import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver; import org.springframework.util.Assert; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; -import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -27,80 +26,73 @@ @RestController public class SamlMetadataEndpoint implements ZoneAware { public static final String DEFAULT_REGISTRATION_ID = "example"; - private static final String DEFAULT_FILE_NAME = "saml-sp.xml"; private static final String APPLICATION_XML_CHARSET_UTF_8 = "application/xml; charset=UTF-8"; - private static final String CONTENT_DISPOSITION_FORMAT = "attachment; filename=\"%s\"; filename*=UTF-8''%s"; - // @todo - this should be a Zone aware resolver - private final RelyingPartyRegistrationResolver relyingPartyRegistrationResolver; private final Saml2MetadataResolver saml2MetadataResolver; + private final IdentityZoneManager identityZoneManager; - private String fileName; - private String encodedFileName; - - private final Boolean wantAssertionSigned; private final RelyingPartyRegistrationRepository relyingPartyRegistrationRepository; public SamlMetadataEndpoint(RelyingPartyRegistrationRepository relyingPartyRegistrationRepository, - SamlConfigProps samlConfigProps) { + IdentityZoneManager identityZoneManager) { Assert.notNull(relyingPartyRegistrationRepository, "relyingPartyRegistrationRepository cannot be null"); this.relyingPartyRegistrationRepository = relyingPartyRegistrationRepository; - this.relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver(relyingPartyRegistrationRepository); + this.identityZoneManager = identityZoneManager; OpenSamlMetadataResolver resolver = new OpenSamlMetadataResolver(); this.saml2MetadataResolver = resolver; resolver.setEntityDescriptorCustomizer(new EntityDescriptorCustomizer()); - this.wantAssertionSigned = samlConfigProps.getWantAssertionSigned(); - setFileName(DEFAULT_FILE_NAME); } private class EntityDescriptorCustomizer implements Consumer { @Override public void accept(OpenSamlMetadataResolver.EntityDescriptorParameters entityDescriptorParameters) { + SamlConfig samlConfig = identityZoneManager.getCurrentIdentityZone().getConfig().getSamlConfig(); + EntityDescriptor descriptor = entityDescriptorParameters.getEntityDescriptor(); SPSSODescriptor spssodescriptor = descriptor.getSPSSODescriptor(SAMLConstants.SAML20P_NS); - spssodescriptor.setWantAssertionsSigned(wantAssertionSigned); + spssodescriptor.setWantAssertionsSigned(samlConfig.isWantAssertionSigned()); spssodescriptor.setAuthnRequestsSigned(entityDescriptorParameters.getRelyingPartyRegistration().getAssertingPartyDetails().getWantAuthnRequestsSigned()); } } @GetMapping(value = "/saml/metadata", produces = APPLICATION_XML_CHARSET_UTF_8) - public ResponseEntity legacyMetadataEndpoint(HttpServletRequest request) { - return metadataEndpoint(DEFAULT_REGISTRATION_ID, request); + public ResponseEntity legacyMetadataEndpoint() { + return metadataEndpoint(DEFAULT_REGISTRATION_ID); } @GetMapping(value = "/saml/metadata/{registrationId}", produces = APPLICATION_XML_CHARSET_UTF_8) - public ResponseEntity metadataEndpoint(@PathVariable String registrationId, HttpServletRequest request) { + public ResponseEntity metadataEndpoint(@PathVariable String registrationId) { RelyingPartyRegistration relyingPartyRegistration = relyingPartyRegistrationRepository.findByRegistrationId(registrationId); if (relyingPartyRegistration == null) { return ResponseEntity.status(HttpServletResponse.SC_UNAUTHORIZED).build(); } String metadata = saml2MetadataResolver.resolve(relyingPartyRegistration); - // @todo - fileName may need to be dynamic based on registrationID - String[] fileNames = retrieveZoneAwareFileNames(); + String contentDisposition = ContentDispositionFilename.getContentDisposition(retrieveZone()); return ResponseEntity.ok() - .header(HttpHeaders.CONTENT_DISPOSITION, String.format( - CONTENT_DISPOSITION_FORMAT, fileNames[0], fileNames[1])) + .header(HttpHeaders.CONTENT_DISPOSITION, contentDisposition) .body(metadata); } +} - public void setFileName(String fileName) { - encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8); - this.fileName = fileName; - } +record ContentDispositionFilename(String fileName) { + private static final String CONTENT_DISPOSITION_FORMAT = "attachment; filename=\"%s\"; filename*=UTF-8''%s"; + private static final String DEFAULT_FILE_NAME = "saml-sp.xml"; - private String[] retrieveZoneAwareFileNames() { - IdentityZone zone = retrieveZone(); - String[] fileNames = new String[2]; + static ContentDispositionFilename retrieveZoneAwareContentDispositionFilename(IdentityZone zone) { if (zone.isUaa()) { - fileNames[0] = fileName; - fileNames[1] = encodedFileName; - } - else { - fileNames[0] = "saml-" + zone.getSubdomain() + "-sp.xml"; - fileNames[1] = URLEncoder.encode(fileNames[0], - StandardCharsets.UTF_8); + return new ContentDispositionFilename(DEFAULT_FILE_NAME); } - return fileNames; + String filename = "saml-%s-sp.xml".formatted(zone.getSubdomain()); + return new ContentDispositionFilename(filename); + } + + static String getContentDisposition(IdentityZone zone) { + return retrieveZoneAwareContentDispositionFilename(zone).getContentDisposition(); + } + + String getContentDisposition() { + String encodedFileName = URLEncoder.encode(fileName, StandardCharsets.UTF_8); + return CONTENT_DISPOSITION_FORMAT.formatted(fileName, encodedFileName); } } diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/config/IdentityZoneConfigurationBootstrapTests.java b/server/src/test/java/org/cloudfoundry/identity/uaa/config/IdentityZoneConfigurationBootstrapTests.java index c3a2e5699bf..b84ce18016a 100644 --- a/server/src/test/java/org/cloudfoundry/identity/uaa/config/IdentityZoneConfigurationBootstrapTests.java +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/config/IdentityZoneConfigurationBootstrapTests.java @@ -143,6 +143,16 @@ void defaultSamlKeys() throws Exception { assertThat(uaa.getConfig().getSamlConfig().getCertificate()).isEqualTo(SamlTestUtils.PROVIDER_CERTIFICATE); } + @Test + void samlWantAssertionSigned() throws Exception { + bootstrap.setSamlSpPrivateKey(SamlTestUtils.PROVIDER_PRIVATE_KEY); + bootstrap.setSamlSpCertificate(SamlTestUtils.PROVIDER_CERTIFICATE); + bootstrap.setSamlSpPrivateKeyPassphrase(SamlTestUtils.PROVIDER_PRIVATE_KEY_PASSWORD); + bootstrap.afterPropertiesSet(); + IdentityZone uaa = provisioning.retrieve(IdentityZone.getUaaZoneId()); + assertThat(uaa.getConfig().getSamlConfig().isWantAssertionSigned()).isEqualTo(false); + } + @Test void enableInResponseTo() throws Exception { bootstrap.setDisableSamlInResponseToCheck(false); @@ -253,7 +263,6 @@ void logoutRedirect() throws Exception { assertThat(config.getLinks().getLogout().isDisableRedirectParameter()).isFalse(); } - @Test void testPrompts() throws Exception { List prompts = Arrays.asList( diff --git a/server/src/test/java/org/cloudfoundry/identity/uaa/provider/saml/SamlMetadataEndpointTest.java b/server/src/test/java/org/cloudfoundry/identity/uaa/provider/saml/SamlMetadataEndpointTest.java new file mode 100644 index 00000000000..4efc84f87b2 --- /dev/null +++ b/server/src/test/java/org/cloudfoundry/identity/uaa/provider/saml/SamlMetadataEndpointTest.java @@ -0,0 +1,108 @@ +package org.cloudfoundry.identity.uaa.provider.saml; + +import org.cloudfoundry.identity.uaa.zone.IdentityZone; +import org.cloudfoundry.identity.uaa.zone.IdentityZoneConfiguration; +import org.cloudfoundry.identity.uaa.zone.SamlConfig; +import org.cloudfoundry.identity.uaa.zone.beans.IdentityZoneManager; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.mock.web.MockHttpServletRequest; +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.Saml2MessageBinding; +import org.xmlunit.assertj.XmlAssert; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.cloudfoundry.identity.uaa.provider.saml.Saml2TestUtils.xmlNamespaces; +import static org.cloudfoundry.identity.uaa.provider.saml.TestSaml2X509Credentials.relyingPartySigningCredential; +import static org.cloudfoundry.identity.uaa.provider.saml.TestSaml2X509Credentials.relyingPartyVerifyingCredential; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class SamlMetadataEndpointTest { + private static final String ASSERTION_CONSUMER_SERVICE = "https://acsl"; + private static final String REGISTRATION_ID = "regId"; + private static final String ENTITY_ID = "entityId"; + + SamlMetadataEndpoint endpoint; + + @Mock + RelyingPartyRegistrationRepository repository; + @Mock + IdentityZoneManager identityZoneManager; + @Mock + RelyingPartyRegistration registration; + @Mock + IdentityZone identityZone; + @Mock + IdentityZoneConfiguration identityZoneConfiguration; + @Mock + SamlConfig samlConfig; + @Mock + RelyingPartyRegistration.AssertingPartyDetails assertingPartyDetails; + + @BeforeEach + void setUp() { + endpoint = spy(new SamlMetadataEndpoint(repository, identityZoneManager)); + when(repository.findByRegistrationId(REGISTRATION_ID)).thenReturn(registration); + when(registration.getEntityId()).thenReturn(ENTITY_ID); + when(registration.getSigningX509Credentials()).thenReturn(List.of(relyingPartySigningCredential())); + when(registration.getDecryptionX509Credentials()).thenReturn(List.of(relyingPartyVerifyingCredential())); + when(registration.getAssertionConsumerServiceBinding()).thenReturn(Saml2MessageBinding.REDIRECT); + when(registration.getAssertionConsumerServiceLocation()).thenReturn(ASSERTION_CONSUMER_SERVICE); + when(identityZoneManager.getCurrentIdentityZone()).thenReturn(identityZone); + when(identityZone.getConfig()).thenReturn(identityZoneConfiguration); + when(identityZoneConfiguration.getSamlConfig()).thenReturn(samlConfig); + when(registration.getAssertingPartyDetails()).thenReturn(assertingPartyDetails); + } + + @Test + void testDefaultFileName() { + ResponseEntity response = endpoint.metadataEndpoint(REGISTRATION_ID); + assertThat(response.getHeaders().getFirst(HttpHeaders.CONTENT_DISPOSITION)) + .isEqualTo("attachment; filename=\"saml-sp.xml\"; filename*=UTF-8''saml-sp.xml"); + } + + @Test + void testZonedFileName() { + when(identityZone.isUaa()).thenReturn(false); + when(identityZone.getSubdomain()).thenReturn("testzone1"); + when(endpoint.retrieveZone()).thenReturn(identityZone); + + ResponseEntity response = endpoint.metadataEndpoint(REGISTRATION_ID); + assertThat(response.getHeaders().getFirst(HttpHeaders.CONTENT_DISPOSITION)) + .isEqualTo("attachment; filename=\"saml-testzone1-sp.xml\"; filename*=UTF-8''saml-testzone1-sp.xml"); + } + + @Test + void testDefaultMetadataXml() { + when(samlConfig.isWantAssertionSigned()).thenReturn(true); + when(assertingPartyDetails.getWantAuthnRequestsSigned()).thenReturn(true); + + ResponseEntity response = endpoint.metadataEndpoint(REGISTRATION_ID); + XmlAssert xmlAssert =XmlAssert.assertThat(response.getBody()).withNamespaceContext(xmlNamespaces()); + xmlAssert.valueByXPath("//md:EntityDescriptor/@entityID").isEqualTo(ENTITY_ID); + xmlAssert.valueByXPath("//md:SPSSODescriptor/@AuthnRequestsSigned").isEqualTo(true); + xmlAssert.valueByXPath("//md:SPSSODescriptor/@WantAssertionsSigned").isEqualTo(true); + xmlAssert.valueByXPath("//md:AssertionConsumerService/@Location").isEqualTo(ASSERTION_CONSUMER_SERVICE); + } + + @Test + void testDefaultMetadataXml_alternateValues() { + when(samlConfig.isWantAssertionSigned()).thenReturn(false); + when(assertingPartyDetails.getWantAuthnRequestsSigned()).thenReturn(false); + + ResponseEntity response = endpoint.metadataEndpoint(REGISTRATION_ID); + XmlAssert xmlAssert =XmlAssert.assertThat(response.getBody()).withNamespaceContext(xmlNamespaces()); + xmlAssert.valueByXPath("//md:SPSSODescriptor/@AuthnRequestsSigned").isEqualTo(false); + xmlAssert.valueByXPath("//md:SPSSODescriptor/@WantAssertionsSigned").isEqualTo(false); + } +} diff --git a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/SamlLoginIT.java b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/SamlLoginIT.java index f74d03332e6..c820d6e79d0 100644 --- a/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/SamlLoginIT.java +++ b/uaa/src/test/java/org/cloudfoundry/identity/uaa/integration/feature/SamlLoginIT.java @@ -50,7 +50,6 @@ import org.cloudfoundry.identity.uaa.zone.IdentityZone; import org.cloudfoundry.identity.uaa.zone.IdentityZoneConfiguration; import org.flywaydb.core.internal.util.StringUtils; -import org.hamcrest.Matchers; import org.junit.Rule; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; @@ -76,6 +75,7 @@ import org.springframework.util.FileCopyUtils; import org.springframework.web.client.RestOperations; import org.springframework.web.client.RestTemplate; +import org.xmlunit.assertj.XmlAssert; import java.io.IOException; import java.io.InputStreamReader; @@ -107,10 +107,9 @@ import static org.cloudfoundry.identity.uaa.provider.ExternalIdentityProviderDefinition.EMAIL_ATTRIBUTE_NAME; import static org.cloudfoundry.identity.uaa.provider.ExternalIdentityProviderDefinition.GROUP_ATTRIBUTE_NAME; import static org.cloudfoundry.identity.uaa.provider.ExternalIdentityProviderDefinition.USER_ATTRIBUTE_PREFIX; +import static org.cloudfoundry.identity.uaa.provider.saml.Saml2TestUtils.xmlNamespaces; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.springframework.http.HttpMethod.GET; import static org.springframework.http.HttpMethod.POST; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; @@ -157,7 +156,9 @@ public class SamlLoginIT { @BeforeAll static void checkZoneDNSSupport() { - assertTrue(doesSupportZoneDNS(), "Expected testzone1.localhost, testzone2.localhost, testzone3.localhost, testzone4.localhost to resolve to 127.0.0.1"); + assertThat(doesSupportZoneDNS()) + .as("Expected testzone1.localhost, testzone2.localhost, testzone3.localhost, testzone4.localhost to resolve to 127.0.0.1") + .isTrue(); } public static String getValidRandomIDPMetaData() { @@ -216,23 +217,26 @@ void samlSPMetadata() { "%s/saml/metadata".formatted(baseUrl), String.class); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); String metadataXml = response.getBody(); + XmlAssert xmlAssert = XmlAssert.assertThat(metadataXml).withNamespaceContext(xmlNamespaces()); // The SAML SP metadata should match the following UAA configs: // login.entityID - assertThat(metadataXml).contains("entityID=\"cloudfoundry-saml-login\"") - // TODO: Are DigestMethod and SignatureMethod needed? - // login.saml.signatureAlgorithm - //.contains("") - //.contains("") - // login.saml.signRequest - .contains("AuthnRequestsSigned=\"true\"") - // login.saml.wantAssertionSigned - .contains("WantAssertionsSigned=\"true\"") - // login.saml.nameID - .contains("urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"); - - assertEquals("saml-sp.xml", - response.getHeaders().getContentDisposition().getFilename()); + xmlAssert.valueByXPath("//md:EntityDescriptor/@entityID").isEqualTo("cloudfoundry-saml-login"); + // login.saml.signRequest + xmlAssert.valueByXPath("//md:EntityDescriptor/md:SPSSODescriptor/@AuthnRequestsSigned").isEqualTo(true); + // login.saml.wantAssertionSigned + xmlAssert.valueByXPath("//md:EntityDescriptor/md:SPSSODescriptor/@WantAssertionsSigned").isEqualTo(true); + xmlAssert.valueByXPath("//md:EntityDescriptor/md:SPSSODescriptor/md:AssertionConsumerService/@Location").contains("/saml/SSO/alias/cloudfoundry-saml-login"); + +// assertThat(metadataXml).contains("entityID=\"cloudfoundry-saml-login\"") +// // TODO: Are DigestMethod and SignatureMethod needed? +// // login.saml.signatureAlgorithm +// //.contains("") +// //.contains("") +// // login.saml.nameID +// .contains("urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"); + + assertThat(response.getHeaders().getContentDisposition().getFilename()).isEqualTo("saml-sp.xml"); } @Test @@ -252,6 +256,7 @@ void samlSPMetadataForZone() { IdentityZoneConfiguration config = new IdentityZoneConfiguration(); config.getCorsPolicy().getDefaultConfiguration().setAllowedMethods(List.of(GET.toString(), POST.toString())); config.getSamlConfig().setEntityID(zoneId + "-saml-login"); + config.getSamlConfig().setWantAssertionSigned(false); IntegrationTestUtils.createZoneOrUpdateSubdomain(identityClient, baseUrl, zoneId, zoneId, config); RestTemplate request = new RestTemplate(); @@ -259,17 +264,18 @@ void samlSPMetadataForZone() { zoneUrl + "/saml/metadata", String.class); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); String metadataXml = response.getBody(); + XmlAssert xmlAssert = XmlAssert.assertThat(metadataXml).withNamespaceContext(xmlNamespaces()); // The SAML SP metadata should match the following UAA configs: // login.entityID - assertThat(metadataXml).contains("entityID=\"" + zoneId + "-saml-login\"") - .contains("AuthnRequestsSigned=\"true\"") - .contains("WantAssertionsSigned=\"true\"") - // TODO: Improve this check - .contains("/saml/SSO/alias/" + zoneId + ".cloudfoundry-saml-login"); - - assertEquals("saml-" + zoneId + "-sp.xml", - response.getHeaders().getContentDisposition().getFilename()); + xmlAssert.valueByXPath("//md:EntityDescriptor/@entityID").isEqualTo(zoneId + "-saml-login"); + // login.saml.signRequest + xmlAssert.valueByXPath("//md:EntityDescriptor/md:SPSSODescriptor/@AuthnRequestsSigned").isEqualTo(true); + // login.saml.wantAssertionSigned + xmlAssert.valueByXPath("//md:EntityDescriptor/md:SPSSODescriptor/@WantAssertionsSigned").isEqualTo(false); + xmlAssert.valueByXPath("//md:EntityDescriptor/md:SPSSODescriptor/md:AssertionConsumerService/@Location").contains("/saml/SSO/alias/testzone1.cloudfoundry-saml-login"); + + assertThat(response.getHeaders().getContentDisposition().getFilename()).isEqualTo("saml-testzone1-sp.xml"); } @Test @@ -491,7 +497,7 @@ void singleLogoutWithNoLogoutUrlOnIDPWithLogoutRedirect() { IntegrationTestUtils.createOrUpdateProvider(zoneAdminToken, baseUrl, provider); LoginPage loginPage = LoginPage.go(webDriver, zoneUrl); - loginPage.validateTitle(Matchers.containsString("testzone2")); + loginPage.validateTitle(containsString("testzone2")); loginPage.clickSamlLink_goesToSamlLoginPage("simplesamlphp") .login_goesToHomePage(testAccounts.getUserName(), testAccounts.getPassword());