Skip to content

Commit a4dbf45

Browse files
committed
Add relying-party-registrations#id
Closes gh-14487
1 parent 671a240 commit a4dbf45

File tree

8 files changed

+112
-11
lines changed

8 files changed

+112
-11
lines changed

Diff for: config/src/main/java/org/springframework/security/config/saml2/RelyingPartyRegistrationsBeanDefinitionParser.java

+7-2
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@ public final class RelyingPartyRegistrationsBeanDefinitionParser implements Bean
6464

6565
private static final String ELT_ENCRYPTION_CREDENTIAL = "encryption-credential";
6666

67+
private static final String ATT_ID = "id";
68+
6769
private static final String ATT_REGISTRATION_ID = "registration-id";
6870

6971
private static final String ATT_ASSERTING_PARTY_ID = "asserting-party-id";
@@ -108,8 +110,11 @@ public BeanDefinition parse(Element element, ParserContext parserContext) {
108110
.rootBeanDefinition(InMemoryRelyingPartyRegistrationRepository.class)
109111
.addConstructorArgValue(relyingPartyRegistrations)
110112
.getBeanDefinition();
111-
String relyingPartyRegistrationRepositoryId = parserContext.getReaderContext()
112-
.generateBeanName(relyingPartyRegistrationRepositoryBean);
113+
String relyingPartyRegistrationRepositoryId = element.getAttribute(ATT_ID);
114+
if (!StringUtils.hasText(relyingPartyRegistrationRepositoryId)) {
115+
relyingPartyRegistrationRepositoryId = parserContext.getReaderContext()
116+
.generateBeanName(relyingPartyRegistrationRepositoryBean);
117+
}
113118
parserContext.registerBeanComponent(new BeanComponentDefinition(relyingPartyRegistrationRepositoryBean,
114119
relyingPartyRegistrationRepositoryId));
115120
parserContext.popAndRegisterContainingComponent();

Diff for: config/src/main/resources/org/springframework/security/config/spring-security-6.3.rnc

+4-1
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,10 @@ saml2-logout.attlist &=
744744

745745
relying-party-registrations =
746746
## Container element for relying party(ies) registered with a SAML 2.0 identity provider
747-
element relying-party-registrations {relying-party-registration+, asserting-party*}
747+
element relying-party-registrations {relying-party-registrations.attlist, relying-party-registration+, asserting-party*}
748+
relying-party-registrations.attlist &=
749+
## The identifier by which to refer to the repository in other beans
750+
attribute id {xsd:token}?
748751

749752
relying-party-registration =
750753
## Represents a relying party registered with a SAML 2.0 identity provider

Diff for: config/src/main/resources/org/springframework/security/config/spring-security-6.3.xsd

+9
Original file line numberDiff line numberDiff line change
@@ -2188,8 +2188,17 @@
21882188
<xs:element maxOccurs="unbounded" ref="security:relying-party-registration"/>
21892189
<xs:element minOccurs="0" maxOccurs="unbounded" ref="security:asserting-party"/>
21902190
</xs:sequence>
2191+
<xs:attributeGroup ref="security:relying-party-registrations.attlist"/>
21912192
</xs:complexType>
21922193
</xs:element>
2194+
<xs:attributeGroup name="relying-party-registrations.attlist">
2195+
<xs:attribute name="id" type="xs:token">
2196+
<xs:annotation>
2197+
<xs:documentation>The identifier by which to refer to the repository in other beans
2198+
</xs:documentation>
2199+
</xs:annotation>
2200+
</xs:attribute>
2201+
</xs:attributeGroup>
21932202
<xs:element name="relying-party-registration">
21942203
<xs:annotation>
21952204
<xs:documentation>Represents a relying party registered with a SAML 2.0 identity provider

Diff for: config/src/test/java/org/springframework/security/config/saml2/RelyingPartyRegistrationsBeanDefinitionParserTests.java

+20
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,29 @@
1616

1717
package org.springframework.security.config.saml2;
1818

19+
import jakarta.servlet.http.HttpServletRequest;
1920
import okhttp3.mockwebserver.MockResponse;
2021
import okhttp3.mockwebserver.MockWebServer;
2122
import org.junit.jupiter.api.AfterEach;
2223
import org.junit.jupiter.api.Test;
2324
import org.junit.jupiter.api.extension.ExtendWith;
2425

2526
import org.springframework.beans.factory.annotation.Autowired;
27+
import org.springframework.beans.factory.annotation.Qualifier;
28+
import org.springframework.core.convert.converter.Converter;
2629
import org.springframework.http.HttpHeaders;
2730
import org.springframework.http.MediaType;
31+
import org.springframework.mock.web.MockHttpServletRequest;
2832
import org.springframework.security.config.test.SpringTestContext;
2933
import org.springframework.security.config.test.SpringTestContextExtension;
3034
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
3135
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
3236
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
3337
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
38+
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
3439

3540
import static org.assertj.core.api.Assertions.assertThat;
41+
import static org.mockito.Mockito.verify;
3642

3743
/**
3844
* Tests for {@link RelyingPartyRegistrationsBeanDefinitionParser}.
@@ -118,6 +124,7 @@ public class RelyingPartyRegistrationsBeanDefinitionParserTests {
118124
// @formatter:on
119125

120126
@Autowired
127+
@Qualifier("registrations")
121128
private RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;
122129

123130
public final SpringTestContext spring = new SpringTestContext(this);
@@ -268,6 +275,19 @@ public void parseWhenMultiRelyingPartyRegistrationThenAvailableInRepository() {
268275
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha384");
269276
}
270277

278+
@Test
279+
public void parseWhenRelayStateResolverThenUses() {
280+
this.spring.configLocations(xml("RelayStateResolver")).autowire();
281+
Converter<HttpServletRequest, String> relayStateResolver = this.spring.getContext().getBean(Converter.class);
282+
OpenSaml4AuthenticationRequestResolver authenticationRequestResolver = this.spring.getContext()
283+
.getBean(OpenSaml4AuthenticationRequestResolver.class);
284+
MockHttpServletRequest request = new MockHttpServletRequest();
285+
request.setRequestURI("/saml2/authenticate/one");
286+
request.setServletPath("/saml2/authenticate/one");
287+
authenticationRequestResolver.resolve(request);
288+
verify(relayStateResolver).convert(request);
289+
}
290+
271291
private static MockResponse xmlResponse(String xml) {
272292
return new MockResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_XML_VALUE).setBody(xml);
273293
}

Diff for: config/src/test/resources/org/springframework/security/config/saml2/RelyingPartyRegistrationsBeanDefinitionParserTests-MultiRegistration.xml

+5-5
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,20 @@
2323
https://www.springframework.org/schema/security/spring-security.xsd
2424
http://www.springframework.org/schema/beans
2525
https://www.springframework.org/schema/beans/spring-beans.xsd">
26-
27-
<relying-party-registrations>
26+
27+
<relying-party-registrations id="registrations">
2828
<relying-party-registration registration-id="one"
2929
entity-id="{baseUrl}/saml2/service-provider-metadata/{registrationId}"
3030
assertion-consumer-service-location="{baseUrl}/login/saml2/sso/{registrationId}"
3131
assertion-consumer-service-binding="REDIRECT"
3232
asserting-party-id="google"/>
33-
33+
3434
<relying-party-registration registration-id="two"
3535
entity-id="{baseUrl}/saml2/service-provider-metadata/{registrationId}"
3636
assertion-consumer-service-location="{baseUrl}/login/saml2/sso/{registrationId}"
3737
assertion-consumer-service-binding="POST"
3838
asserting-party-id="simple-saml"/>
39-
39+
4040
<asserting-party asserting-party-id="google" entity-id="https://accounts.google.com/o/saml2/idp/entity-id"
4141
want-authn-requests-signed="true"
4242
single-sign-on-service-location="https://accounts.google.com/o/saml2/idp/sso-url"
@@ -48,7 +48,7 @@
4848
certificate-location="classpath:org/springframework/security/config/saml2/idp-certificate.crt"
4949
private-key-location="classpath:org/springframework/security/config/saml2/rp-private.key"/>
5050
</asserting-party>
51-
51+
5252
<asserting-party asserting-party-id="simple-saml"
5353
entity-id="https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/metadata.php"
5454
single-sign-on-service-location="https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/SSOService.php"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright 2002-2021 the original author or authors.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ https://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
18+
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
19+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
20+
xmlns="http://www.springframework.org/schema/security"
21+
xsi:schemaLocation="
22+
http://www.springframework.org/schema/security
23+
https://www.springframework.org/schema/security/spring-security.xsd
24+
http://www.springframework.org/schema/beans
25+
https://www.springframework.org/schema/beans/spring-beans.xsd">
26+
27+
<relying-party-registrations id="registrations">
28+
<relying-party-registration registration-id="one"
29+
entity-id="{baseUrl}/saml2/service-provider-metadata/{registrationId}"
30+
assertion-consumer-service-location="{baseUrl}/login/saml2/sso/{registrationId}"
31+
assertion-consumer-service-binding="REDIRECT"
32+
asserting-party-id="google">
33+
<signing-credential
34+
certificate-location="classpath:org/springframework/security/config/saml2/rp-certificate.crt"
35+
private-key-location="classpath:org/springframework/security/config/saml2/rp-private.key"/>
36+
</relying-party-registration>
37+
<asserting-party asserting-party-id="google" entity-id="https://accounts.google.com/o/saml2/idp/entity-id"
38+
want-authn-requests-signed="true"
39+
single-sign-on-service-location="https://accounts.google.com/o/saml2/idp/sso-url"
40+
single-sign-on-service-binding="POST">
41+
<verification-credential
42+
certificate-location="classpath:org/springframework/security/config/saml2/idp-certificate.crt"
43+
private-key-location="classpath:org/springframework/security/config/saml2/rp-private.key"/>
44+
<encryption-credential
45+
certificate-location="classpath:org/springframework/security/config/saml2/idp-certificate.crt"
46+
private-key-location="classpath:org/springframework/security/config/saml2/rp-private.key"/>
47+
</asserting-party>
48+
</relying-party-registrations>
49+
50+
<b:bean class="org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver">
51+
<b:constructor-arg ref="registrations"/>
52+
<b:property name="relayStateResolver" ref="relayStateResolver"/>
53+
</b:bean>
54+
55+
<b:bean name="relayStateResolver" class="org.mockito.Mockito" factory-method="mock">
56+
<b:constructor-arg value="org.springframework.core.convert.converter.Converter" type="java.lang.Class"/>
57+
</b:bean>
58+
</b:beans>

Diff for: config/src/test/resources/org/springframework/security/config/saml2/RelyingPartyRegistrationsBeanDefinitionParserTests-SingleRegistration.xml

+3-3
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,14 @@
2323
https://www.springframework.org/schema/security/spring-security.xsd
2424
http://www.springframework.org/schema/beans
2525
https://www.springframework.org/schema/beans/spring-beans.xsd">
26-
27-
<relying-party-registrations>
26+
27+
<relying-party-registrations id="registrations">
2828
<relying-party-registration registration-id="one"
2929
entity-id="{baseUrl}/saml2/service-provider-metadata/{registrationId}"
3030
assertion-consumer-service-location="{baseUrl}/login/saml2/sso/{registrationId}"
3131
assertion-consumer-service-binding="REDIRECT"
3232
asserting-party-id="google"/>
33-
33+
3434
<asserting-party asserting-party-id="google" entity-id="https://accounts.google.com/o/saml2/idp/entity-id"
3535
want-authn-requests-signed="true"
3636
single-sign-on-service-location="https://accounts.google.com/o/saml2/idp/sso-url"

Diff for: docs/modules/ROOT/pages/servlet/appendix/namespace/http.adoc

+6
Original file line numberDiff line numberDiff line change
@@ -1331,6 +1331,12 @@ Reference to an `OpaqueTokenAuthenticationConverter`. Responsible for converting
13311331
== <relying-party-registrations>
13321332
The container element for relying party(ies) registered (xref:servlet/saml2/login/overview.adoc#servlet-saml2login-relyingpartyregistration[ClientRegistration]) with a SAML 2.0 Identity Provider.
13331333

1334+
[[nsa-relying-party-registrations-attributes]]
1335+
=== <relying-party-registrations> Attributes
1336+
1337+
[[nsa-relying-party-registrations-id]]
1338+
* **id**
1339+
The ID that uniquely identifies the `RelyingPartyRegistrationRepository`.
13341340

13351341
[[nsa-relying-party-registrations-children]]
13361342
=== Child Elements of <relying-party-registrations>

0 commit comments

Comments
 (0)