Skip to content

Commit 2e02987

Browse files
committed
Polish refreshable-metadata Sample
1 parent 0a7da94 commit 2e02987

File tree

6 files changed

+208
-128
lines changed

6 files changed

+208
-128
lines changed

servlet/spring-boot/java/saml2/refreshable-metadata/src/integTest/java/example/Saml2LoginApplicationITests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ void logoutWhenRelyingPartyInitiatedLogoutThenLoginPageWithLogoutParam() throws
8282
}
8383

8484
private void performLogin() throws Exception {
85-
HtmlPage login = this.webClient.getPage("http://localhost:" + this.port + "/saml2/authenticate/one");
85+
HtmlPage login = this.webClient.getPage("http://localhost:" + this.port);
8686
this.webClient.waitForBackgroundJavaScript(10000);
8787
HtmlForm form = findForm(login);
8888
HtmlInput username = form.getInputByName("username");

servlet/spring-boot/java/saml2/refreshable-metadata/src/main/java/example/RefreshableRelyingPartyRegistrationRepository.java

-112
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
/*
2+
* Copyright 2002-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package example;
18+
19+
import java.io.IOException;
20+
import java.io.InputStream;
21+
import java.security.cert.CertificateException;
22+
import java.security.cert.CertificateFactory;
23+
import java.security.cert.X509Certificate;
24+
import java.security.interfaces.RSAPrivateKey;
25+
26+
import org.springframework.boot.context.properties.ConfigurationProperties;
27+
import org.springframework.boot.io.ApplicationResourceLoader;
28+
import org.springframework.core.io.Resource;
29+
import org.springframework.core.io.ResourceLoader;
30+
import org.springframework.security.saml2.core.Saml2X509Credential;
31+
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
32+
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
33+
import org.springframework.stereotype.Component;
34+
35+
@Component
36+
@ConfigurationProperties("saml2")
37+
public class RelyingPartyMetadata {
38+
39+
private final ResourceLoader resourceLoader = new ApplicationResourceLoader();
40+
41+
private String entityId = "{baseUrl}/saml2/metadata";
42+
43+
private String sso = "{baseUrl}/login/saml2/sso";
44+
45+
private SingleLogout slo = new SingleLogout();
46+
47+
private X509Certificate certificate;
48+
49+
private RSAPrivateKey key;
50+
51+
public RelyingPartyRegistration apply(RelyingPartyRegistration.Builder builder) {
52+
Saml2X509Credential signing = Saml2X509Credential.signing(this.key, this.certificate);
53+
return builder.entityId(this.entityId)
54+
.assertionConsumerServiceLocation(this.sso)
55+
.singleLogoutServiceBinding(this.slo.getBinding())
56+
.singleLogoutServiceLocation(this.slo.getLocation())
57+
.singleLogoutServiceResponseLocation(this.slo.getResponseLocation())
58+
.signingX509Credentials((c) -> c.add(signing))
59+
.build();
60+
}
61+
62+
public void setEntityId(String entityId) {
63+
this.entityId = entityId;
64+
}
65+
66+
public void setSso(String sso) {
67+
this.sso = sso;
68+
}
69+
70+
public void setSlo(SingleLogout slo) {
71+
this.slo = slo;
72+
}
73+
74+
public void setCertificate(String certificate) {
75+
Resource source = this.resourceLoader.getResource(certificate);
76+
try (InputStream in = source.getInputStream()) {
77+
CertificateFactory certificates = CertificateFactory.getInstance("X.509");
78+
this.certificate = (X509Certificate) certificates.generateCertificate(in);
79+
}
80+
catch (CertificateException | IOException ex) {
81+
throw new IllegalArgumentException(ex);
82+
}
83+
}
84+
85+
public void setKey(RSAPrivateKey key) {
86+
this.key = key;
87+
}
88+
89+
public static class SingleLogout {
90+
91+
private Saml2MessageBinding binding = Saml2MessageBinding.REDIRECT;
92+
93+
private String location = "{baseUrl}/logout/saml2/slo";
94+
95+
private String responseLocation = "{baseUrl}/logout/saml2/slo";
96+
97+
public Saml2MessageBinding getBinding() {
98+
return this.binding;
99+
}
100+
101+
public void setBinding(Saml2MessageBinding binding) {
102+
this.binding = binding;
103+
}
104+
105+
public String getLocation() {
106+
return this.location;
107+
}
108+
109+
public void setLocation(String location) {
110+
this.location = location;
111+
}
112+
113+
public String getResponseLocation() {
114+
if (this.responseLocation == null) {
115+
return this.location;
116+
}
117+
return this.responseLocation;
118+
}
119+
120+
public void setResponseLocation(String responseLocation) {
121+
this.responseLocation = responseLocation;
122+
}
123+
124+
}
125+
126+
}

servlet/spring-boot/java/saml2/refreshable-metadata/src/main/java/example/SecurityConfiguration.java

+13
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,24 @@
1616

1717
package example;
1818

19+
import org.springframework.beans.factory.annotation.Value;
1920
import org.springframework.context.annotation.Bean;
2021
import org.springframework.context.annotation.Configuration;
2122
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
23+
import org.springframework.security.saml2.core.OpenSamlInitializationService;
24+
import org.springframework.security.saml2.provider.service.registration.AssertingPartyMetadataRepository;
25+
import org.springframework.security.saml2.provider.service.registration.OpenSaml5AssertingPartyMetadataRepository;
2226
import org.springframework.security.web.SecurityFilterChain;
2327

2428
import static org.springframework.security.config.Customizer.withDefaults;
2529

2630
@Configuration
2731
public class SecurityConfiguration {
2832

33+
static {
34+
OpenSamlInitializationService.initialize();
35+
}
36+
2937
@Bean
3038
SecurityFilterChain app(HttpSecurity http) throws Exception {
3139
// @formatter:off
@@ -39,4 +47,9 @@ SecurityFilterChain app(HttpSecurity http) throws Exception {
3947
return http.build();
4048
}
4149

50+
@Bean
51+
AssertingPartyMetadataRepository assertingParties(@Value("${saml2.ap.metadata}") String location) {
52+
return OpenSaml5AssertingPartyMetadataRepository.withTrustedMetadataLocation(location).build();
53+
}
54+
4255
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package example;
18+
19+
import java.util.Iterator;
20+
21+
import org.springframework.security.saml2.provider.service.registration.AssertingPartyMetadata;
22+
import org.springframework.security.saml2.provider.service.registration.AssertingPartyMetadataRepository;
23+
import org.springframework.security.saml2.provider.service.registration.IterableRelyingPartyRegistrationRepository;
24+
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
25+
import org.springframework.stereotype.Component;
26+
27+
@Component
28+
public class SourcedRelyingPartyRegistrationRepository implements IterableRelyingPartyRegistrationRepository {
29+
30+
private final AssertingPartyMetadataRepository assertingParties;
31+
32+
private final RelyingPartyMetadata metadata;
33+
34+
public SourcedRelyingPartyRegistrationRepository(AssertingPartyMetadataRepository assertingParties,
35+
RelyingPartyMetadata metadata) {
36+
this.assertingParties = assertingParties;
37+
this.metadata = metadata;
38+
}
39+
40+
@Override
41+
public RelyingPartyRegistration findByRegistrationId(String registrationId) {
42+
AssertingPartyMetadata metadata = this.assertingParties.findByEntityId(registrationId);
43+
return this.metadata.apply(RelyingPartyRegistration.withAssertingPartyMetadata(metadata));
44+
}
45+
46+
@Override
47+
public Iterator<RelyingPartyRegistration> iterator() {
48+
Iterator<AssertingPartyMetadata> assertingParties = this.assertingParties.iterator();
49+
RelyingPartyMetadata metadata = this.metadata;
50+
return new Iterator<>() {
51+
@Override
52+
public boolean hasNext() {
53+
return assertingParties.hasNext();
54+
}
55+
56+
@Override
57+
public RelyingPartyRegistration next() {
58+
return metadata.apply(RelyingPartyRegistration.withAssertingPartyMetadata(assertingParties.next()));
59+
}
60+
};
61+
}
62+
63+
}

servlet/spring-boot/java/saml2/refreshable-metadata/src/main/resources/application.yml

+5-15
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,11 @@ spring:
44
file: classpath:docker/compose.yml
55
readiness:
66
wait: never
7-
security:
8-
saml2:
9-
relyingparty:
10-
registration:
11-
one:
12-
entity-id: "{baseUrl}/saml2/metadata"
13-
acs.location: "{baseUrl}/login/saml2/sso"
14-
signing.credentials:
15-
- private-key-location: classpath:credentials/rp-private.key
16-
certificate-location: classpath:credentials/rp-certificate.crt
17-
singlelogout:
18-
binding: REDIRECT
19-
url: "{baseUrl}/logout/saml2/slo"
20-
assertingparty:
21-
metadata-uri: http://idp-one.7f000001.nip.io/simplesaml/saml2/idp/metadata.php
227

238
logging.level:
249
org.springframework.security: TRACE
10+
11+
saml2:
12+
certificate: classpath:credentials/rp-certificate.crt
13+
key: classpath:credentials/rp-private.key
14+
ap.metadata: http://idp-one.7f000001.nip.io/simplesaml/saml2/idp/metadata.php

0 commit comments

Comments
 (0)