Skip to content

Commit

Permalink
wip: Ensuring the WantsAssertionSigned and AuthnRequestsSigned are po…
Browse files Browse the repository at this point in the history
…pulated in SPSSODescriptor

- Building out EntityDescriptor in the RelyingPartyRegistration which contains the SPSSODescriptor picked up by the resolve method

[#186986697]

Co-authored-by: Duane May <duane.may@broadcom.com>
  • Loading branch information
Tallicia and duanemay committed Apr 18, 2024
1 parent 8759b56 commit dac04b6
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
package org.cloudfoundry.identity.uaa.provider.saml;


import org.cloudfoundry.identity.uaa.provider.saml.SamlRelyingPartyRegistrationRepository;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.saml2.metadata.EntityDescriptor;
import org.opensaml.saml.saml2.metadata.SPSSODescriptor;
import org.opensaml.saml.saml2.metadata.impl.IDPSSODescriptorBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
Expand All @@ -9,19 +16,27 @@
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.registration.RelyingPartyRegistrations;
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
import org.springframework.stereotype.Controller;
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.ResponseBody;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.function.Consumer;

import org.opensaml.saml.saml2.metadata.SPSSODescriptor;



@Controller
public class SamlMetadataEndpoint {
Expand All @@ -37,13 +52,26 @@ public class SamlMetadataEndpoint {
private String fileName;
private String encodedFileName;

private class EntityDescriptorCustomizer implements Consumer<OpenSamlMetadataResolver.EntityDescriptorParameters> {

@Override
public void accept(OpenSamlMetadataResolver.EntityDescriptorParameters entityDescriptorParameters) {
EntityDescriptor descriptor = entityDescriptorParameters.getEntityDescriptor();
SPSSODescriptor spssodescriptor = descriptor.getSPSSODescriptor(SAMLConstants.SAML20P_NS);
spssodescriptor.setWantAssertionsSigned(true);
spssodescriptor.setAuthnRequestsSigned(true);
}
}

public SamlMetadataEndpoint(
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository

) {
Assert.notNull(relyingPartyRegistrationRepository, "relyingPartyRegistrationRepository cannot be null");
this.relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver(relyingPartyRegistrationRepository);
this.saml2MetadataResolver = new OpenSamlMetadataResolver();
OpenSamlMetadataResolver resolver = new OpenSamlMetadataResolver();
this.saml2MetadataResolver = resolver;
resolver.setEntityDescriptorCustomizer(new EntityDescriptorCustomizer());
setFileName(DEFAULT_FILE_NAME);
}

Expand All @@ -53,6 +81,9 @@ public ResponseEntity<String> legacyMetadataEndpoint(HttpServletRequest request)
return metadataEndpoint(DEFAULT_REGISTRATION_ID, request);
}

@Autowired
private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;

@GetMapping(value = "/saml/metadata/{registrationId}", produces = APPLICATION_XML_CHARSET_UTF_8)
@ResponseBody
public ResponseEntity<String> metadataEndpoint(@PathVariable String registrationId,
Expand All @@ -61,10 +92,12 @@ public ResponseEntity<String> metadataEndpoint(@PathVariable String registration

) {

String format = "attachment; filename=\"%s\"; filename*=UTF-8''%s";
// String format = "attachment; filename=\"%s\"; filename*=UTF-8''%s";
String format = "attachment; filename=\"%s\"; filename*=UTF-8";

RelyingPartyRegistration relyingPartyRegistration =
this.relyingPartyRegistrationResolver.resolve(request,registrationId);
// RelyingPartyRegistration relyingPartyRegistration =
// this.relyingPartyRegistrationResolver.resolve(request,registrationId);
RelyingPartyRegistration relyingPartyRegistration = relyingPartyRegistrationRepository.findByRegistrationId(registrationId);
if (relyingPartyRegistration == null) {
return ResponseEntity.status(HttpServletResponse.SC_UNAUTHORIZED).build();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.cloudfoundry.identity.uaa.provider.saml;

import org.apache.commons.io.IOUtils;
import org.opensaml.saml.saml2.metadata.SPSSODescriptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
Expand Down Expand Up @@ -32,12 +33,40 @@ public class SamlRelyingPartyRegistrationRepository {

@Bean
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {

String CLASSPATH_DUMMY_SAML_IDP_METADATA_XML = "classpath:dummy-saml-idp-metadata.xml";
String samlEntityID = "integration-saml-entity-id";
String samlNameIDFormat = "example-NAME_ID_FORMAT";

RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations
.fromMetadataLocation(CLASSPATH_DUMMY_SAML_IDP_METADATA_XML)
.entityId(samlEntityID)
.nameIdFormat(samlSpNameID)
.nameIdFormat(samlNameIDFormat)
.registrationId("example")
.assertingPartyDetails(details -> details
.entityId(samlEntityID)
.wantAuthnRequestsSigned(true)
.signingAlgorithms(algos -> algos.add(""))
)
.build();


// RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations
// .fromMetadataLocation(CLASSPATH_DUMMY_SAML_IDP_METADATA_XML)
// .entityId(samlEntityID)
// .nameIdFormat(samlSpNameID)
// .registrationId("example")
// .assertingPartyDetails(details -> details
// .wantAuthnRequestsSigned(true)
// .entityId("TEST_REG_REP")
// )
// .assertingPartyDetails(party -> party
// .entityId("XXXXXXXXX---" + samlEntityID)
//// .singleSignOnServiceLocation("https://idp.example.com/SSO.saml2")
// .wantAuthnRequestsSigned(true)
//// .verificationX509Credentials(c -> c.add(credential))
// )
// .build();
return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.xpath;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;

@DefaultTestContext
class SamlMetadataMockMvcTests {
Expand All @@ -26,6 +27,19 @@ void legacyMetadataRoot() throws Exception {
.andExpect(forwardedUrl("/saml/metadata/example"));
}

@Test
void testSamlMetadataRootNoEndingSlash() throws Exception {
mockMvc.perform(get(new URI("/saml/metadata")))
.andExpect(status().isOk());
}

@Test
void testSamlMetadataRootWithEndingSlash() throws Exception {
mockMvc.perform(get(new URI("/saml/metadata/")))
.andExpect(status().isOk());
}


@Test
void testSamlMetadataDefaultNoEndingSlash() throws Exception {
mockMvc.perform(get(new URI("/saml/metadata/example")))
Expand All @@ -43,10 +57,13 @@ void testSamlMetadataXMLValidation() throws Exception {
ResultActions response = null;

ResultActions xml = mockMvc.perform(get(new URI("/saml/metadata/example")))
.andDo(print())
.andExpect(status().isOk());
// // The SAML SP metadata should match the following UAA configs:
// // login.entityID
xml.andExpect(xpath("/EntityDescriptor/@entityID").string(SAML_ENTITY_ID));
xml.andExpect(xpath("/EntityDescriptor/@entityID").string(SAML_ENTITY_ID))
.andExpect(xpath("/EntityDescriptor/SPSSODescriptor/@AuthnRequestsSigned").booleanValue(true))
.andExpect(xpath("/EntityDescriptor/SPSSODescriptor/@WantAssertionsSigned").booleanValue(true));

// xpath("...ds:DigestMethod/@Algorithm").string("http://www.w3.org/2001/04/xmlenc#sha256");

Expand Down

0 comments on commit dac04b6

Please sign in to comment.