Skip to content

Commit

Permalink
Polish refreshable-metadata Sample
Browse files Browse the repository at this point in the history
  • Loading branch information
jzheaux committed Nov 6, 2024
1 parent 0a7da94 commit 2e02987
Show file tree
Hide file tree
Showing 6 changed files with 208 additions and 128 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ void logoutWhenRelyingPartyInitiatedLogoutThenLoginPageWithLogoutParam() throws
}

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

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*
* Copyright 2002-2024 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 java.io.InputStream;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.io.ApplicationResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties("saml2")
public class RelyingPartyMetadata {

private final ResourceLoader resourceLoader = new ApplicationResourceLoader();

private String entityId = "{baseUrl}/saml2/metadata";

private String sso = "{baseUrl}/login/saml2/sso";

private SingleLogout slo = new SingleLogout();

private X509Certificate certificate;

private RSAPrivateKey key;

public RelyingPartyRegistration apply(RelyingPartyRegistration.Builder builder) {
Saml2X509Credential signing = Saml2X509Credential.signing(this.key, this.certificate);
return builder.entityId(this.entityId)
.assertionConsumerServiceLocation(this.sso)
.singleLogoutServiceBinding(this.slo.getBinding())
.singleLogoutServiceLocation(this.slo.getLocation())
.singleLogoutServiceResponseLocation(this.slo.getResponseLocation())
.signingX509Credentials((c) -> c.add(signing))
.build();
}

public void setEntityId(String entityId) {
this.entityId = entityId;
}

public void setSso(String sso) {
this.sso = sso;
}

public void setSlo(SingleLogout slo) {
this.slo = slo;
}

public void setCertificate(String certificate) {
Resource source = this.resourceLoader.getResource(certificate);
try (InputStream in = source.getInputStream()) {
CertificateFactory certificates = CertificateFactory.getInstance("X.509");
this.certificate = (X509Certificate) certificates.generateCertificate(in);
}
catch (CertificateException | IOException ex) {
throw new IllegalArgumentException(ex);
}
}

public void setKey(RSAPrivateKey key) {
this.key = key;
}

public static class SingleLogout {

private Saml2MessageBinding binding = Saml2MessageBinding.REDIRECT;

private String location = "{baseUrl}/logout/saml2/slo";

private String responseLocation = "{baseUrl}/logout/saml2/slo";

public Saml2MessageBinding getBinding() {
return this.binding;
}

public void setBinding(Saml2MessageBinding binding) {
this.binding = binding;
}

public String getLocation() {
return this.location;
}

public void setLocation(String location) {
this.location = location;
}

public String getResponseLocation() {
if (this.responseLocation == null) {
return this.location;
}
return this.responseLocation;
}

public void setResponseLocation(String responseLocation) {
this.responseLocation = responseLocation;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,24 @@

package example;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.saml2.core.OpenSamlInitializationService;
import org.springframework.security.saml2.provider.service.registration.AssertingPartyMetadataRepository;
import org.springframework.security.saml2.provider.service.registration.OpenSaml5AssertingPartyMetadataRepository;
import org.springframework.security.web.SecurityFilterChain;

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

@Configuration
public class SecurityConfiguration {

static {
OpenSamlInitializationService.initialize();
}

@Bean
SecurityFilterChain app(HttpSecurity http) throws Exception {
// @formatter:off
Expand All @@ -39,4 +47,9 @@ SecurityFilterChain app(HttpSecurity http) throws Exception {
return http.build();
}

@Bean
AssertingPartyMetadataRepository assertingParties(@Value("${saml2.ap.metadata}") String location) {
return OpenSaml5AssertingPartyMetadataRepository.withTrustedMetadataLocation(location).build();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* 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.util.Iterator;

import org.springframework.security.saml2.provider.service.registration.AssertingPartyMetadata;
import org.springframework.security.saml2.provider.service.registration.AssertingPartyMetadataRepository;
import org.springframework.security.saml2.provider.service.registration.IterableRelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.stereotype.Component;

@Component
public class SourcedRelyingPartyRegistrationRepository implements IterableRelyingPartyRegistrationRepository {

private final AssertingPartyMetadataRepository assertingParties;

private final RelyingPartyMetadata metadata;

public SourcedRelyingPartyRegistrationRepository(AssertingPartyMetadataRepository assertingParties,
RelyingPartyMetadata metadata) {
this.assertingParties = assertingParties;
this.metadata = metadata;
}

@Override
public RelyingPartyRegistration findByRegistrationId(String registrationId) {
AssertingPartyMetadata metadata = this.assertingParties.findByEntityId(registrationId);
return this.metadata.apply(RelyingPartyRegistration.withAssertingPartyMetadata(metadata));
}

@Override
public Iterator<RelyingPartyRegistration> iterator() {
Iterator<AssertingPartyMetadata> assertingParties = this.assertingParties.iterator();
RelyingPartyMetadata metadata = this.metadata;
return new Iterator<>() {
@Override
public boolean hasNext() {
return assertingParties.hasNext();
}

@Override
public RelyingPartyRegistration next() {
return metadata.apply(RelyingPartyRegistration.withAssertingPartyMetadata(assertingParties.next()));
}
};
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,11 @@ spring:
file: classpath:docker/compose.yml
readiness:
wait: never
security:
saml2:
relyingparty:
registration:
one:
entity-id: "{baseUrl}/saml2/metadata"
acs.location: "{baseUrl}/login/saml2/sso"
signing.credentials:
- private-key-location: classpath:credentials/rp-private.key
certificate-location: classpath:credentials/rp-certificate.crt
singlelogout:
binding: REDIRECT
url: "{baseUrl}/logout/saml2/slo"
assertingparty:
metadata-uri: http://idp-one.7f000001.nip.io/simplesaml/saml2/idp/metadata.php

logging.level:
org.springframework.security: TRACE

saml2:
certificate: classpath:credentials/rp-certificate.crt
key: classpath:credentials/rp-private.key
ap.metadata: http://idp-one.7f000001.nip.io/simplesaml/saml2/idp/metadata.php

0 comments on commit 2e02987

Please sign in to comment.