Skip to content

Commit

Permalink
Polish saml-extension-federation Configuration
Browse files Browse the repository at this point in the history
  • Loading branch information
jzheaux committed Nov 6, 2024
1 parent d058ae6 commit 0a7da94
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 75 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* 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.converter.RsaKeyConverters;
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}/saml/metadata";

private String sso = "{baseUrl}/saml/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(String key) {
Resource source = this.resourceLoader.getResource(key);
try (InputStream in = source.getInputStream()) {
this.key = RsaKeyConverters.pkcs8().convert(in);
}
catch (IOException ex) {
throw new IllegalArgumentException(ex);
}
}

public static class SingleLogout {

private Saml2MessageBinding binding = Saml2MessageBinding.REDIRECT;

private String location = "{baseUrl}/saml/logout";

private String responseLocation = "{baseUrl}/saml/SingleLogout";

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
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* 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.
Expand All @@ -16,26 +16,16 @@

package example;

import java.io.File;
import java.io.FileInputStream;
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 java.util.UUID;
import java.util.stream.Collectors;
import java.util.List;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyProperties;
import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyProperties.Registration;
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.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository;
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.web.SecurityFilterChain;

Expand All @@ -60,32 +50,13 @@ SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
}

@Bean
InMemoryRelyingPartyRegistrationRepository repository(Saml2RelyingPartyProperties properties,
@Value("classpath:credentials/rp-private.key") RSAPrivateKey key,
@Value("classpath:credentials/rp-certificate.crt") File cert) {
Saml2X509Credential signing = Saml2X509Credential.signing(key, x509Certificate(cert));
Registration registration = properties.getRegistration().values().iterator().next();
return new InMemoryRelyingPartyRegistrationRepository(RelyingPartyRegistrations
.collectionFromMetadataLocation(registration.getAssertingparty().getMetadataUri())
RelyingPartyRegistrationRepository registrations(RelyingPartyMetadata rp,
@Value("${saml2.ap.metadata}") String ap) {
List<RelyingPartyRegistration> registrations = RelyingPartyRegistrations.collectionFromMetadataLocation(ap)
.stream()
.map((builder) -> builder.registrationId(UUID.randomUUID().toString())
.entityId(registration.getEntityId())
.assertionConsumerServiceLocation(registration.getAcs().getLocation())
.singleLogoutServiceBinding(registration.getSinglelogout().getBinding())
.singleLogoutServiceLocation(registration.getSinglelogout().getUrl())
.singleLogoutServiceResponseLocation(registration.getSinglelogout().getResponseUrl())
.signingX509Credentials((credentials) -> credentials.add(signing))
.build())
.collect(Collectors.toList()));
}

X509Certificate x509Certificate(File location) {
try (InputStream source = new FileInputStream(location)) {
return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(source);
}
catch (CertificateException | IOException ex) {
throw new IllegalArgumentException(ex);
}
.map(rp::apply)
.toList();
return new InMemoryRelyingPartyRegistrationRepository(registrations);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,8 @@ spring:
security:
filter:
dispatcher-types: async, error, request, forward
saml2:
relyingparty:
registration:
metadata:
entity-id: "{baseUrl}/saml/metadata"
singlelogout:
binding: REDIRECT
url: "{baseUrl}/saml/logout"
responseUrl: "{baseUrl}/saml/SingleLogout"
acs:
location: "{baseUrl}/saml/SSO"
assertingparty.metadata-uri: http://idp-one.7f000001.nip.io/simplesaml/saml2/idp/metadata.php

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

This file was deleted.

0 comments on commit 0a7da94

Please sign in to comment.