Remove SAML Deprecations

Closes gh-11077
This commit is contained in:
Marcus Da Coregio 2022-04-08 09:33:20 -03:00 committed by Marcus Hert Da Coregio
parent 195d767d98
commit 995b2918bb
39 changed files with 157 additions and 3392 deletions

View File

@ -33,21 +33,18 @@ import org.springframework.security.config.annotation.web.configurers.CsrfConfig
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest;
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider; import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider;
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationRequestFactory;
import org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationProvider; import org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationProvider;
import org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationRequestFactory;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestFactory;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; 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.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter; import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter;
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationRequestFilter; import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationRequestFilter;
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver; import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.DefaultSaml2AuthenticationRequestContextResolver;
import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository; import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository;
import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver; import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestContextResolver;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository; import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter; import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter;
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml3AuthenticationRequestResolver;
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver; import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver;
import org.springframework.security.web.authentication.AuthenticationConverter; import org.springframework.security.web.authentication.AuthenticationConverter;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
@ -87,7 +84,6 @@ import org.springframework.util.StringUtils;
* *
* <ul> * <ul>
* <li>{@link RelyingPartyRegistrationRepository} (required)</li> * <li>{@link RelyingPartyRegistrationRepository} (required)</li>
* <li>{@link Saml2AuthenticationRequestFactory} (optional)</li>
* </ul> * </ul>
* *
* <h2>Shared Objects Used</h2> * <h2>Shared Objects Used</h2>
@ -96,7 +92,6 @@ import org.springframework.util.StringUtils;
* *
* <ul> * <ul>
* <li>{@link RelyingPartyRegistrationRepository} (required)</li> * <li>{@link RelyingPartyRegistrationRepository} (required)</li>
* <li>{@link Saml2AuthenticationRequestFactory} (optional)</li>
* <li>{@link DefaultLoginPageGeneratingFilter} - if {@link #loginPage(String)} is not * <li>{@link DefaultLoginPageGeneratingFilter} - if {@link #loginPage(String)} is not
* configured and {@code DefaultLoginPageGeneratingFilter} is available, than a default * configured and {@code DefaultLoginPageGeneratingFilter} is available, than a default
* login page will be made available</li> * login page will be made available</li>
@ -300,42 +295,21 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
private Saml2WebSsoAuthenticationRequestFilter getAuthenticationRequestFilter(B http) { private Saml2WebSsoAuthenticationRequestFilter getAuthenticationRequestFilter(B http) {
Saml2AuthenticationRequestResolver authenticationRequestResolver = getAuthenticationRequestResolver(http); Saml2AuthenticationRequestResolver authenticationRequestResolver = getAuthenticationRequestResolver(http);
if (authenticationRequestResolver != null) { return new Saml2WebSsoAuthenticationRequestFilter(authenticationRequestResolver);
return new Saml2WebSsoAuthenticationRequestFilter(authenticationRequestResolver);
}
return new Saml2WebSsoAuthenticationRequestFilter(getAuthenticationRequestContextResolver(http),
getAuthenticationRequestFactory(http));
} }
private Saml2AuthenticationRequestResolver getAuthenticationRequestResolver(B http) { private Saml2AuthenticationRequestResolver getAuthenticationRequestResolver(B http) {
if (this.authenticationRequestResolver != null) { if (this.authenticationRequestResolver != null) {
return this.authenticationRequestResolver; return this.authenticationRequestResolver;
} }
return getBeanOrNull(http, Saml2AuthenticationRequestResolver.class); Saml2AuthenticationRequestResolver bean = getBeanOrNull(http, Saml2AuthenticationRequestResolver.class);
} if (bean != null) {
return bean;
private Saml2AuthenticationRequestFactory getAuthenticationRequestFactory(B http) {
Saml2AuthenticationRequestFactory resolver = getSharedOrBean(http, Saml2AuthenticationRequestFactory.class);
if (resolver != null) {
return resolver;
} }
if (version().startsWith("4")) { if (version().startsWith("4")) {
return new OpenSaml4AuthenticationRequestFactory(); return new OpenSaml4AuthenticationRequestResolver(relyingPartyRegistrationResolver(http));
} }
else { return new OpenSaml3AuthenticationRequestResolver(relyingPartyRegistrationResolver(http));
return new OpenSamlAuthenticationRequestFactory();
}
}
private Saml2AuthenticationRequestContextResolver getAuthenticationRequestContextResolver(B http) {
Saml2AuthenticationRequestContextResolver resolver = getBeanOrNull(http,
Saml2AuthenticationRequestContextResolver.class);
if (resolver != null) {
return resolver;
}
RelyingPartyRegistrationResolver registrationResolver = new DefaultRelyingPartyRegistrationResolver(
this.relyingPartyRegistrationRepository);
return new DefaultSaml2AuthenticationRequestContextResolver(registrationResolver);
} }
private AuthenticationConverter getAuthenticationConverter(B http) { private AuthenticationConverter getAuthenticationConverter(B http) {
@ -348,8 +322,7 @@ public final class Saml2LoginConfigurer<B extends HttpSecurityBuilder<B>>
Assert.state(this.loginProcessingUrl.contains("{registrationId}"), Assert.state(this.loginProcessingUrl.contains("{registrationId}"),
"loginProcessingUrl must contain {registrationId} path variable"); "loginProcessingUrl must contain {registrationId} path variable");
return new Saml2AuthenticationTokenConverter( return new Saml2AuthenticationTokenConverter(
(RelyingPartyRegistrationResolver) new DefaultRelyingPartyRegistrationResolver( new DefaultRelyingPartyRegistrationResolver(this.relyingPartyRegistrationRepository));
this.relyingPartyRegistrationRepository));
} }
return authenticationConverterBean; return authenticationConverterBean;
} }

View File

@ -19,7 +19,6 @@ package org.springframework.security.config.annotation.web.configurers.saml2;
import java.io.IOException; import java.io.IOException;
import java.net.URLDecoder; import java.net.URLDecoder;
import java.time.Duration; import java.time.Duration;
import java.time.Instant;
import java.util.Base64; import java.util.Base64;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -34,7 +33,6 @@ import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
import org.opensaml.saml.saml2.core.Assertion; import org.opensaml.saml.saml2.core.Assertion;
import org.opensaml.saml.saml2.core.AuthnRequest;
import org.springframework.beans.factory.BeanCreationException; import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -68,23 +66,17 @@ import org.springframework.security.saml2.core.Saml2Utils;
import org.springframework.security.saml2.core.TestSaml2X509Credentials; import org.springframework.security.saml2.core.TestSaml2X509Credentials;
import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest;
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider; import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationProvider;
import org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationRequestFactory;
import org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationProvider; import org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationProvider;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal;
import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication; import org.springframework.security.saml2.provider.service.authentication.Saml2Authentication;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestContext;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestFactory;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken;
import org.springframework.security.saml2.provider.service.authentication.TestOpenSamlObjects;
import org.springframework.security.saml2.provider.service.authentication.TestSaml2AuthenticationRequestContexts;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; 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.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations; import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter; import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter;
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver; import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver; import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestContextResolver;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository; import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter; import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter;
import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver; import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver;
@ -113,7 +105,6 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.config.Customizer.withDefaults;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
@ -211,30 +202,6 @@ public class Saml2LoginConfigurerTests {
validateSaml2WebSsoAuthenticationFilterConfiguration(); validateSaml2WebSsoAuthenticationFilterConfiguration();
} }
@Test
public void saml2LoginWhenCustomAuthenticationRequestContextResolverThenUses() throws Exception {
this.spring.register(CustomAuthenticationRequestContextResolver.class).autowire();
Saml2AuthenticationRequestContext context = TestSaml2AuthenticationRequestContexts
.authenticationRequestContext().build();
Saml2AuthenticationRequestContextResolver resolver = this.spring.getContext()
.getBean(Saml2AuthenticationRequestContextResolver.class);
given(resolver.resolve(any(HttpServletRequest.class))).willReturn(context);
this.mvc.perform(get("/saml2/authenticate/registration-id")).andExpect(status().isFound());
verify(resolver).resolve(any(HttpServletRequest.class));
}
@Test
public void authenticationRequestWhenAuthnRequestContextConverterThenUses() throws Exception {
this.spring.register(CustomAuthenticationRequestContextConverterResolver.class).autowire();
MvcResult result = this.mvc.perform(get("/saml2/authenticate/registration-id")).andReturn();
UriComponents components = UriComponentsBuilder.fromHttpUrl(result.getResponse().getRedirectedUrl()).build();
String samlRequest = components.getQueryParams().getFirst("SAMLRequest");
String decoded = URLDecoder.decode(samlRequest, "UTF-8");
String inflated = Saml2Utils.samlInflate(Saml2Utils.samlDecode(decoded));
assertThat(inflated).contains("ForceAuthn=\"true\"");
}
@Test @Test
public void authenticationRequestWhenAuthenticationRequestResolverBeanThenUses() throws Exception { public void authenticationRequestWhenAuthenticationRequestResolverBeanThenUses() throws Exception {
this.spring.register(CustomAuthenticationRequestResolverBean.class).autowire(); this.spring.register(CustomAuthenticationRequestResolverBean.class).autowire();
@ -257,19 +224,6 @@ public class Saml2LoginConfigurerTests {
assertThat(inflated).contains("ForceAuthn=\"true\""); assertThat(inflated).contains("ForceAuthn=\"true\"");
} }
@Test
public void authenticationRequestWhenAuthenticationRequestResolverAndFactoryThenResolverTakesPrecedence()
throws Exception {
this.spring.register(CustomAuthenticationRequestResolverPrecedence.class).autowire();
MvcResult result = this.mvc.perform(get("/saml2/authenticate/registration-id")).andReturn();
UriComponents components = UriComponentsBuilder.fromHttpUrl(result.getResponse().getRedirectedUrl()).build();
String samlRequest = components.getQueryParams().getFirst("SAMLRequest");
String decoded = URLDecoder.decode(samlRequest, "UTF-8");
String inflated = Saml2Utils.samlInflate(Saml2Utils.samlDecode(decoded));
assertThat(inflated).contains("ForceAuthn=\"true\"");
verifyNoInteractions(this.spring.getContext().getBean(Saml2AuthenticationRequestFactory.class));
}
@Test @Test
public void authenticateWhenCustomAuthenticationConverterThenUses() throws Exception { public void authenticateWhenCustomAuthenticationConverterThenUses() throws Exception {
this.spring.register(CustomAuthenticationConverter.class).autowire(); this.spring.register(CustomAuthenticationConverter.class).autowire();
@ -513,61 +467,6 @@ public class Saml2LoginConfigurerTests {
} }
@EnableWebSecurity
@Import(Saml2LoginConfigBeans.class)
static class CustomAuthenticationRequestContextResolver extends WebSecurityConfigurerAdapter {
private final Saml2AuthenticationRequestContextResolver resolver = mock(
Saml2AuthenticationRequestContextResolver.class);
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests((authz) -> authz
.anyRequest().authenticated()
)
.saml2Login(withDefaults());
// @formatter:on
}
@Bean
Saml2AuthenticationRequestContextResolver resolver() {
return this.resolver;
}
}
@EnableWebSecurity
@Import(Saml2LoginConfigBeans.class)
static class CustomAuthenticationRequestContextConverterResolver extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests((authz) -> authz
.anyRequest().authenticated()
)
.saml2Login((saml2) -> {
});
// @formatter:on
}
@Bean
Saml2AuthenticationRequestFactory authenticationRequestFactory() {
OpenSaml4AuthenticationRequestFactory authenticationRequestFactory = new OpenSaml4AuthenticationRequestFactory();
authenticationRequestFactory.setAuthenticationRequestContextConverter((context) -> {
AuthnRequest authnRequest = TestOpenSamlObjects.authnRequest();
authnRequest.setIssueInstant(Instant.now());
authnRequest.setForceAuthn(true);
return authnRequest;
});
return authenticationRequestFactory;
}
}
@EnableWebSecurity @EnableWebSecurity
@Import(Saml2LoginConfigBeans.class) @Import(Saml2LoginConfigBeans.class)
static class CustomAuthenticationRequestResolverBean { static class CustomAuthenticationRequestResolverBean {
@ -630,41 +529,6 @@ public class Saml2LoginConfigurerTests {
} }
@EnableWebSecurity
@Import(Saml2LoginConfigBeans.class)
static class CustomAuthenticationRequestResolverPrecedence {
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
// @formatter:off
http
.authorizeRequests((authz) -> authz
.anyRequest().authenticated()
)
.saml2Login(Customizer.withDefaults());
// @formatter:on
return http.build();
}
@Bean
Saml2AuthenticationRequestFactory authenticationRequestFactory() {
return mock(Saml2AuthenticationRequestFactory.class);
}
@Bean
Saml2AuthenticationRequestResolver authenticationRequestResolver(
RelyingPartyRegistrationRepository registrations) {
RelyingPartyRegistrationResolver registrationResolver = new DefaultRelyingPartyRegistrationResolver(
registrations);
OpenSaml4AuthenticationRequestResolver delegate = new OpenSaml4AuthenticationRequestResolver(
registrationResolver);
delegate.setAuthnRequestCustomizer((parameters) -> parameters.getAuthnRequest().setForceAuthn(true));
return delegate;
}
}
@EnableWebSecurity @EnableWebSecurity
@Import(Saml2LoginConfigBeans.class) @Import(Saml2LoginConfigBeans.class)
static class CustomAuthenticationConverter extends WebSecurityConfigurerAdapter { static class CustomAuthenticationConverter extends WebSecurityConfigurerAdapter {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -23,8 +23,7 @@ import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate; import java.security.cert.X509Certificate;
import org.springframework.security.converter.RsaKeyConverters; import org.springframework.security.converter.RsaKeyConverters;
import org.springframework.security.saml2.credentials.Saml2X509Credential; import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType;
/** /**
* Preconfigured SAML credentials for SAML integration tests. * Preconfigured SAML credentials for SAML integration tests.
@ -61,7 +60,8 @@ public final class TestSaml2Credentials {
+ "lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk\n" + "lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk\n"
+ "-----END CERTIFICATE-----"; + "-----END CERTIFICATE-----";
// @formatter:on // @formatter:on
return new Saml2X509Credential(x509Certificate(certificate), Saml2X509CredentialType.VERIFICATION); return new Saml2X509Credential(x509Certificate(certificate),
Saml2X509Credential.Saml2X509CredentialType.VERIFICATION);
} }
static X509Certificate x509Certificate(String source) { static X509Certificate x509Certificate(String source) {
@ -114,7 +114,8 @@ public final class TestSaml2Credentials {
// @formatter:on // @formatter:on
PrivateKey pk = RsaKeyConverters.pkcs8().convert(new ByteArrayInputStream(key.getBytes())); PrivateKey pk = RsaKeyConverters.pkcs8().convert(new ByteArrayInputStream(key.getBytes()));
X509Certificate cert = x509Certificate(certificate); X509Certificate cert = x509Certificate(certificate);
return new Saml2X509Credential(pk, cert, Saml2X509CredentialType.SIGNING, Saml2X509CredentialType.DECRYPTION); return new Saml2X509Credential(pk, cert, Saml2X509Credential.Saml2X509CredentialType.SIGNING,
Saml2X509Credential.Saml2X509CredentialType.DECRYPTION);
} }
} }

View File

@ -40,7 +40,6 @@ import org.springframework.security.saml2.provider.service.authentication.Saml2A
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationToken;
import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest;
import org.springframework.security.saml2.provider.service.authentication.TestSaml2AuthenticationRequestContexts;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; 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.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations; import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
@ -231,8 +230,7 @@ public class Saml2LoginBeanDefinitionParserTests {
.configLocations(this.xml("WithCustomRelyingPartyRepository-WithCustomAuthenticationRequestResolver")) .configLocations(this.xml("WithCustomRelyingPartyRepository-WithCustomAuthenticationRequestResolver"))
.autowire(); .autowire();
Saml2RedirectAuthenticationRequest request = Saml2RedirectAuthenticationRequest Saml2RedirectAuthenticationRequest request = Saml2RedirectAuthenticationRequest
.withAuthenticationRequestContext( .withRelyingPartyRegistration(TestRelyingPartyRegistrations.noCredentials().build())
TestSaml2AuthenticationRequestContexts.authenticationRequestContext().build())
.samlRequest("request").authenticationRequestUri(IDP_SSO_URL).build(); .samlRequest("request").authenticationRequestUri(IDP_SSO_URL).build();
given(this.authenticationRequestResolver.resolve(any(HttpServletRequest.class))).willReturn(request); given(this.authenticationRequestResolver.resolve(any(HttpServletRequest.class))).willReturn(request);
this.mvc.perform(get("/saml2/authenticate/registration-id")).andExpect(status().isFound()); this.mvc.perform(get("/saml2/authenticate/registration-id")).andExpect(status().isFound());

View File

@ -34,8 +34,7 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.test.SpringTestContext import org.springframework.security.config.test.SpringTestContext
import org.springframework.security.config.test.SpringTestContextExtension import org.springframework.security.config.test.SpringTestContextExtension
import org.springframework.security.saml2.credentials.Saml2X509Credential import org.springframework.security.saml2.core.Saml2X509Credential
import org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.VERIFICATION
import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository 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.RelyingPartyRegistration
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository
@ -101,10 +100,14 @@ class Saml2DslTests {
relyingPartyRegistrationRepository = relyingPartyRegistrationRepository =
InMemoryRelyingPartyRegistrationRepository( InMemoryRelyingPartyRegistrationRepository(
RelyingPartyRegistration.withRegistrationId("samlId") RelyingPartyRegistration.withRegistrationId("samlId")
.assertionConsumerServiceUrlTemplate("{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI) .assertionConsumerServiceLocation("{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI)
.credentials { c -> c.add(Saml2X509Credential(loadCert("rod.cer"), VERIFICATION)) } .assertingPartyDetails { a -> a
.providerDetails { c -> c.webSsoUrl("ssoUrl") } .verificationX509Credentials { c -> c
.providerDetails { c -> c.entityId("entityId") } .add(Saml2X509Credential(loadCert("rod.cer"), Saml2X509Credential.Saml2X509CredentialType.VERIFICATION))
}
}
.assertingPartyDetails { c -> c.singleSignOnServiceLocation("ssoUrl") }
.assertingPartyDetails { c -> c.entityId("entityId") }
.build() .build()
) )
} }

View File

@ -1,208 +0,0 @@
/*
* Copyright 2002-2020 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 org.springframework.security.saml2.credentials;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
import org.springframework.util.Assert;
/**
* Saml2X509Credential is meant to hold an X509 certificate, or an X509 certificate and a
* private key. Per:
* https://www.oasis-open.org/committees/download.php/8958/sstc-saml-implementation-guidelines-draft-01.pdf
* Line: 584, Section 4.3 Credentials Used for both signing, signature verification and
* encryption/decryption
*
* @since 5.2
* @deprecated Use {@link org.springframework.security.saml2.core.Saml2X509Credential}
* instead
*/
@Deprecated
public class Saml2X509Credential {
private final PrivateKey privateKey;
private final X509Certificate certificate;
private final Set<Saml2X509CredentialType> credentialTypes;
/**
* Creates a Saml2X509Credentials representing Identity Provider credentials for
* verification, encryption or both.
* @param certificate an IDP X509Certificate, cannot be null
* @param types credential types, must be one of
* {@link Saml2X509CredentialType#VERIFICATION} or
* {@link Saml2X509CredentialType#ENCRYPTION} or both.
*/
public Saml2X509Credential(X509Certificate certificate, Saml2X509CredentialType... types) {
this(null, false, certificate, types);
validateUsages(types, Saml2X509CredentialType.VERIFICATION, Saml2X509CredentialType.ENCRYPTION);
}
/**
* Creates a Saml2X509Credentials representing Service Provider credentials for
* signing, decryption or both.
* @param privateKey a private key used for signing or decryption, cannot be null
* @param certificate an SP X509Certificate shared with identity providers, cannot be
* null
* @param types credential types, must be one of
* {@link Saml2X509CredentialType#SIGNING} or
* {@link Saml2X509CredentialType#DECRYPTION} or both.
*/
public Saml2X509Credential(PrivateKey privateKey, X509Certificate certificate, Saml2X509CredentialType... types) {
this(privateKey, true, certificate, types);
validateUsages(types, Saml2X509CredentialType.SIGNING, Saml2X509CredentialType.DECRYPTION);
}
public Saml2X509Credential(PrivateKey privateKey, X509Certificate certificate, Set<Saml2X509CredentialType> types) {
Assert.notNull(certificate, "certificate cannot be null");
Assert.notEmpty(types, "credentialTypes cannot be empty");
this.privateKey = privateKey;
this.certificate = certificate;
this.credentialTypes = types;
}
private Saml2X509Credential(PrivateKey privateKey, boolean keyRequired, X509Certificate certificate,
Saml2X509CredentialType... types) {
Assert.notNull(certificate, "certificate cannot be null");
Assert.notEmpty(types, "credentials types cannot be empty");
if (keyRequired) {
Assert.notNull(privateKey, "privateKey cannot be null");
}
this.privateKey = privateKey;
this.certificate = certificate;
this.credentialTypes = new LinkedHashSet<>(Arrays.asList(types));
}
/**
* Returns true if the credential has a private key and can be used for signing, the
* types will contain {@link Saml2X509CredentialType#SIGNING}.
* @return true if the credential is a {@link Saml2X509CredentialType#SIGNING} type
*/
public boolean isSigningCredential() {
return getCredentialTypes().contains(Saml2X509CredentialType.SIGNING);
}
/**
* Returns true if the credential has a private key and can be used for decryption,
* the types will contain {@link Saml2X509CredentialType#DECRYPTION}.
* @return true if the credential is a {@link Saml2X509CredentialType#DECRYPTION} type
*/
public boolean isDecryptionCredential() {
return getCredentialTypes().contains(Saml2X509CredentialType.DECRYPTION);
}
/**
* Returns true if the credential has a certificate and can be used for signature
* verification, the types will contain {@link Saml2X509CredentialType#VERIFICATION}.
* @return true if the credential is a {@link Saml2X509CredentialType#VERIFICATION}
* type
*/
public boolean isSignatureVerficationCredential() {
return getCredentialTypes().contains(Saml2X509CredentialType.VERIFICATION);
}
/**
* Returns true if the credential has a certificate and can be used for signature
* verification, the types will contain {@link Saml2X509CredentialType#VERIFICATION}.
* @return true if the credential is a {@link Saml2X509CredentialType#VERIFICATION}
* type
*/
public boolean isEncryptionCredential() {
return getCredentialTypes().contains(Saml2X509CredentialType.ENCRYPTION);
}
/**
* Returns the credential types for this credential.
* @return a set of credential types/usages that this credential can be used for
*/
protected Set<Saml2X509CredentialType> getCredentialTypes() {
return this.credentialTypes;
}
/**
* Returns the private key, or null if this credential type doesn't require one.
* @return the private key, or null
* @see #Saml2X509Credential(PrivateKey, X509Certificate, Saml2X509CredentialType...)
*/
public PrivateKey getPrivateKey() {
return this.privateKey;
}
/**
* Returns the X509 certificate for ths credential. Cannot be null
* @return the X509 certificate
*/
public X509Certificate getCertificate() {
return this.certificate;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Saml2X509Credential that = (Saml2X509Credential) o;
return Objects.equals(this.privateKey, that.privateKey) && this.certificate.equals(that.certificate)
&& this.credentialTypes.equals(that.credentialTypes);
}
@Override
public int hashCode() {
return Objects.hash(this.privateKey, this.certificate, this.credentialTypes);
}
private void validateUsages(Saml2X509CredentialType[] usages, Saml2X509CredentialType... validUsages) {
for (Saml2X509CredentialType usage : usages) {
boolean valid = false;
for (Saml2X509CredentialType validUsage : validUsages) {
if (usage == validUsage) {
valid = true;
break;
}
}
Assert.state(valid, () -> usage + " is not a valid usage for this credential");
}
}
/**
* @deprecated Use
* {@link org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType}
* instead
*/
@Deprecated
public enum Saml2X509CredentialType {
VERIFICATION,
ENCRYPTION,
SIGNING,
DECRYPTION,
}
}

View File

@ -33,8 +33,8 @@ import org.springframework.util.Assert;
* (line 2031) * (line 2031)
* *
* @since 5.3 * @since 5.3
* @see Saml2AuthenticationRequestFactory#createPostAuthenticationRequest(Saml2AuthenticationRequestContext) * @see Saml2PostAuthenticationRequest
* @see Saml2AuthenticationRequestFactory#createRedirectAuthenticationRequest(Saml2AuthenticationRequestContext) * @see Saml2RedirectAuthenticationRequest
*/ */
public abstract class AbstractSaml2AuthenticationRequest implements Serializable { public abstract class AbstractSaml2AuthenticationRequest implements Serializable {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -80,69 +80,6 @@ public class Saml2AuthenticationException extends AuthenticationException {
this.error = error; this.error = error;
} }
/**
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
* @param error the
* {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error
* SAML 2.0 Error}
* @deprecated Use
* {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error}
* constructor instead
*/
@Deprecated
public Saml2AuthenticationException(
org.springframework.security.saml2.provider.service.authentication.Saml2Error error) {
this(error, error.getDescription());
}
/**
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
* @param error the
* {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error
* SAML 2.0 Error}
* @param cause the root cause
* @deprecated Use
* {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error}
* constructor instead
*/
@Deprecated
public Saml2AuthenticationException(
org.springframework.security.saml2.provider.service.authentication.Saml2Error error, Throwable cause) {
this(error, cause.getMessage(), cause);
}
/**
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
* @param error the {@link Saml2Error SAML 2.0 Error}
* @param message the detail message
* @deprecated Use {@link Saml2Error} constructor instead
*/
@Deprecated
public Saml2AuthenticationException(
org.springframework.security.saml2.provider.service.authentication.Saml2Error error, String message) {
this(error, message, null);
}
/**
* Constructs a {@code Saml2AuthenticationException} using the provided parameters.
* @param error the
* {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error
* SAML 2.0 Error}
* @param message the detail message
* @param cause the root cause
* @deprecated Use
* {@link org.springframework.security.saml2.provider.service.authentication.Saml2Error}
* constructor instead
*/
@Deprecated
public Saml2AuthenticationException(
org.springframework.security.saml2.provider.service.authentication.Saml2Error error, String message,
Throwable cause) {
super(message, cause);
Assert.notNull(error, "error cannot be null");
this.error = new Saml2Error(error.getErrorCode(), error.getDescription());
}
/** /**
* Get the associated {@link Saml2Error} * Get the associated {@link Saml2Error}
* @return the associated {@link Saml2Error} * @return the associated {@link Saml2Error}
@ -151,17 +88,6 @@ public class Saml2AuthenticationException extends AuthenticationException {
return this.error; return this.error;
} }
/**
* Returns the {@link Saml2Error SAML 2.0 Error}.
* @return the {@link Saml2Error}
* @deprecated Use {@link #getSaml2Error()} instead
*/
@Deprecated
public org.springframework.security.saml2.provider.service.authentication.Saml2Error getError() {
return new org.springframework.security.saml2.provider.service.authentication.Saml2Error(
this.error.getErrorCode(), this.error.getDescription());
}
@Override @Override
public String toString() { public String toString() {
final StringBuffer sb = new StringBuffer("Saml2AuthenticationException{"); final StringBuffer sb = new StringBuffer("Saml2AuthenticationException{");

View File

@ -1,199 +0,0 @@
/*
* Copyright 2002-2020 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 org.springframework.security.saml2.provider.service.authentication;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Consumer;
import org.springframework.security.saml2.credentials.Saml2X509Credential;
import org.springframework.util.Assert;
/**
* Data holder for information required to send an {@code AuthNRequest} from the service
* provider to the identity provider
* https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf
* (line 2031)
*
* @since 5.2
* @deprecated use {@link Saml2AuthenticationRequestContext}
*/
@Deprecated
public final class Saml2AuthenticationRequest {
private final String issuer;
private final List<Saml2X509Credential> credentials;
private final String destination;
private final String assertionConsumerServiceUrl;
private Saml2AuthenticationRequest(String issuer, String destination, String assertionConsumerServiceUrl,
List<Saml2X509Credential> credentials) {
Assert.hasText(issuer, "issuer cannot be null");
Assert.hasText(destination, "destination cannot be null");
Assert.hasText(assertionConsumerServiceUrl, "spAssertionConsumerServiceUrl cannot be null");
this.issuer = issuer;
this.destination = destination;
this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
this.credentials = new LinkedList<>();
for (Saml2X509Credential c : credentials) {
if (c.isSigningCredential()) {
this.credentials.add(c);
}
}
}
/**
* returns the issuer, the local SP entity ID, for this authentication request. This
* property should be used to populate the {@code AuthNRequest.Issuer} XML element.
* This value typically is a URI, but can be an arbitrary string.
* @return issuer
*/
public String getIssuer() {
return this.issuer;
}
/**
* returns the destination, the WEB Single Sign On URI, for this authentication
* request. This property populates the {@code AuthNRequest#Destination} XML
* attribute.
* @return destination
*/
public String getDestination() {
return this.destination;
}
/**
* Returns the desired {@code AssertionConsumerServiceUrl} that this SP wishes to
* receive the assertion on. The IDP may or may not honor this request. This property
* populates the {@code AuthNRequest#AssertionConsumerServiceURL} XML attribute.
* @return the AssertionConsumerServiceURL value
*/
public String getAssertionConsumerServiceUrl() {
return this.assertionConsumerServiceUrl;
}
/**
* Returns a list of credentials that can be used to sign the {@code AuthNRequest}
* object
* @return signing credentials
*/
public List<Saml2X509Credential> getCredentials() {
return this.credentials;
}
/**
* A builder for {@link Saml2AuthenticationRequest}.
* @return a {@link Builder} for constructing a {@link Saml2AuthenticationRequest}
*/
public static Builder builder() {
return new Builder();
}
/**
* A builder for {@link Saml2AuthenticationRequest}.
* @param context a context object to copy values from. returns a builder object
* @return a {@link Builder} for constructing a {@link Saml2AuthenticationRequest}
*/
public static Builder withAuthenticationRequestContext(Saml2AuthenticationRequestContext context) {
return new Builder().assertionConsumerServiceUrl(context.getAssertionConsumerServiceUrl())
.issuer(context.getIssuer()).destination(context.getDestination())
.credentials((c) -> c.addAll(context.getRelyingPartyRegistration().getCredentials()));
}
/**
* A builder for {@link Saml2AuthenticationRequest}.
*/
public static final class Builder {
private String issuer;
private List<Saml2X509Credential> credentials = new LinkedList<>();
private String destination;
private String assertionConsumerServiceUrl;
private Builder() {
}
/**
* Sets the issuer for the authentication request.
* @param issuer - a required value
* @return this {@code Builder}
*/
public Builder issuer(String issuer) {
this.issuer = issuer;
return this;
}
/**
* Modifies the collection of {@link Saml2X509Credential} credentials used in
* communication between IDP and SP, specifically signing the authentication
* request. For example: <code>
* Saml2X509Credential credential = ...;
* return Saml2AuthenticationRequest.withLocalSpEntityId("id")
* .credentials((c) -&gt; c.add(credential))
* ...
* .build();
* </code>
* @param credentials - a consumer that can modify the collection of credentials
* @return this object
*/
public Builder credentials(Consumer<Collection<Saml2X509Credential>> credentials) {
credentials.accept(this.credentials);
return this;
}
/**
* Sets the Destination for the authentication request. Typically the
* {@code Service Provider EntityID}
* @param destination - a required value
* @return this {@code Builder}
*/
public Builder destination(String destination) {
this.destination = destination;
return this;
}
/**
* Sets the {@code assertionConsumerServiceURL} for the authentication request.
* Typically the {@code Service Provider EntityID}
* @param assertionConsumerServiceUrl - a required value
* @return this {@code Builder}
*/
public Builder assertionConsumerServiceUrl(String assertionConsumerServiceUrl) {
this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
return this;
}
/**
* Creates a {@link Saml2AuthenticationRequest} object.
* @return the Saml2AuthenticationRequest object
* @throws IllegalArgumentException if a required property is not set
*/
public Saml2AuthenticationRequest build() {
return new Saml2AuthenticationRequest(this.issuer, this.destination, this.assertionConsumerServiceUrl,
this.credentials);
}
}
}

View File

@ -1,183 +0,0 @@
/*
* Copyright 2002-2022 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 org.springframework.security.saml2.provider.service.authentication;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.util.Assert;
/**
* Data holder for information required to create an {@code AuthNRequest} to be sent from
* the service provider to the identity provider <a href=
* "https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf">
* Assertions and Protocols for SAML 2 (line 2031)</a>
*
* @since 5.3
* @see Saml2AuthenticationRequestFactory#createPostAuthenticationRequest(Saml2AuthenticationRequestContext)
* @see Saml2AuthenticationRequestFactory#createRedirectAuthenticationRequest(Saml2AuthenticationRequestContext)
* @deprecated Use
* {@link org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver}
* instead
*/
@Deprecated
public class Saml2AuthenticationRequestContext {
private final RelyingPartyRegistration relyingPartyRegistration;
private final String issuer;
private final String assertionConsumerServiceUrl;
private final String relayState;
protected Saml2AuthenticationRequestContext(RelyingPartyRegistration relyingPartyRegistration, String issuer,
String assertionConsumerServiceUrl, String relayState) {
Assert.hasText(issuer, "issuer cannot be null or empty");
Assert.notNull(relyingPartyRegistration, "relyingPartyRegistration cannot be null");
Assert.hasText(assertionConsumerServiceUrl, "spAssertionConsumerServiceUrl cannot be null or empty");
this.issuer = issuer;
this.relyingPartyRegistration = relyingPartyRegistration;
this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
this.relayState = relayState;
}
/**
* Returns the {@link RelyingPartyRegistration} configuration for which the
* AuthNRequest is intended for.
* @return the {@link RelyingPartyRegistration} configuration
*/
public RelyingPartyRegistration getRelyingPartyRegistration() {
return this.relyingPartyRegistration;
}
/**
* Returns the {@code Issuer} value to be used in the {@code AuthNRequest} object.
* This property should be used to populate the {@code AuthNRequest.Issuer} XML
* element. This value typically is a URI, but can be an arbitrary string.
* @return the Issuer value
*/
public String getIssuer() {
return this.issuer;
}
/**
* Returns the desired {@code AssertionConsumerServiceUrl} that this SP wishes to
* receive the assertion on. The IDP may or may not honor this request. This property
* populates the {@code AuthNRequest.AssertionConsumerServiceURL} XML attribute.
* @return the AssertionConsumerServiceURL value
*/
public String getAssertionConsumerServiceUrl() {
return this.assertionConsumerServiceUrl;
}
/**
* Returns the RelayState value, if present in the parameters
* @return the RelayState value, or null if not available
*/
public String getRelayState() {
return this.relayState;
}
/**
* Returns the {@code Destination}, the WEB Single Sign On URI, for this
* authentication request. This property can also populate the
* {@code AuthNRequest.Destination} XML attribute.
* @return the Destination value
*/
public String getDestination() {
return this.getRelyingPartyRegistration().getAssertingPartyDetails().getSingleSignOnServiceLocation();
}
/**
* A builder for {@link Saml2AuthenticationRequestContext}.
* @return a builder object
*/
public static Builder builder() {
return new Builder();
}
/**
* A builder for {@link Saml2AuthenticationRequestContext}.
*/
public static final class Builder {
private String issuer;
private String assertionConsumerServiceUrl;
private String relayState;
private RelyingPartyRegistration relyingPartyRegistration;
private Builder() {
}
/**
* Sets the issuer for the authentication request.
* @param issuer - a required value
* @return this {@code Builder}
*/
public Builder issuer(String issuer) {
this.issuer = issuer;
return this;
}
/**
* Sets the {@link RelyingPartyRegistration} used to build the authentication
* request.
* @param relyingPartyRegistration - a required value
* @return this {@code Builder}
*/
public Builder relyingPartyRegistration(RelyingPartyRegistration relyingPartyRegistration) {
this.relyingPartyRegistration = relyingPartyRegistration;
return this;
}
/**
* Sets the {@code assertionConsumerServiceURL} for the authentication request.
* Typically the {@code Service Provider EntityID}
* @param assertionConsumerServiceUrl - a required value
* @return this {@code Builder}
*/
public Builder assertionConsumerServiceUrl(String assertionConsumerServiceUrl) {
this.assertionConsumerServiceUrl = assertionConsumerServiceUrl;
return this;
}
/**
* Sets the {@code RelayState} parameter that will accompany this AuthNRequest
* @param relayState the relay state value, unencoded. if null or empty, the
* parameter will be removed from the map.
* @return this object
*/
public Builder relayState(String relayState) {
this.relayState = relayState;
return this;
}
/**
* Creates a {@link Saml2AuthenticationRequestContext} object.
* @return the Saml2AuthenticationRequest object
* @throws IllegalArgumentException if a required property is not set
*/
public Saml2AuthenticationRequestContext build() {
return new Saml2AuthenticationRequestContext(this.relyingPartyRegistration, this.issuer,
this.assertionConsumerServiceUrl, this.relayState);
}
}
}

View File

@ -1,120 +0,0 @@
/*
* Copyright 2002-2020 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 org.springframework.security.saml2.provider.service.authentication;
import java.nio.charset.StandardCharsets;
import org.springframework.security.saml2.Saml2Exception;
import org.springframework.security.saml2.core.Saml2X509Credential.Saml2X509CredentialType;
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
/**
* Component that generates AuthenticationRequest, <code>samlp:AuthnRequestType</code>
* XML, and accompanying signature data. as defined by
* https://www.oasis-open.org/committees/download.php/35711/sstc-saml-core-errata-2.0-wd-06-diff.pdf
* Page 50, Line 2147
*
* @since 5.2
* @deprecated As of 5.7.0, use
* {@link org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver}
* instead
*/
@Deprecated
public interface Saml2AuthenticationRequestFactory {
/**
* Creates an authentication request from the Service Provider, sp, to the Identity
* Provider, idp. The authentication result is an XML string that may be signed,
* encrypted, both or neither. This method only returns the {@code SAMLRequest} string
* for the request, and for a complete set of data parameters please use
* {@link #createRedirectAuthenticationRequest(Saml2AuthenticationRequestContext)} or
* {@link #createPostAuthenticationRequest(Saml2AuthenticationRequestContext)}
* @param request information about the identity provider, the recipient of this
* authentication request and accompanying data
* @return XML data in the format of a String. This data may be signed, encrypted,
* both signed and encrypted with the signature embedded in the XML or neither signed
* and encrypted
* @throws Saml2Exception when a SAML library exception occurs
* @since 5.2
* @deprecated please use
* {@link #createRedirectAuthenticationRequest(Saml2AuthenticationRequestContext)} or
* {@link #createPostAuthenticationRequest(Saml2AuthenticationRequestContext)} This
* method will be removed in future versions of Spring Security
*/
@Deprecated
String createAuthenticationRequest(Saml2AuthenticationRequest request);
/**
* Creates all the necessary AuthNRequest parameters for a REDIRECT binding. If the
* {@link Saml2AuthenticationRequestContext} doesn't contain any
* {@link Saml2X509CredentialType#SIGNING} credentials the result will not contain any
* signatures. The data set will be signed and encoded for REDIRECT binding including
* the DEFLATE encoding. It will contain the following parameters to be sent as part
* of the query string: {@code SAMLRequest, RelayState, SigAlg, Signature}. <i>The
* default implementation, for sake of backwards compatibility, of this method returns
* the SAMLRequest message with an XML signature embedded, that should only be used
* for the{@link Saml2MessageBinding#POST} binding, but works over
* {@link Saml2MessageBinding#POST} with most providers.</i>
* @param context - information about the identity provider, the recipient of this
* authentication request and accompanying data
* @return a {@link Saml2RedirectAuthenticationRequest} object with applicable http
* parameters necessary to make the AuthNRequest over a POST or REDIRECT binding. All
* parameters will be SAML encoded/deflated, but escaped, ie URI encoded or encoded
* for Form Data.
* @throws Saml2Exception when a SAML library exception occurs
* @since 5.3
*/
default Saml2RedirectAuthenticationRequest createRedirectAuthenticationRequest(
Saml2AuthenticationRequestContext context) {
// backwards compatible with 5.2.x settings
Saml2AuthenticationRequest.Builder resultBuilder = Saml2AuthenticationRequest
.withAuthenticationRequestContext(context);
String samlRequest = createAuthenticationRequest(resultBuilder.build());
samlRequest = Saml2Utils.samlEncode(Saml2Utils.samlDeflate(samlRequest));
return Saml2RedirectAuthenticationRequest.withAuthenticationRequestContext(context).samlRequest(samlRequest)
.build();
}
/**
* Creates all the necessary AuthNRequest parameters for a POST binding. If the
* {@link Saml2AuthenticationRequestContext} doesn't contain any
* {@link Saml2X509CredentialType#SIGNING} credentials the result will not contain any
* signatures. The data set will be signed and encoded for POST binding and if
* applicable signed with XML signatures. will contain the following parameters to be
* sent as part of the form data: {@code SAMLRequest, RelayState}. <i>The default
* implementation of this method returns the SAMLRequest message with an XML signature
* embedded, that should only be used for the {@link Saml2MessageBinding#POST}
* binding.</i>
* @param context - information about the identity provider, the recipient of this
* authentication request and accompanying data
* @return a {@link Saml2PostAuthenticationRequest} object with applicable http
* parameters necessary to make the AuthNRequest over a POST binding. All parameters
* will be SAML encoded but not escaped for Form Data.
* @throws Saml2Exception when a SAML library exception occurs
* @since 5.3
*/
default Saml2PostAuthenticationRequest createPostAuthenticationRequest(Saml2AuthenticationRequestContext context) {
// backwards compatible with 5.2.x settings
Saml2AuthenticationRequest.Builder resultBuilder = Saml2AuthenticationRequest
.withAuthenticationRequestContext(context);
String samlRequest = createAuthenticationRequest(resultBuilder.build());
samlRequest = Saml2Utils.samlEncode(samlRequest.getBytes(StandardCharsets.UTF_8));
return Saml2PostAuthenticationRequest.withAuthenticationRequestContext(context).samlRequest(samlRequest)
.build();
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -17,10 +17,8 @@
package org.springframework.security.saml2.provider.service.authentication; package org.springframework.security.saml2.provider.service.authentication;
import java.util.Collections; import java.util.Collections;
import java.util.List;
import org.springframework.security.authentication.AbstractAuthenticationToken; import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.saml2.credentials.Saml2X509Credential;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.util.Assert; import org.springframework.util.Assert;
@ -81,31 +79,6 @@ public class Saml2AuthenticationToken extends AbstractAuthenticationToken {
this(relyingPartyRegistration, saml2Response, null); this(relyingPartyRegistration, saml2Response, null);
} }
/**
* Creates an authentication token from an incoming SAML 2 Response object
* @param saml2Response inflated and decoded XML representation of the SAML 2 Response
* @param recipientUri the URL that the SAML 2 Response was received at. Used for
* validation
* @param idpEntityId the entity ID of the asserting entity
* @param localSpEntityId the configured local SP, the relying party, entity ID
* @param credentials the credentials configured for signature verification and
* decryption
* @deprecated Use {@link #Saml2AuthenticationToken(RelyingPartyRegistration, String)}
* instead
*/
@Deprecated
public Saml2AuthenticationToken(String saml2Response, String recipientUri, String idpEntityId,
String localSpEntityId, List<Saml2X509Credential> credentials) {
super(null);
this.relyingPartyRegistration = RelyingPartyRegistration.withRegistrationId(idpEntityId)
.entityId(localSpEntityId).assertionConsumerServiceLocation(recipientUri)
.credentials((c) -> c.addAll(credentials)).assertingPartyDetails((assertingParty) -> assertingParty
.entityId(idpEntityId).singleSignOnServiceLocation(idpEntityId))
.build();
this.saml2Response = saml2Response;
this.authenticationRequest = null;
}
/** /**
* Returns the decoded and inflated SAML 2.0 Response XML object as a string * Returns the decoded and inflated SAML 2.0 Response XML object as a string
* @return decoded and inflated XML data as a {@link String} * @return decoded and inflated XML data as a {@link String}
@ -141,38 +114,6 @@ public class Saml2AuthenticationToken extends AbstractAuthenticationToken {
return this.saml2Response; return this.saml2Response;
} }
/**
* Returns the URI that the SAML 2 Response object came in on
* @return URI as a string
* @deprecated Use
* {@code getRelyingPartyRegistration().getAssertionConsumerServiceLocation()} instead
*/
@Deprecated
public String getRecipientUri() {
return this.relyingPartyRegistration.getAssertionConsumerServiceLocation();
}
/**
* Returns the configured entity ID of the receiving relying party, SP
* @return an entityID for the configured local relying party
* @deprecated Use {@code getRelyingPartyRegistration().getEntityId()} instead
*/
@Deprecated
public String getLocalSpEntityId() {
return this.relyingPartyRegistration.getEntityId();
}
/**
* Returns all the credentials associated with the relying party configuraiton
* @return all associated credentials
* @deprecated Get the credentials through {@link #getRelyingPartyRegistration()}
* instead
*/
@Deprecated
public List<Saml2X509Credential> getX509Credentials() {
return this.relyingPartyRegistration.getCredentials();
}
/** /**
* @return false * @return false
*/ */
@ -190,18 +131,6 @@ public class Saml2AuthenticationToken extends AbstractAuthenticationToken {
throw new IllegalArgumentException(); throw new IllegalArgumentException();
} }
/**
* Returns the configured IDP, asserting party, entity ID
* @return a string representing the entity ID
* @deprecated Use
* {@code getRelyingPartyRegistration().getAssertingPartyDetails().getEntityId()}
* instead
*/
@Deprecated
public String getIdpEntityId() {
return this.relyingPartyRegistration.getAssertingPartyDetails().getEntityId();
}
/** /**
* Returns the authentication request sent to the assertion party or {@code null} if * Returns the authentication request sent to the assertion party or {@code null} if
* no authentication request is present * no authentication request is present

View File

@ -1,72 +0,0 @@
/*
* Copyright 2002-2020 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 org.springframework.security.saml2.provider.service.authentication;
import java.io.Serializable;
import org.springframework.security.core.SpringSecurityCoreVersion;
/**
* A representation of an SAML 2.0 Error.
*
* <p>
* At a minimum, an error response will contain an error code. The commonly used error
* code are defined in this class or a new codes can be defined in the future as arbitrary
* strings.
* </p>
*
* @since 5.2
* @deprecated Use {@link org.springframework.security.saml2.core.Saml2Error} instead
*/
@Deprecated
public class Saml2Error implements Serializable {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
private final org.springframework.security.saml2.core.Saml2Error error;
/**
* Constructs a {@code Saml2Error} using the provided parameters.
* @param errorCode the error code
* @param description the error description
*/
public Saml2Error(String errorCode, String description) {
this.error = new org.springframework.security.saml2.core.Saml2Error(errorCode, description);
}
/**
* Returns the error code.
* @return the error code
*/
public final String getErrorCode() {
return this.error.getErrorCode();
}
/**
* Returns the error description.
* @return the error description
*/
public final String getDescription() {
return this.error.getDescription();
}
@Override
public String toString() {
return "[" + this.getErrorCode() + "] " + ((this.getDescription() != null) ? this.getDescription() : "");
}
}

View File

@ -1,107 +0,0 @@
/*
* Copyright 2002-2020 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 org.springframework.security.saml2.provider.service.authentication;
/**
* A list of SAML known 2 error codes used during SAML authentication.
*
* @since 5.2
* @deprecated Use {@link org.springframework.security.saml2.core.Saml2ErrorCodes} instead
*/
@Deprecated
public interface Saml2ErrorCodes {
/**
* SAML Data does not represent a SAML 2 Response object. A valid XML object was
* received, but that object was not a SAML 2 Response object of type
* {@code ResponseType} per specification
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=46
*/
String UNKNOWN_RESPONSE_CLASS = org.springframework.security.saml2.core.Saml2ErrorCodes.UNKNOWN_RESPONSE_CLASS;
/**
* The response data is malformed or incomplete. An invalid XML object was received,
* and XML unmarshalling failed.
*/
String MALFORMED_RESPONSE_DATA = org.springframework.security.saml2.core.Saml2ErrorCodes.MALFORMED_RESPONSE_DATA;
/**
* Response destination does not match the request URL. A SAML 2 response object was
* received at a URL that did not match the URL stored in the {code Destination}
* attribute in the Response object.
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=38
*/
String INVALID_DESTINATION = org.springframework.security.saml2.core.Saml2ErrorCodes.INVALID_DESTINATION;
/**
* The assertion was not valid. The assertion used for authentication failed
* validation. Details around the failure will be present in the error description.
*/
String INVALID_ASSERTION = org.springframework.security.saml2.core.Saml2ErrorCodes.INVALID_ASSERTION;
/**
* The signature of response or assertion was invalid. Either the response or the
* assertion was missing a signature or the signature could not be verified using the
* system's configured credentials. Most commonly the IDP's X509 certificate.
*/
String INVALID_SIGNATURE = org.springframework.security.saml2.core.Saml2ErrorCodes.INVALID_SIGNATURE;
/**
* The assertion did not contain a subject element. The subject element, type
* SubjectType, contains a {@code NameID} or an {@code EncryptedID} that is used to
* assign the authenticated principal an identifier, typically a username.
*
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=18
*/
String SUBJECT_NOT_FOUND = org.springframework.security.saml2.core.Saml2ErrorCodes.SUBJECT_NOT_FOUND;
/**
* The subject did not contain a user identifier The assertion contained a subject
* element, but the subject element did not have a {@code NameID} or
* {@code EncryptedID} element
*
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=18
*/
String USERNAME_NOT_FOUND = org.springframework.security.saml2.core.Saml2ErrorCodes.USERNAME_NOT_FOUND;
/**
* The system failed to decrypt an assertion or a name identifier. This error code
* will be thrown if the decryption of either a {@code EncryptedAssertion} or
* {@code EncryptedID} fails.
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=17
*/
String DECRYPTION_ERROR = org.springframework.security.saml2.core.Saml2ErrorCodes.DECRYPTION_ERROR;
/**
* An Issuer element contained a value that didn't
* https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf#page=15
*/
String INVALID_ISSUER = org.springframework.security.saml2.core.Saml2ErrorCodes.INVALID_ISSUER;
/**
* An error happened during validation. Used when internal, non classified, errors are
* caught during the authentication process.
*/
String INTERNAL_VALIDATION_ERROR = org.springframework.security.saml2.core.Saml2ErrorCodes.INTERNAL_VALIDATION_ERROR;
/**
* The relying party registration was not found. The registration ID did not
* correspond to any relying party registration.
*/
String RELYING_PARTY_REGISTRATION_NOT_FOUND = org.springframework.security.saml2.core.Saml2ErrorCodes.RELYING_PARTY_REGISTRATION_NOT_FOUND;
}

View File

@ -26,7 +26,7 @@ import org.springframework.security.saml2.provider.service.registration.Saml2Mes
* (line 2031) * (line 2031)
* *
* @since 5.3 * @since 5.3
* @see Saml2AuthenticationRequestFactory * @see org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver
*/ */
public class Saml2PostAuthenticationRequest extends AbstractSaml2AuthenticationRequest { public class Saml2PostAuthenticationRequest extends AbstractSaml2AuthenticationRequest {
@ -42,19 +42,6 @@ public class Saml2PostAuthenticationRequest extends AbstractSaml2AuthenticationR
return Saml2MessageBinding.POST; return Saml2MessageBinding.POST;
} }
/**
* Constructs a {@link Builder} from a {@link Saml2AuthenticationRequestContext}
* object. By default the
* {@link Saml2PostAuthenticationRequest#getAuthenticationRequestUri()} will be set to
* the {@link Saml2AuthenticationRequestContext#getDestination()} value.
* @param context input providing {@code Destination}, {@code RelayState}, and
* {@code Issuer} objects.
* @return a modifiable builder object
*/
public static Builder withAuthenticationRequestContext(Saml2AuthenticationRequestContext context) {
return new Builder().authenticationRequestUri(context.getDestination()).relayState(context.getRelayState());
}
/** /**
* Constructs a {@link Builder} from a {@link RelyingPartyRegistration} object. * Constructs a {@link Builder} from a {@link RelyingPartyRegistration} object.
* @param registration a relying party registration * @param registration a relying party registration

View File

@ -26,7 +26,7 @@ import org.springframework.security.saml2.provider.service.registration.Saml2Mes
* (line 2031) * (line 2031)
* *
* @since 5.3 * @since 5.3
* @see Saml2AuthenticationRequestFactory * @see org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver
*/ */
public final class Saml2RedirectAuthenticationRequest extends AbstractSaml2AuthenticationRequest { public final class Saml2RedirectAuthenticationRequest extends AbstractSaml2AuthenticationRequest {
@ -65,19 +65,6 @@ public final class Saml2RedirectAuthenticationRequest extends AbstractSaml2Authe
return Saml2MessageBinding.REDIRECT; return Saml2MessageBinding.REDIRECT;
} }
/**
* Constructs a {@link Saml2RedirectAuthenticationRequest.Builder} from a
* {@link Saml2AuthenticationRequestContext} object. By default the
* {@link Saml2RedirectAuthenticationRequest#getAuthenticationRequestUri()} will be
* set to the {@link Saml2AuthenticationRequestContext#getDestination()} value.
* @param context input providing {@code Destination}, {@code RelayState}, and
* {@code Issuer} objects.
* @return a modifiable builder object
*/
public static Builder withAuthenticationRequestContext(Saml2AuthenticationRequestContext context) {
return new Builder().authenticationRequestUri(context.getDestination()).relayState(context.getRelayState());
}
/** /**
* Constructs a {@link Saml2PostAuthenticationRequest.Builder} from a * Constructs a {@link Saml2PostAuthenticationRequest.Builder} from a
* {@link RelyingPartyRegistration} object. * {@link RelyingPartyRegistration} object.

View File

@ -16,17 +16,13 @@
package org.springframework.security.saml2.provider.service.registration; package org.springframework.security.saml2.provider.service.registration;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function;
import org.opensaml.xmlsec.signature.support.SignatureConstants; import org.opensaml.xmlsec.signature.support.SignatureConstants;
@ -89,9 +85,7 @@ public final class RelyingPartyRegistration {
private final String nameIdFormat; private final String nameIdFormat;
private final ProviderDetails providerDetails; private final AssertingPartyDetails assertingPartyDetails;
private final List<org.springframework.security.saml2.credentials.Saml2X509Credential> credentials;
private final Collection<Saml2X509Credential> decryptionX509Credentials; private final Collection<Saml2X509Credential> decryptionX509Credentials;
@ -100,8 +94,7 @@ public final class RelyingPartyRegistration {
private RelyingPartyRegistration(String registrationId, String entityId, String assertionConsumerServiceLocation, private RelyingPartyRegistration(String registrationId, String entityId, String assertionConsumerServiceLocation,
Saml2MessageBinding assertionConsumerServiceBinding, String singleLogoutServiceLocation, Saml2MessageBinding assertionConsumerServiceBinding, String singleLogoutServiceLocation,
String singleLogoutServiceResponseLocation, Saml2MessageBinding singleLogoutServiceBinding, String singleLogoutServiceResponseLocation, Saml2MessageBinding singleLogoutServiceBinding,
ProviderDetails providerDetails, String nameIdFormat, AssertingPartyDetails assertingPartyDetails, String nameIdFormat,
Collection<org.springframework.security.saml2.credentials.Saml2X509Credential> credentials,
Collection<Saml2X509Credential> decryptionX509Credentials, Collection<Saml2X509Credential> decryptionX509Credentials,
Collection<Saml2X509Credential> signingX509Credentials) { Collection<Saml2X509Credential> signingX509Credentials) {
Assert.hasText(registrationId, "registrationId cannot be empty"); Assert.hasText(registrationId, "registrationId cannot be empty");
@ -110,13 +103,7 @@ public final class RelyingPartyRegistration {
Assert.notNull(assertionConsumerServiceBinding, "assertionConsumerServiceBinding cannot be null"); Assert.notNull(assertionConsumerServiceBinding, "assertionConsumerServiceBinding cannot be null");
Assert.isTrue(singleLogoutServiceLocation == null || singleLogoutServiceBinding != null, Assert.isTrue(singleLogoutServiceLocation == null || singleLogoutServiceBinding != null,
"singleLogoutServiceBinding cannot be null when singleLogoutServiceLocation is set"); "singleLogoutServiceBinding cannot be null when singleLogoutServiceLocation is set");
Assert.notNull(providerDetails, "providerDetails cannot be null"); Assert.notNull(assertingPartyDetails, "assertingPartyDetails cannot be null");
Assert.isTrue(
!credentials.isEmpty() || (decryptionX509Credentials.isEmpty() && signingX509Credentials.isEmpty()),
"credentials cannot be empty");
for (org.springframework.security.saml2.credentials.Saml2X509Credential c : credentials) {
Assert.notNull(c, "credentials cannot contain null elements");
}
Assert.notNull(decryptionX509Credentials, "decryptionX509Credentials cannot be null"); Assert.notNull(decryptionX509Credentials, "decryptionX509Credentials cannot be null");
for (Saml2X509Credential c : decryptionX509Credentials) { for (Saml2X509Credential c : decryptionX509Credentials) {
Assert.notNull(c, "decryptionX509Credentials cannot contain null elements"); Assert.notNull(c, "decryptionX509Credentials cannot contain null elements");
@ -136,8 +123,7 @@ public final class RelyingPartyRegistration {
this.singleLogoutServiceResponseLocation = singleLogoutServiceResponseLocation; this.singleLogoutServiceResponseLocation = singleLogoutServiceResponseLocation;
this.singleLogoutServiceBinding = singleLogoutServiceBinding; this.singleLogoutServiceBinding = singleLogoutServiceBinding;
this.nameIdFormat = nameIdFormat; this.nameIdFormat = nameIdFormat;
this.providerDetails = providerDetails; this.assertingPartyDetails = assertingPartyDetails;
this.credentials = Collections.unmodifiableList(new LinkedList<>(credentials));
this.decryptionX509Credentials = Collections.unmodifiableList(new LinkedList<>(decryptionX509Credentials)); this.decryptionX509Credentials = Collections.unmodifiableList(new LinkedList<>(decryptionX509Credentials));
this.signingX509Credentials = Collections.unmodifiableList(new LinkedList<>(signingX509Credentials)); this.signingX509Credentials = Collections.unmodifiableList(new LinkedList<>(signingX509Credentials));
} }
@ -278,139 +264,7 @@ public final class RelyingPartyRegistration {
* @since 5.4 * @since 5.4
*/ */
public AssertingPartyDetails getAssertingPartyDetails() { public AssertingPartyDetails getAssertingPartyDetails() {
return this.providerDetails.assertingPartyDetails; return this.assertingPartyDetails;
}
/**
* Returns the entity ID of the IDP, the asserting party.
* @return entity ID of the asserting party
* @deprecated use {@link AssertingPartyDetails#getEntityId} from
* {@link #getAssertingPartyDetails}
*/
@Deprecated
public String getRemoteIdpEntityId() {
return this.providerDetails.getEntityId();
}
/**
* returns the URL template for which ACS URL authentication requests should contain
* Possible variables are {@code baseUrl}, {@code registrationId}, {@code baseScheme},
* {@code baseHost}, and {@code basePort}.
* @return string containing the ACS URL template, with or without variables present
* @deprecated Use {@link #getAssertionConsumerServiceLocation} instead
*/
@Deprecated
public String getAssertionConsumerServiceUrlTemplate() {
return this.assertionConsumerServiceLocation;
}
/**
* Contains the URL for which to send the SAML 2 Authentication Request to initiate a
* single sign on flow.
* @return a IDP URL that accepts REDIRECT or POST binding for authentication requests
* @deprecated use {@link AssertingPartyDetails#getSingleSignOnServiceLocation} from
* {@link #getAssertingPartyDetails}
*/
@Deprecated
public String getIdpWebSsoUrl() {
return this.getAssertingPartyDetails().getSingleSignOnServiceLocation();
}
/**
* Returns specific configuration around the Identity Provider SSO endpoint
* @return the IDP SSO endpoint configuration
* @since 5.3
* @deprecated Use {@link #getAssertingPartyDetails} instead
*/
@Deprecated
public ProviderDetails getProviderDetails() {
return this.providerDetails;
}
/**
* The local relying party, or Service Provider, can generate it's entity ID based on
* possible variables of {@code baseUrl}, {@code registrationId}, {@code baseScheme},
* {@code baseHost}, and {@code basePort}, for example
* {@code {baseUrl}/saml2/service-provider-metadata/{registrationId}}
* @return a string containing the entity ID or entity ID template
* @deprecated Use {@link #getEntityId} instead
*/
@Deprecated
public String getLocalEntityIdTemplate() {
return this.entityId;
}
/**
* Returns a list of configured credentials to be used in message exchanges between
* relying party, SP, and asserting party, IDP.
* @return a list of credentials
* @deprecated Instead of retrieving all credentials, use the appropriate method for
* obtaining the correct type
*/
@Deprecated
public List<org.springframework.security.saml2.credentials.Saml2X509Credential> getCredentials() {
return this.credentials;
}
/**
* @return a filtered list containing only credentials of type
* {@link org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType#VERIFICATION}.
* Returns an empty list of credentials are not found
* @deprecated Use {code #getAssertingPartyDetails().getSigningX509Credentials()}
* instead
*/
@Deprecated
public List<org.springframework.security.saml2.credentials.Saml2X509Credential> getVerificationCredentials() {
return filterCredentials(
org.springframework.security.saml2.credentials.Saml2X509Credential::isSignatureVerficationCredential);
}
/**
* @return a filtered list containing only credentials of type
* {@link org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType#SIGNING}.
* Returns an empty list of credentials are not found
* @deprecated Use {@link #getSigningX509Credentials()} instead
*/
@Deprecated
public List<org.springframework.security.saml2.credentials.Saml2X509Credential> getSigningCredentials() {
return filterCredentials(
org.springframework.security.saml2.credentials.Saml2X509Credential::isSigningCredential);
}
/**
* @return a filtered list containing only credentials of type
* {@link org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType#ENCRYPTION}.
* Returns an empty list of credentials are not found
* @deprecated Use {@link AssertingPartyDetails#getEncryptionX509Credentials()}
* instead
*/
@Deprecated
public List<org.springframework.security.saml2.credentials.Saml2X509Credential> getEncryptionCredentials() {
return filterCredentials(
org.springframework.security.saml2.credentials.Saml2X509Credential::isEncryptionCredential);
}
/**
* @return a filtered list containing only credentials of type
* {@link org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType#DECRYPTION}.
* Returns an empty list of credentials are not found
* @deprecated Use {@link #getDecryptionX509Credentials()} instead
*/
@Deprecated
public List<org.springframework.security.saml2.credentials.Saml2X509Credential> getDecryptionCredentials() {
return filterCredentials(
org.springframework.security.saml2.credentials.Saml2X509Credential::isDecryptionCredential);
}
private List<org.springframework.security.saml2.credentials.Saml2X509Credential> filterCredentials(
Function<org.springframework.security.saml2.credentials.Saml2X509Credential, Boolean> filter) {
List<org.springframework.security.saml2.credentials.Saml2X509Credential> result = new LinkedList<>();
for (org.springframework.security.saml2.credentials.Saml2X509Credential c : this.credentials) {
if (filter.apply(c)) {
result.add(c);
}
}
return result;
} }
/** /**
@ -477,51 +331,6 @@ public final class RelyingPartyRegistration {
registration.getAssertingPartyDetails().getSingleLogoutServiceBinding())); registration.getAssertingPartyDetails().getSingleLogoutServiceBinding()));
} }
private static Saml2X509Credential fromDeprecated(
org.springframework.security.saml2.credentials.Saml2X509Credential credential) {
PrivateKey privateKey = credential.getPrivateKey();
X509Certificate certificate = credential.getCertificate();
Set<Saml2X509Credential.Saml2X509CredentialType> credentialTypes = new LinkedHashSet<>();
if (credential.isSigningCredential()) {
credentialTypes.add(Saml2X509Credential.Saml2X509CredentialType.SIGNING);
}
if (credential.isSignatureVerficationCredential()) {
credentialTypes.add(Saml2X509Credential.Saml2X509CredentialType.VERIFICATION);
}
if (credential.isEncryptionCredential()) {
credentialTypes.add(Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION);
}
if (credential.isDecryptionCredential()) {
credentialTypes.add(Saml2X509Credential.Saml2X509CredentialType.DECRYPTION);
}
return new Saml2X509Credential(privateKey, certificate, credentialTypes);
}
private static org.springframework.security.saml2.credentials.Saml2X509Credential toDeprecated(
Saml2X509Credential credential) {
PrivateKey privateKey = credential.getPrivateKey();
X509Certificate certificate = credential.getCertificate();
Set<org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType> credentialTypes = new LinkedHashSet<>();
if (credential.isSigningCredential()) {
credentialTypes.add(
org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.SIGNING);
}
if (credential.isVerificationCredential()) {
credentialTypes.add(
org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.VERIFICATION);
}
if (credential.isEncryptionCredential()) {
credentialTypes.add(
org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION);
}
if (credential.isDecryptionCredential()) {
credentialTypes.add(
org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType.DECRYPTION);
}
return new org.springframework.security.saml2.credentials.Saml2X509Credential(privateKey, certificate,
credentialTypes);
}
/** /**
* The configuration metadata of the Asserting party * The configuration metadata of the Asserting party
* *
@ -746,7 +555,7 @@ public final class RelyingPartyRegistration {
* Equivalent to the value found in the asserting party's &lt;EntityDescriptor * Equivalent to the value found in the asserting party's &lt;EntityDescriptor
* EntityID="..."/&gt; * EntityID="..."/&gt;
* @param entityId the asserting party's EntityID * @param entityId the asserting party's EntityID
* @return the {@link ProviderDetails.Builder} for further configuration * @return the {@link AssertingPartyDetails.Builder} for further configuration
*/ */
public Builder entityId(String entityId) { public Builder entityId(String entityId) {
this.entityId = entityId; this.entityId = entityId;
@ -758,7 +567,7 @@ public final class RelyingPartyRegistration {
* preference that relying parties should sign the AuthnRequest before * preference that relying parties should sign the AuthnRequest before
* sending. * sending.
* @param wantAuthnRequestsSigned the WantAuthnRequestsSigned setting * @param wantAuthnRequestsSigned the WantAuthnRequestsSigned setting
* @return the {@link ProviderDetails.Builder} for further configuration * @return the {@link AssertingPartyDetails.Builder} for further configuration
*/ */
public Builder wantAuthnRequestsSigned(boolean wantAuthnRequestsSigned) { public Builder wantAuthnRequestsSigned(boolean wantAuthnRequestsSigned) {
this.wantAuthnRequestsSigned = wantAuthnRequestsSigned; this.wantAuthnRequestsSigned = wantAuthnRequestsSigned;
@ -813,7 +622,7 @@ public final class RelyingPartyRegistration {
* Equivalent to the value found in &lt;SingleSignOnService * Equivalent to the value found in &lt;SingleSignOnService
* Location="..."/&gt; in the asserting party's &lt;IDPSSODescriptor&gt;. * Location="..."/&gt; in the asserting party's &lt;IDPSSODescriptor&gt;.
* @param singleSignOnServiceLocation the SingleSignOnService Location * @param singleSignOnServiceLocation the SingleSignOnService Location
* @return the {@link ProviderDetails.Builder} for further configuration * @return the {@link AssertingPartyDetails.Builder} for further configuration
*/ */
public Builder singleSignOnServiceLocation(String singleSignOnServiceLocation) { public Builder singleSignOnServiceLocation(String singleSignOnServiceLocation) {
this.singleSignOnServiceLocation = singleSignOnServiceLocation; this.singleSignOnServiceLocation = singleSignOnServiceLocation;
@ -829,7 +638,7 @@ public final class RelyingPartyRegistration {
* Equivalent to the value found in &lt;SingleSignOnService Binding="..."/&gt; * Equivalent to the value found in &lt;SingleSignOnService Binding="..."/&gt;
* in the asserting party's &lt;IDPSSODescriptor&gt;. * in the asserting party's &lt;IDPSSODescriptor&gt;.
* @param singleSignOnServiceBinding the SingleSignOnService Binding * @param singleSignOnServiceBinding the SingleSignOnService Binding
* @return the {@link ProviderDetails.Builder} for further configuration * @return the {@link AssertingPartyDetails.Builder} for further configuration
*/ */
public Builder singleSignOnServiceBinding(Saml2MessageBinding singleSignOnServiceBinding) { public Builder singleSignOnServiceBinding(Saml2MessageBinding singleSignOnServiceBinding) {
this.singleSignOnServiceBinding = singleSignOnServiceBinding; this.singleSignOnServiceBinding = singleSignOnServiceBinding;
@ -910,126 +719,6 @@ public final class RelyingPartyRegistration {
} }
/**
* Configuration for IDP SSO endpoint configuration
*
* @since 5.3
* @deprecated Use {@link AssertingPartyDetails} instead
*/
@Deprecated
public static final class ProviderDetails {
private final AssertingPartyDetails assertingPartyDetails;
private ProviderDetails(AssertingPartyDetails assertingPartyDetails) {
Assert.notNull("assertingPartyDetails cannot be null");
this.assertingPartyDetails = assertingPartyDetails;
}
/**
* Returns the entity ID of the Identity Provider
* @return the entity ID of the IDP
*/
public String getEntityId() {
return this.assertingPartyDetails.getEntityId();
}
/**
* Contains the URL for which to send the SAML 2 Authentication Request to
* initiate a single sign on flow.
* @return a IDP URL that accepts REDIRECT or POST binding for authentication
* requests
*/
public String getWebSsoUrl() {
return this.assertingPartyDetails.getSingleSignOnServiceLocation();
}
/**
* @return {@code true} if AuthNRequests from this relying party to the IDP should
* be signed {@code false} if no signature is required.
*/
public boolean isSignAuthNRequest() {
return this.assertingPartyDetails.getWantAuthnRequestsSigned();
}
/**
* @return the type of SAML 2 Binding the AuthNRequest should be sent on
*/
public Saml2MessageBinding getBinding() {
return this.assertingPartyDetails.getSingleSignOnServiceBinding();
}
/**
* Builder for IDP SSO endpoint configuration
*
* @since 5.3
* @deprecated Use {@link AssertingPartyDetails.Builder} instead
*/
@Deprecated
public static final class Builder {
private AssertingPartyDetails.Builder assertingPartyDetailsBuilder = new AssertingPartyDetails.Builder();
/**
* Set the asserting party's <a href=
* "https://www.oasis-open.org/committees/download.php/51890/SAML%20MD%20simplified%20overview.pdf#2.9%20EntityDescriptor">EntityID</a>.
* Equivalent to the value found in the asserting party's &lt;EntityDescriptor
* EntityID="..."/&gt;
* @param entityId the asserting party's EntityID
* @return the {@link Builder} for further configuration
* @since 5.4
*/
public Builder entityId(String entityId) {
this.assertingPartyDetailsBuilder.entityId(entityId);
return this;
}
/**
* Sets the {@code SSO URL} for the remote asserting party, the Identity
* Provider.
* @param url - a URL that accepts authentication requests via REDIRECT or
* POST bindings
* @return this object
*/
public Builder webSsoUrl(String url) {
this.assertingPartyDetailsBuilder.singleSignOnServiceLocation(url);
return this;
}
/**
* Set to true if the AuthNRequest message should be signed
* @param signAuthNRequest true if the message should be signed
* @return this object
*/
public Builder signAuthNRequest(boolean signAuthNRequest) {
this.assertingPartyDetailsBuilder.wantAuthnRequestsSigned(signAuthNRequest);
return this;
}
/**
* Sets the message binding to be used when sending an AuthNRequest message
* @param binding either {@link Saml2MessageBinding#POST} or
* {@link Saml2MessageBinding#REDIRECT}
* @return this object
*/
public Builder binding(Saml2MessageBinding binding) {
this.assertingPartyDetailsBuilder.singleSignOnServiceBinding(binding);
return this;
}
/**
* Creates an immutable ProviderDetails object representing the configuration
* for an Identity Provider, IDP
* @return immutable ProviderDetails object
*/
public ProviderDetails build() {
return new ProviderDetails(this.assertingPartyDetailsBuilder.build());
}
}
}
public static final class Builder { public static final class Builder {
private String registrationId; private String registrationId;
@ -1052,9 +741,7 @@ public final class RelyingPartyRegistration {
private String nameIdFormat = null; private String nameIdFormat = null;
private ProviderDetails.Builder providerDetails = new ProviderDetails.Builder(); private AssertingPartyDetails.Builder assertingPartyDetailsBuilder = new AssertingPartyDetails.Builder();
private Collection<org.springframework.security.saml2.credentials.Saml2X509Credential> credentials = new LinkedHashSet<>();
private Builder(String registrationId) { private Builder(String registrationId) {
this.registrationId = registrationId; this.registrationId = registrationId;
@ -1225,104 +912,7 @@ public final class RelyingPartyRegistration {
* @since 5.4 * @since 5.4
*/ */
public Builder assertingPartyDetails(Consumer<AssertingPartyDetails.Builder> assertingPartyDetails) { public Builder assertingPartyDetails(Consumer<AssertingPartyDetails.Builder> assertingPartyDetails) {
assertingPartyDetails.accept(this.providerDetails.assertingPartyDetailsBuilder); assertingPartyDetails.accept(this.assertingPartyDetailsBuilder);
return this;
}
/**
* Modifies the collection of {@link Saml2X509Credential} objects used in
* communication between IDP and SP For example: <code>
* Saml2X509Credential credential = ...;
* return RelyingPartyRegistration.withRegistrationId("id")
* .credentials((c) -&gt; c.add(credential))
* ...
* .build();
* </code>
* @param credentials - a consumer that can modify the collection of credentials
* @return this object
* @deprecated Use {@link #signingX509Credentials} or
* {@link #decryptionX509Credentials} instead for relying party keys or
* {@link AssertingPartyDetails.Builder#verificationX509Credentials} or
* {@link AssertingPartyDetails.Builder#encryptionX509Credentials} for asserting
* party keys
*/
@Deprecated
public Builder credentials(
Consumer<Collection<org.springframework.security.saml2.credentials.Saml2X509Credential>> credentials) {
credentials.accept(this.credentials);
return this;
}
/**
* <a href=
* "https://www.oasis-open.org/committees/download.php/51890/SAML%20MD%20simplified%20overview.pdf#2.3%20AttributeConsumingService">Assertion
* Consumer Service</a> URL template. It can contain variables {@code baseUrl},
* {@code registrationId}, {@code baseScheme}, {@code baseHost}, and
* {@code basePort}.
* @param assertionConsumerServiceUrlTemplate the Assertion Consumer Service URL
* template (i.e. "{baseUrl}/login/saml2/sso/{registrationId}".
* @return this object
* @deprecated Use {@link #assertionConsumerServiceLocation} instead.
*/
@Deprecated
public Builder assertionConsumerServiceUrlTemplate(String assertionConsumerServiceUrlTemplate) {
this.assertionConsumerServiceLocation = assertionConsumerServiceUrlTemplate;
return this;
}
/**
* Sets the {@code entityId} for the remote asserting party, the Identity
* Provider.
* @param entityId the IDP entityId
* @return this object
* @deprecated use
* {@code #assertingPartyDetails(Consumer<AssertingPartyDetails.Builder >)}
*/
@Deprecated
public Builder remoteIdpEntityId(String entityId) {
assertingPartyDetails((idp) -> idp.entityId(entityId));
return this;
}
/**
* Sets the {@code SSO URL} for the remote asserting party, the Identity Provider.
* @param url - a URL that accepts authentication requests via REDIRECT or POST
* bindings
* @return this object
* @deprecated use
* {@code #assertingPartyDetails(Consumer<AssertingPartyDetails.Builder >)}
*/
@Deprecated
public Builder idpWebSsoUrl(String url) {
assertingPartyDetails((config) -> config.singleSignOnServiceLocation(url));
return this;
}
/**
* Sets the local relying party, or Service Provider, entity Id template. can
* generate it's entity ID based on possible variables of {@code baseUrl},
* {@code registrationId}, {@code baseScheme}, {@code baseHost}, and
* {@code basePort}, for example
* {@code {baseUrl}/saml2/service-provider-metadata/{registrationId}}
* @param template the entity id
* @return a string containing the entity ID or entity ID template
* @deprecated Use {@link #entityId} instead
*/
@Deprecated
public Builder localEntityIdTemplate(String template) {
this.entityId = template;
return this;
}
/**
* Configures the IDP SSO endpoint
* @param providerDetails a consumer that configures the IDP SSO endpoint
* @return this object
* @deprecated Use {@link #assertingPartyDetails} instead
*/
@Deprecated
public Builder providerDetails(Consumer<ProviderDetails.Builder> providerDetails) {
providerDetails.accept(this.providerDetails);
return this; return this;
} }
@ -1332,41 +922,13 @@ public final class RelyingPartyRegistration {
* @return a RelyingPartyRegistration instance * @return a RelyingPartyRegistration instance
*/ */
public RelyingPartyRegistration build() { public RelyingPartyRegistration build() {
for (org.springframework.security.saml2.credentials.Saml2X509Credential credential : this.credentials) {
Saml2X509Credential mapped = fromDeprecated(credential);
if (credential.isSigningCredential()) {
signingX509Credentials((c) -> c.add(mapped));
}
if (credential.isDecryptionCredential()) {
decryptionX509Credentials((c) -> c.add(mapped));
}
if (credential.isSignatureVerficationCredential()) {
this.providerDetails.assertingPartyDetailsBuilder.verificationX509Credentials((c) -> c.add(mapped));
}
if (credential.isEncryptionCredential()) {
this.providerDetails.assertingPartyDetailsBuilder.encryptionX509Credentials((c) -> c.add(mapped));
}
}
for (Saml2X509Credential credential : this.signingX509Credentials) {
this.credentials.add(toDeprecated(credential));
}
for (Saml2X509Credential credential : this.decryptionX509Credentials) {
this.credentials.add(toDeprecated(credential));
}
for (Saml2X509Credential credential : this.providerDetails.assertingPartyDetailsBuilder.verificationX509Credentials) {
this.credentials.add(toDeprecated(credential));
}
for (Saml2X509Credential credential : this.providerDetails.assertingPartyDetailsBuilder.encryptionX509Credentials) {
this.credentials.add(toDeprecated(credential));
}
if (this.singleLogoutServiceResponseLocation == null) { if (this.singleLogoutServiceResponseLocation == null) {
this.singleLogoutServiceResponseLocation = this.singleLogoutServiceLocation; this.singleLogoutServiceResponseLocation = this.singleLogoutServiceLocation;
} }
return new RelyingPartyRegistration(this.registrationId, this.entityId, return new RelyingPartyRegistration(this.registrationId, this.entityId,
this.assertionConsumerServiceLocation, this.assertionConsumerServiceBinding, this.assertionConsumerServiceLocation, this.assertionConsumerServiceBinding,
this.singleLogoutServiceLocation, this.singleLogoutServiceResponseLocation, this.singleLogoutServiceLocation, this.singleLogoutServiceResponseLocation,
this.singleLogoutServiceBinding, this.providerDetails.build(), this.nameIdFormat, this.credentials, this.singleLogoutServiceBinding, this.assertingPartyDetailsBuilder.build(), this.nameIdFormat,
this.decryptionX509Credentials, this.signingX509Credentials); this.decryptionX509Credentials, this.signingX509Credentials);
} }

View File

@ -23,30 +23,17 @@ import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.opensaml.core.Version;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.security.saml2.core.Saml2ParameterNames; import org.springframework.security.saml2.core.Saml2ParameterNames;
import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestContext;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestFactory;
import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest;
import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; 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.Saml2MessageBinding;
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.DefaultSaml2AuthenticationRequestContextResolver;
import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository; import org.springframework.security.saml2.provider.service.web.HttpSessionSaml2AuthenticationRequestRepository;
import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestContextResolver;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository; import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository;
import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver; import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher.MatchResult;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter; import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.HtmlUtils; import org.springframework.web.util.HtmlUtils;
@ -82,53 +69,6 @@ public class Saml2WebSsoAuthenticationRequestFilter extends OncePerRequestFilter
private Saml2AuthenticationRequestRepository<AbstractSaml2AuthenticationRequest> authenticationRequestRepository = new HttpSessionSaml2AuthenticationRequestRepository(); private Saml2AuthenticationRequestRepository<AbstractSaml2AuthenticationRequest> authenticationRequestRepository = new HttpSessionSaml2AuthenticationRequestRepository();
/**
* Construct a {@link Saml2WebSsoAuthenticationRequestFilter} with the provided
* parameters
* @param relyingPartyRegistrationRepository a repository for relying party
* configurations
* @deprecated use the constructor that takes a
* {@link Saml2AuthenticationRequestFactory}
*/
@Deprecated
public Saml2WebSsoAuthenticationRequestFilter(
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository) {
this(new DefaultSaml2AuthenticationRequestContextResolver(
(RelyingPartyRegistrationResolver) new DefaultRelyingPartyRegistrationResolver(
relyingPartyRegistrationRepository)),
requestFactory());
}
private static Saml2AuthenticationRequestFactory requestFactory() {
String opensamlClassName = "org.springframework.security.saml2.provider.service.authentication.OpenSamlAuthenticationRequestFactory";
if (Version.getVersion().startsWith("4")) {
opensamlClassName = "org.springframework.security.saml2.provider.service.authentication.OpenSaml4AuthenticationRequestFactory";
}
try {
return (Saml2AuthenticationRequestFactory) ClassUtils.forName(opensamlClassName, null)
.getDeclaredConstructor().newInstance();
}
catch (Exception ex) {
throw new IllegalStateException(ex);
}
}
/**
* Construct a {@link Saml2WebSsoAuthenticationRequestFilter} with the provided
* parameters
* @param authenticationRequestContextResolver a strategy for formulating a
* {@link Saml2AuthenticationRequestContext}
* @param authenticationRequestFactory strategy for formulating a
* &lt;saml2:AuthnRequest&gt;
* @since 5.4
*/
public Saml2WebSsoAuthenticationRequestFilter(
Saml2AuthenticationRequestContextResolver authenticationRequestContextResolver,
Saml2AuthenticationRequestFactory authenticationRequestFactory) {
this(new FactorySaml2AuthenticationRequestResolver(authenticationRequestContextResolver,
authenticationRequestFactory));
}
/** /**
* Construct a {@link Saml2WebSsoAuthenticationRequestFilter} with the strategy for * Construct a {@link Saml2WebSsoAuthenticationRequestFilter} with the strategy for
* resolving the {@code AuthnRequest} * resolving the {@code AuthnRequest}
@ -141,35 +81,6 @@ public class Saml2WebSsoAuthenticationRequestFilter extends OncePerRequestFilter
this.authenticationRequestResolver = authenticationRequestResolver; this.authenticationRequestResolver = authenticationRequestResolver;
} }
/**
* Use the given {@link Saml2AuthenticationRequestFactory} for formulating the SAML
* 2.0 AuthnRequest
* @param authenticationRequestFactory the {@link Saml2AuthenticationRequestFactory}
* to use
* @deprecated use the constructor instead
*/
@Deprecated
public void setAuthenticationRequestFactory(Saml2AuthenticationRequestFactory authenticationRequestFactory) {
Assert.notNull(authenticationRequestFactory, "authenticationRequestFactory cannot be null");
Assert.isInstanceOf(FactorySaml2AuthenticationRequestResolver.class, this.authenticationRequestResolver,
"You cannot supply both a Saml2AuthenticationRequestResolver and a Saml2AuthenticationRequestFactory");
((FactorySaml2AuthenticationRequestResolver) this.authenticationRequestResolver).authenticationRequestFactory = authenticationRequestFactory;
}
/**
* Use the given {@link RequestMatcher} that activates this filter for a given request
* @param redirectMatcher the {@link RequestMatcher} to use
* @deprecated Configure the request matcher in an implementation of
* {@link Saml2AuthenticationRequestResolver} instead
*/
@Deprecated
public void setRedirectMatcher(RequestMatcher redirectMatcher) {
Assert.notNull(redirectMatcher, "redirectMatcher cannot be null");
Assert.isInstanceOf(FactorySaml2AuthenticationRequestResolver.class, this.authenticationRequestResolver,
"You cannot supply a Saml2AuthenticationRequestResolver and a redirect matcher");
((FactorySaml2AuthenticationRequestResolver) this.authenticationRequestResolver).redirectMatcher = redirectMatcher;
}
/** /**
* Use the given {@link Saml2AuthenticationRequestRepository} to save the * Use the given {@link Saml2AuthenticationRequestRepository} to save the
* authentication request * authentication request
@ -270,41 +181,4 @@ public class Saml2WebSsoAuthenticationRequestFilter extends OncePerRequestFilter
return html.toString(); return html.toString();
} }
private static class FactorySaml2AuthenticationRequestResolver implements Saml2AuthenticationRequestResolver {
private final Saml2AuthenticationRequestContextResolver authenticationRequestContextResolver;
private RequestMatcher redirectMatcher = new AntPathRequestMatcher("/saml2/authenticate/{registrationId}");
private Saml2AuthenticationRequestFactory authenticationRequestFactory;
FactorySaml2AuthenticationRequestResolver(
Saml2AuthenticationRequestContextResolver authenticationRequestContextResolver,
Saml2AuthenticationRequestFactory authenticationRequestFactory) {
Assert.notNull(authenticationRequestContextResolver, "authenticationRequestContextResolver cannot be null");
Assert.notNull(authenticationRequestFactory, "authenticationRequestFactory cannot be null");
this.authenticationRequestContextResolver = authenticationRequestContextResolver;
this.authenticationRequestFactory = authenticationRequestFactory;
}
@Override
public AbstractSaml2AuthenticationRequest resolve(HttpServletRequest request) {
MatchResult matcher = this.redirectMatcher.matcher(request);
if (!matcher.isMatch()) {
return null;
}
Saml2AuthenticationRequestContext context = this.authenticationRequestContextResolver.resolve(request);
if (context == null) {
return null;
}
Saml2MessageBinding binding = context.getRelyingPartyRegistration().getAssertingPartyDetails()
.getSingleSignOnServiceBinding();
if (binding == Saml2MessageBinding.REDIRECT) {
return this.authenticationRequestFactory.createRedirectAuthenticationRequest(context);
}
return this.authenticationRequestFactory.createPostAuthenticationRequest(context);
}
}
} }

View File

@ -1,90 +0,0 @@
/*
* Copyright 2002-2022 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 org.springframework.security.saml2.provider.service.web;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.saml2.core.Saml2ParameterNames;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestContext;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.util.Assert;
/**
* The default implementation for {@link Saml2AuthenticationRequestContextResolver} which
* uses the current request and given relying party to formulate a
* {@link Saml2AuthenticationRequestContext}
*
* @author Shazin Sadakath
* @author Josh Cummings
* @since 5.4
* @deprecated Use
* {@link org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver}
* instead
*/
@Deprecated
public final class DefaultSaml2AuthenticationRequestContextResolver
implements Saml2AuthenticationRequestContextResolver {
private final Log logger = LogFactory.getLog(getClass());
private final Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver;
/**
* Construct a {@link DefaultSaml2AuthenticationRequestContextResolver}
* @param relyingPartyRegistrationResolver
* @deprecated Use
* {@link DefaultSaml2AuthenticationRequestContextResolver#DefaultSaml2AuthenticationRequestContextResolver(RelyingPartyRegistrationResolver)}
* instead
*/
@Deprecated
public DefaultSaml2AuthenticationRequestContextResolver(
Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver) {
this.relyingPartyRegistrationResolver = relyingPartyRegistrationResolver;
}
public DefaultSaml2AuthenticationRequestContextResolver(
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
this.relyingPartyRegistrationResolver = (request) -> relyingPartyRegistrationResolver.resolve(request, null);
}
@Override
public Saml2AuthenticationRequestContext resolve(HttpServletRequest request) {
Assert.notNull(request, "request cannot be null");
RelyingPartyRegistration relyingParty = this.relyingPartyRegistrationResolver.convert(request);
if (relyingParty == null) {
return null;
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Creating SAML 2.0 Authentication Request for Asserting Party ["
+ relyingParty.getRegistrationId() + "]");
}
return createRedirectAuthenticationRequestContext(request, relyingParty);
}
private Saml2AuthenticationRequestContext createRedirectAuthenticationRequestContext(HttpServletRequest request,
RelyingPartyRegistration relyingParty) {
return Saml2AuthenticationRequestContext.builder().issuer(relyingParty.getEntityId())
.relyingPartyRegistration(relyingParty)
.assertionConsumerServiceUrl(relyingParty.getAssertionConsumerServiceLocation())
.relayState(request.getParameter(Saml2ParameterNames.RELAY_STATE)).build();
}
}

View File

@ -1,46 +0,0 @@
/*
* Copyright 2002-2022 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 org.springframework.security.saml2.provider.service.web;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestContext;
/**
* This {@code Saml2AuthenticationRequestContextResolver} formulates a
* <a href="https://docs.oasis-open.org/security/saml/v2.0/saml-core-2.0-os.pdf">SAML 2.0
* AuthnRequest</a> (line 1968)
*
* @author Shazin Sadakath
* @author Josh Cummings
* @since 5.4
* @deprecated Use
* {@link org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver}
* instead
*/
@Deprecated
public interface Saml2AuthenticationRequestContextResolver {
/**
* This {@code resolve} method is defined to create a
* {@link Saml2AuthenticationRequestContext}
* @param request the current request
* @return the created {@link Saml2AuthenticationRequestContext} for the request
*/
Saml2AuthenticationRequestContext resolve(HttpServletRequest request);
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -54,25 +54,10 @@ public final class Saml2AuthenticationTokenConverter implements AuthenticationCo
private Function<HttpServletRequest, AbstractSaml2AuthenticationRequest> loader; private Function<HttpServletRequest, AbstractSaml2AuthenticationRequest> loader;
/**
* Constructs a {@link Saml2AuthenticationTokenConverter} given a strategy for
* resolving {@link RelyingPartyRegistration}s
* @param relyingPartyRegistrationResolver the strategy for resolving
* {@link RelyingPartyRegistration}s
* @deprecated Use
* {@link Saml2AuthenticationTokenConverter#Saml2AuthenticationTokenConverter(RelyingPartyRegistrationResolver)}
* instead
*/
@Deprecated
public Saml2AuthenticationTokenConverter(
Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver) {
Assert.notNull(relyingPartyRegistrationResolver, "relyingPartyRegistrationResolver cannot be null");
this.relyingPartyRegistrationResolver = relyingPartyRegistrationResolver;
this.loader = new HttpSessionSaml2AuthenticationRequestRepository()::loadAuthenticationRequest;
}
public Saml2AuthenticationTokenConverter(RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) { public Saml2AuthenticationTokenConverter(RelyingPartyRegistrationResolver relyingPartyRegistrationResolver) {
this(adaptToConverter(relyingPartyRegistrationResolver)); Assert.notNull(relyingPartyRegistrationResolver, "relyingPartyRegistrationResolver cannot be null");
this.relyingPartyRegistrationResolver = adaptToConverter(relyingPartyRegistrationResolver);
this.loader = new HttpSessionSaml2AuthenticationRequestRepository()::loadAuthenticationRequest;
} }
private static Converter<HttpServletRequest, RelyingPartyRegistration> adaptToConverter( private static Converter<HttpServletRequest, RelyingPartyRegistration> adaptToConverter(

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -25,7 +25,6 @@ import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.springframework.core.convert.converter.Converter;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.security.saml2.provider.service.metadata.Saml2MetadataResolver; import org.springframework.security.saml2.provider.service.metadata.Saml2MetadataResolver;
@ -55,21 +54,6 @@ public final class Saml2MetadataFilter extends OncePerRequestFilter {
private RequestMatcher requestMatcher = new AntPathRequestMatcher( private RequestMatcher requestMatcher = new AntPathRequestMatcher(
"/saml2/service-provider-metadata/{registrationId}"); "/saml2/service-provider-metadata/{registrationId}");
/**
* Construct a {@link Saml2MetadataFilter}
* @param relyingPartyRegistrationResolver
* @param saml2MetadataResolver
* @deprecated Use
* {@link Saml2MetadataFilter#Saml2MetadataFilter(RelyingPartyRegistrationResolver, Saml2MetadataResolver)}
* instead
*/
@Deprecated
public Saml2MetadataFilter(Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver,
Saml2MetadataResolver saml2MetadataResolver) {
this.relyingPartyRegistrationResolver = (request, id) -> relyingPartyRegistrationResolver.convert(request);
this.saml2MetadataResolver = saml2MetadataResolver;
}
public Saml2MetadataFilter(RelyingPartyRegistrationResolver relyingPartyRegistrationResolver, public Saml2MetadataFilter(RelyingPartyRegistrationResolver relyingPartyRegistrationResolver,
Saml2MetadataResolver saml2MetadataResolver) { Saml2MetadataResolver saml2MetadataResolver) {
Assert.notNull(relyingPartyRegistrationResolver, "relyingPartyRegistrationResolver cannot be null"); Assert.notNull(relyingPartyRegistrationResolver, "relyingPartyRegistrationResolver cannot be null");

View File

@ -1,206 +0,0 @@
/*
* Copyright 2002-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 org.springframework.security.saml2.provider.service.authentication;
import java.nio.charset.StandardCharsets;
import java.time.Clock;
import java.time.Instant;
import java.util.Map;
import java.util.UUID;
import org.joda.time.DateTime;
import org.opensaml.core.config.ConfigurationService;
import org.opensaml.core.xml.config.XMLObjectProviderRegistry;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.saml2.core.AuthnRequest;
import org.opensaml.saml.saml2.core.Issuer;
import org.opensaml.saml.saml2.core.impl.AuthnRequestBuilder;
import org.opensaml.saml.saml2.core.impl.IssuerBuilder;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.saml2.core.OpenSamlInitializationService;
import org.springframework.security.saml2.core.Saml2ParameterNames;
import org.springframework.security.saml2.provider.service.authentication.OpenSamlSigningUtils.QueryParametersPartial;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* A {@link Saml2AuthenticationRequestFactory} that generates, signs, and serializes a
* SAML 2.0 AuthnRequest using OpenSAML 3
*
* @author Filip Hanik
* @author Josh Cummings
* @since 5.2
* @deprecated Because OpenSAML 3 has reached End-of-Life, please update to
* {@code OpenSaml4AuthenticationRequestFactory}
*/
public class OpenSamlAuthenticationRequestFactory implements Saml2AuthenticationRequestFactory {
static {
OpenSamlInitializationService.initialize();
}
private AuthnRequestBuilder authnRequestBuilder;
private IssuerBuilder issuerBuilder;
private Clock clock = Clock.systemUTC();
private Converter<Saml2AuthenticationRequestContext, Saml2MessageBinding> protocolBindingResolver = (context) -> {
if (context == null) {
return Saml2MessageBinding.POST;
}
return context.getRelyingPartyRegistration().getAssertionConsumerServiceBinding();
};
private Converter<Saml2AuthenticationRequestContext, AuthnRequest> authenticationRequestContextConverter;
/**
* Creates an {@link OpenSamlAuthenticationRequestFactory}
*/
public OpenSamlAuthenticationRequestFactory() {
this.authenticationRequestContextConverter = this::createAuthnRequest;
XMLObjectProviderRegistry registry = ConfigurationService.get(XMLObjectProviderRegistry.class);
this.authnRequestBuilder = (AuthnRequestBuilder) registry.getBuilderFactory()
.getBuilder(AuthnRequest.DEFAULT_ELEMENT_NAME);
this.issuerBuilder = (IssuerBuilder) registry.getBuilderFactory().getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
}
@Override
@Deprecated
public String createAuthenticationRequest(Saml2AuthenticationRequest request) {
Saml2MessageBinding binding = this.protocolBindingResolver.convert(null);
RelyingPartyRegistration registration = RelyingPartyRegistration.withRegistrationId("noId")
.assertionConsumerServiceBinding(binding)
.assertionConsumerServiceLocation(request.getAssertionConsumerServiceUrl())
.entityId(request.getIssuer()).remoteIdpEntityId("noIssuer").idpWebSsoUrl("noUrl")
.credentials((credentials) -> credentials.addAll(request.getCredentials())).build();
Saml2AuthenticationRequestContext context = Saml2AuthenticationRequestContext.builder()
.relyingPartyRegistration(registration).issuer(request.getIssuer())
.assertionConsumerServiceUrl(request.getAssertionConsumerServiceUrl()).build();
AuthnRequest authnRequest = this.authenticationRequestContextConverter.convert(context);
return OpenSamlSigningUtils.serialize(OpenSamlSigningUtils.sign(authnRequest, registration));
}
@Override
public Saml2PostAuthenticationRequest createPostAuthenticationRequest(Saml2AuthenticationRequestContext context) {
AuthnRequest authnRequest = this.authenticationRequestContextConverter.convert(context);
RelyingPartyRegistration registration = context.getRelyingPartyRegistration();
if (registration.getAssertingPartyDetails().getWantAuthnRequestsSigned()) {
OpenSamlSigningUtils.sign(authnRequest, registration);
}
String xml = OpenSamlSigningUtils.serialize(authnRequest);
return Saml2PostAuthenticationRequest.withAuthenticationRequestContext(context)
.samlRequest(Saml2Utils.samlEncode(xml.getBytes(StandardCharsets.UTF_8))).build();
}
@Override
public Saml2RedirectAuthenticationRequest createRedirectAuthenticationRequest(
Saml2AuthenticationRequestContext context) {
AuthnRequest authnRequest = this.authenticationRequestContextConverter.convert(context);
RelyingPartyRegistration registration = context.getRelyingPartyRegistration();
String xml = OpenSamlSigningUtils.serialize(authnRequest);
Saml2RedirectAuthenticationRequest.Builder result = Saml2RedirectAuthenticationRequest
.withAuthenticationRequestContext(context);
String deflatedAndEncoded = Saml2Utils.samlEncode(Saml2Utils.samlDeflate(xml));
result.samlRequest(deflatedAndEncoded).relayState(context.getRelayState());
if (registration.getAssertingPartyDetails().getWantAuthnRequestsSigned()) {
QueryParametersPartial partial = OpenSamlSigningUtils.sign(registration)
.param(Saml2ParameterNames.SAML_REQUEST, deflatedAndEncoded);
if (StringUtils.hasText(context.getRelayState())) {
partial.param(Saml2ParameterNames.RELAY_STATE, context.getRelayState());
}
Map<String, String> parameters = partial.parameters();
return result.sigAlg(parameters.get(Saml2ParameterNames.SIG_ALG))
.signature(parameters.get(Saml2ParameterNames.SIGNATURE)).build();
}
return result.build();
}
private AuthnRequest createAuthnRequest(Saml2AuthenticationRequestContext context) {
String issuer = context.getIssuer();
String destination = context.getDestination();
String assertionConsumerServiceUrl = context.getAssertionConsumerServiceUrl();
Saml2MessageBinding protocolBinding = this.protocolBindingResolver.convert(context);
AuthnRequest auth = this.authnRequestBuilder.buildObject();
if (auth.getID() == null) {
auth.setID("ARQ" + UUID.randomUUID().toString().substring(1));
}
if (auth.getIssueInstant() == null) {
auth.setIssueInstant(new DateTime(this.clock.millis()));
}
if (auth.isForceAuthn() == null) {
auth.setForceAuthn(Boolean.FALSE);
}
if (auth.isPassive() == null) {
auth.setIsPassive(Boolean.FALSE);
}
if (auth.getProtocolBinding() == null) {
auth.setProtocolBinding(protocolBinding.getUrn());
}
Issuer iss = this.issuerBuilder.buildObject();
iss.setValue(issuer);
auth.setIssuer(iss);
auth.setDestination(destination);
auth.setAssertionConsumerServiceURL(assertionConsumerServiceUrl);
return auth;
}
/**
* Set the {@link AuthnRequest} post-processor resolver
* @param authenticationRequestContextConverter a strategy for creating an
* {@link AuthnRequest}
* @since 5.4
*/
public void setAuthenticationRequestContextConverter(
Converter<Saml2AuthenticationRequestContext, AuthnRequest> authenticationRequestContextConverter) {
Assert.notNull(authenticationRequestContextConverter, "authenticationRequestContextConverter cannot be null");
this.authenticationRequestContextConverter = authenticationRequestContextConverter;
}
/**
* ' Use this {@link Clock} with {@link Instant#now()} for generating timestamps
* @param clock the {@link Clock} to use
*/
public void setClock(Clock clock) {
Assert.notNull(clock, "clock cannot be null");
this.clock = clock;
}
/**
* Sets the {@code protocolBinding} to use when generating authentication requests.
* Acceptable values are {@link SAMLConstants#SAML2_POST_BINDING_URI} and
* {@link SAMLConstants#SAML2_REDIRECT_BINDING_URI} The IDP will be reading this value
* in the {@code AuthNRequest} to determine how to send the Response/Assertion to the
* ACS URL, assertion consumer service URL.
* @param protocolBinding either {@link SAMLConstants#SAML2_POST_BINDING_URI} or
* {@link SAMLConstants#SAML2_REDIRECT_BINDING_URI}
* @throws IllegalArgumentException if the protocolBinding is not valid
* @deprecated Use
* {@link org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.Builder#assertionConsumerServiceBinding(Saml2MessageBinding)}
* instead
*/
@Deprecated
public void setProtocolBinding(String protocolBinding) {
Saml2MessageBinding binding = Saml2MessageBinding.from(protocolBinding);
Assert.notNull(binding, "Invalid protocol binding: " + protocolBinding);
this.protocolBindingResolver = (context) -> binding;
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2021 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -606,9 +606,9 @@ public class OpenSamlAuthenticationProviderTests {
private Consumer<Saml2AuthenticationException> errorOf(String errorCode, String description) { private Consumer<Saml2AuthenticationException> errorOf(String errorCode, String description) {
return (ex) -> { return (ex) -> {
assertThat(ex.getError().getErrorCode()).isEqualTo(errorCode); assertThat(ex.getSaml2Error().getErrorCode()).isEqualTo(errorCode);
if (StringUtils.hasText(description)) { if (StringUtils.hasText(description)) {
assertThat(ex.getError().getDescription()).contains(description); assertThat(ex.getSaml2Error().getDescription()).contains(description);
} }
}; };
} }

View File

@ -1,287 +0,0 @@
/*
* Copyright 2002-2020 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 org.springframework.security.saml2.provider.service.authentication;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import org.joda.time.DateTime;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.saml2.core.AuthnRequest;
import org.opensaml.saml.saml2.core.impl.AuthnRequestUnmarshaller;
import org.opensaml.xmlsec.signature.support.SignatureConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.saml2.Saml2Exception;
import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.credentials.TestSaml2X509Credentials;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link OpenSamlAuthenticationRequestFactory}
*/
public class OpenSamlAuthenticationRequestFactoryTests {
private OpenSamlAuthenticationRequestFactory factory;
private Saml2AuthenticationRequestContext.Builder contextBuilder;
private Saml2AuthenticationRequestContext context;
private RelyingPartyRegistration.Builder relyingPartyRegistrationBuilder;
private RelyingPartyRegistration relyingPartyRegistration;
private AuthnRequestUnmarshaller unmarshaller;
@BeforeEach
public void setUp() {
this.relyingPartyRegistrationBuilder = RelyingPartyRegistration.withRegistrationId("id")
.assertionConsumerServiceLocation("template")
.providerDetails((c) -> c.webSsoUrl("https://destination/sso"))
.providerDetails((c) -> c.entityId("remote-entity-id")).localEntityIdTemplate("local-entity-id")
.credentials((c) -> c.add(TestSaml2X509Credentials.relyingPartySigningCredential()));
this.relyingPartyRegistration = this.relyingPartyRegistrationBuilder.build();
this.contextBuilder = Saml2AuthenticationRequestContext.builder().issuer("https://issuer")
.relyingPartyRegistration(this.relyingPartyRegistration)
.assertionConsumerServiceUrl("https://issuer/sso");
this.context = this.contextBuilder.build();
this.factory = new OpenSamlAuthenticationRequestFactory();
this.unmarshaller = (AuthnRequestUnmarshaller) XMLObjectProviderRegistrySupport.getUnmarshallerFactory()
.getUnmarshaller(AuthnRequest.DEFAULT_ELEMENT_NAME);
}
@Test
public void createAuthenticationRequestWhenInvokingDeprecatedMethodThenReturnsXML() {
Saml2AuthenticationRequest request = Saml2AuthenticationRequest.withAuthenticationRequestContext(this.context)
.build();
String result = this.factory.createAuthenticationRequest(request);
assertThat(result.replace("\n", ""))
.startsWith("<?xml version=\"1.0\" encoding=\"UTF-8\"?><saml2p:AuthnRequest");
}
@Test
public void createRedirectAuthenticationRequestWhenUsingContextThenAllValuesAreSet() {
this.context = this.contextBuilder.relayState("Relay State Value").build();
Saml2RedirectAuthenticationRequest result = this.factory.createRedirectAuthenticationRequest(this.context);
assertThat(result.getSamlRequest()).isNotEmpty();
assertThat(result.getRelayState()).isEqualTo("Relay State Value");
assertThat(result.getSigAlg()).isNotEmpty();
assertThat(result.getSignature()).isNotEmpty();
assertThat(result.getBinding()).isEqualTo(Saml2MessageBinding.REDIRECT);
}
@Test
public void createRedirectAuthenticationRequestWhenNotSignRequestThenNoSignatureIsPresent() {
this.context = this.contextBuilder.relayState("Relay State Value")
.relyingPartyRegistration(
RelyingPartyRegistration.withRelyingPartyRegistration(this.relyingPartyRegistration)
.providerDetails((c) -> c.signAuthNRequest(false)).build())
.build();
Saml2RedirectAuthenticationRequest result = this.factory.createRedirectAuthenticationRequest(this.context);
assertThat(result.getSamlRequest()).isNotEmpty();
assertThat(result.getRelayState()).isEqualTo("Relay State Value");
assertThat(result.getSigAlg()).isNull();
assertThat(result.getSignature()).isNull();
assertThat(result.getBinding()).isEqualTo(Saml2MessageBinding.REDIRECT);
}
@Test
public void createRedirectAuthenticationRequestWhenSignRequestThenSignatureIsPresent() {
this.context = this.contextBuilder.relayState("Relay State Value")
.relyingPartyRegistration(this.relyingPartyRegistration).build();
Saml2RedirectAuthenticationRequest request = this.factory.createRedirectAuthenticationRequest(this.context);
assertThat(request.getRelayState()).isEqualTo("Relay State Value");
assertThat(request.getSigAlg()).isEqualTo(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
assertThat(request.getSignature()).isNotNull();
}
@Test
public void createRedirectAuthenticationRequestWhenSignRequestThenCredentialIsRequired() {
Saml2X509Credential credential = org.springframework.security.saml2.core.TestSaml2X509Credentials
.relyingPartyVerifyingCredential();
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.noCredentials()
.assertingPartyDetails((party) -> party.verificationX509Credentials((c) -> c.add(credential))).build();
this.context = this.contextBuilder.relayState("Relay State Value").relyingPartyRegistration(registration)
.build();
assertThatExceptionOfType(Saml2Exception.class)
.isThrownBy(() -> this.factory.createPostAuthenticationRequest(this.context));
}
@Test
public void createPostAuthenticationRequestWhenNotSignRequestThenNoSignatureIsPresent() {
this.context = this.contextBuilder.relayState("Relay State Value")
.relyingPartyRegistration(
RelyingPartyRegistration.withRelyingPartyRegistration(this.relyingPartyRegistration)
.providerDetails((c) -> c.signAuthNRequest(false)).build())
.build();
Saml2PostAuthenticationRequest result = this.factory.createPostAuthenticationRequest(this.context);
assertThat(result.getSamlRequest()).isNotEmpty();
assertThat(result.getRelayState()).isEqualTo("Relay State Value");
assertThat(result.getBinding()).isEqualTo(Saml2MessageBinding.POST);
assertThat(new String(Saml2Utils.samlDecode(result.getSamlRequest()), StandardCharsets.UTF_8))
.doesNotContain("ds:Signature");
}
@Test
public void createPostAuthenticationRequestWhenSignRequestThenSignatureIsPresent() {
this.context = this.contextBuilder.relayState("Relay State Value")
.relyingPartyRegistration(
RelyingPartyRegistration.withRelyingPartyRegistration(this.relyingPartyRegistration).build())
.build();
Saml2PostAuthenticationRequest result = this.factory.createPostAuthenticationRequest(this.context);
assertThat(result.getSamlRequest()).isNotEmpty();
assertThat(result.getRelayState()).isEqualTo("Relay State Value");
assertThat(result.getBinding()).isEqualTo(Saml2MessageBinding.POST);
assertThat(new String(Saml2Utils.samlDecode(result.getSamlRequest()), StandardCharsets.UTF_8))
.contains("ds:Signature");
}
@Test
public void createPostAuthenticationRequestWhenSignRequestThenCredentialIsRequired() {
Saml2X509Credential credential = org.springframework.security.saml2.core.TestSaml2X509Credentials
.relyingPartyVerifyingCredential();
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.noCredentials()
.assertingPartyDetails((party) -> party.verificationX509Credentials((c) -> c.add(credential))).build();
this.context = this.contextBuilder.relayState("Relay State Value").relyingPartyRegistration(registration)
.build();
assertThatExceptionOfType(Saml2Exception.class)
.isThrownBy(() -> this.factory.createPostAuthenticationRequest(this.context));
}
@Test
public void createAuthenticationRequestWhenDefaultThenReturnsPostBinding() {
AuthnRequest authn = getAuthNRequest(Saml2MessageBinding.POST);
Assertions.assertEquals(SAMLConstants.SAML2_POST_BINDING_URI, authn.getProtocolBinding());
}
@Test
public void createAuthenticationRequestWhenSetUriThenReturnsCorrectBinding() {
this.factory.setProtocolBinding(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
AuthnRequest authn = getAuthNRequest(Saml2MessageBinding.POST);
Assertions.assertEquals(SAMLConstants.SAML2_REDIRECT_BINDING_URI, authn.getProtocolBinding());
}
@Test
public void createAuthenticationRequestWhenSetUnsupportredUriThenThrowsIllegalArgumentException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.factory.setProtocolBinding("my-invalid-binding"))
.withMessageContaining("my-invalid-binding");
}
@Test
public void createPostAuthenticationRequestWhenAuthnRequestConsumerThenUses() {
Converter<Saml2AuthenticationRequestContext, AuthnRequest> authenticationRequestContextConverter = mock(
Converter.class);
given(authenticationRequestContextConverter.convert(this.context)).willReturn(authnRequest());
this.factory.setAuthenticationRequestContextConverter(authenticationRequestContextConverter);
this.factory.createPostAuthenticationRequest(this.context);
verify(authenticationRequestContextConverter).convert(this.context);
}
@Test
public void createRedirectAuthenticationRequestWhenAuthnRequestConsumerThenUses() {
Converter<Saml2AuthenticationRequestContext, AuthnRequest> authenticationRequestContextConverter = mock(
Converter.class);
given(authenticationRequestContextConverter.convert(this.context)).willReturn(authnRequest());
this.factory.setAuthenticationRequestContextConverter(authenticationRequestContextConverter);
this.factory.createRedirectAuthenticationRequest(this.context);
verify(authenticationRequestContextConverter).convert(this.context);
}
@Test
public void setAuthenticationRequestContextConverterWhenNullThenException() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> this.factory.setAuthenticationRequestContextConverter(null));
// @formatter:on
}
@Test
public void createPostAuthenticationRequestWhenAssertionConsumerServiceBindingThenUses() {
RelyingPartyRegistration relyingPartyRegistration = this.relyingPartyRegistrationBuilder
.assertionConsumerServiceBinding(Saml2MessageBinding.REDIRECT).build();
Saml2AuthenticationRequestContext context = this.contextBuilder
.relyingPartyRegistration(relyingPartyRegistration).build();
Saml2PostAuthenticationRequest request = this.factory.createPostAuthenticationRequest(context);
String samlRequest = request.getSamlRequest();
String inflated = new String(Saml2Utils.samlDecode(samlRequest));
assertThat(inflated).contains("ProtocolBinding=\"" + SAMLConstants.SAML2_REDIRECT_BINDING_URI + "\"");
}
@Test
public void createRedirectAuthenticationRequestWhenSHA1SignRequestThenSignatureIsPresent() {
RelyingPartyRegistration relyingPartyRegistration = this.relyingPartyRegistrationBuilder
.assertingPartyDetails(
(a) -> a.signingAlgorithms((algs) -> algs.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1)))
.build();
Saml2AuthenticationRequestContext context = this.contextBuilder.relayState("Relay State Value")
.relyingPartyRegistration(relyingPartyRegistration).build();
Saml2RedirectAuthenticationRequest result = this.factory.createRedirectAuthenticationRequest(context);
assertThat(result.getSamlRequest()).isNotEmpty();
assertThat(result.getRelayState()).isEqualTo("Relay State Value");
assertThat(result.getSigAlg()).isEqualTo(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
assertThat(result.getSignature()).isNotNull();
assertThat(result.getBinding()).isEqualTo(Saml2MessageBinding.REDIRECT);
}
private AuthnRequest authnRequest() {
AuthnRequest authnRequest = TestOpenSamlObjects.authnRequest();
authnRequest.setIssueInstant(DateTime.now());
return authnRequest;
}
private AuthnRequest getAuthNRequest(Saml2MessageBinding binding) {
AbstractSaml2AuthenticationRequest result = (binding == Saml2MessageBinding.REDIRECT)
? this.factory.createRedirectAuthenticationRequest(this.context)
: this.factory.createPostAuthenticationRequest(this.context);
String samlRequest = result.getSamlRequest();
assertThat(samlRequest).isNotEmpty();
if (result.getBinding() == Saml2MessageBinding.REDIRECT) {
samlRequest = Saml2Utils.samlInflate(Saml2Utils.samlDecode(samlRequest));
}
else {
samlRequest = new String(Saml2Utils.samlDecode(samlRequest), StandardCharsets.UTF_8);
}
try {
Document document = XMLObjectProviderRegistrySupport.getParserPool()
.parse(new ByteArrayInputStream(samlRequest.getBytes(StandardCharsets.UTF_8)));
Element element = document.getDocumentElement();
return (AuthnRequest) this.unmarshaller.unmarshall(element);
}
catch (Exception ex) {
throw new Saml2Exception(ex);
}
}
}

View File

@ -1,204 +0,0 @@
/*
* Copyright 2002-2022 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 org.springframework.security.saml2.provider.service.authentication;
import java.nio.charset.StandardCharsets;
import java.time.Clock;
import java.time.Instant;
import java.util.Map;
import java.util.UUID;
import org.opensaml.core.config.ConfigurationService;
import org.opensaml.core.xml.config.XMLObjectProviderRegistry;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.saml2.core.AuthnRequest;
import org.opensaml.saml.saml2.core.Issuer;
import org.opensaml.saml.saml2.core.NameIDPolicy;
import org.opensaml.saml.saml2.core.impl.AuthnRequestBuilder;
import org.opensaml.saml.saml2.core.impl.IssuerBuilder;
import org.opensaml.saml.saml2.core.impl.NameIDPolicyBuilder;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.saml2.core.OpenSamlInitializationService;
import org.springframework.security.saml2.core.Saml2ParameterNames;
import org.springframework.security.saml2.provider.service.authentication.OpenSamlSigningUtils.QueryParametersPartial;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* A {@link Saml2AuthenticationRequestFactory} that generates, signs, and serializes a
* SAML 2.0 AuthnRequest using OpenSAML 4
*
* @author Josh Cummings
* @since 5.5
* @deprecated Use
* {@link org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver}
* instead
*/
@Deprecated
public final class OpenSaml4AuthenticationRequestFactory implements Saml2AuthenticationRequestFactory {
static {
OpenSamlInitializationService.initialize();
}
private final AuthnRequestBuilder authnRequestBuilder;
private final IssuerBuilder issuerBuilder;
private final NameIDPolicyBuilder nameIdPolicyBuilder;
private Clock clock = Clock.systemUTC();
private Converter<Saml2AuthenticationRequestContext, AuthnRequest> authenticationRequestContextConverter;
/**
* Creates an {@link OpenSaml4AuthenticationRequestFactory}
*/
public OpenSaml4AuthenticationRequestFactory() {
this.authenticationRequestContextConverter = this::createAuthnRequest;
XMLObjectProviderRegistry registry = ConfigurationService.get(XMLObjectProviderRegistry.class);
this.authnRequestBuilder = (AuthnRequestBuilder) registry.getBuilderFactory()
.getBuilder(AuthnRequest.DEFAULT_ELEMENT_NAME);
this.issuerBuilder = (IssuerBuilder) registry.getBuilderFactory().getBuilder(Issuer.DEFAULT_ELEMENT_NAME);
this.nameIdPolicyBuilder = (NameIDPolicyBuilder) registry.getBuilderFactory()
.getBuilder(NameIDPolicy.DEFAULT_ELEMENT_NAME);
}
/**
* {@inheritDoc}
*/
@Override
@Deprecated
public String createAuthenticationRequest(Saml2AuthenticationRequest request) {
RelyingPartyRegistration registration = RelyingPartyRegistration.withRegistrationId("noId")
.assertionConsumerServiceBinding(Saml2MessageBinding.POST)
.assertionConsumerServiceLocation(request.getAssertionConsumerServiceUrl())
.entityId(request.getIssuer()).remoteIdpEntityId("noIssuer").idpWebSsoUrl("noUrl")
.credentials((credentials) -> credentials.addAll(request.getCredentials())).build();
Saml2AuthenticationRequestContext context = Saml2AuthenticationRequestContext.builder()
.relyingPartyRegistration(registration).issuer(request.getIssuer())
.assertionConsumerServiceUrl(request.getAssertionConsumerServiceUrl()).build();
AuthnRequest authnRequest = this.authenticationRequestContextConverter.convert(context);
return OpenSamlSigningUtils.serialize(OpenSamlSigningUtils.sign(authnRequest, registration));
}
/**
* {@inheritDoc}
*/
@Override
public Saml2PostAuthenticationRequest createPostAuthenticationRequest(Saml2AuthenticationRequestContext context) {
AuthnRequest authnRequest = this.authenticationRequestContextConverter.convert(context);
RelyingPartyRegistration registration = context.getRelyingPartyRegistration();
if (registration.getAssertingPartyDetails().getWantAuthnRequestsSigned()) {
OpenSamlSigningUtils.sign(authnRequest, registration);
}
String xml = OpenSamlSigningUtils.serialize(authnRequest);
return Saml2PostAuthenticationRequest.withAuthenticationRequestContext(context)
.samlRequest(Saml2Utils.samlEncode(xml.getBytes(StandardCharsets.UTF_8))).build();
}
/**
* {@inheritDoc}
*/
@Override
public Saml2RedirectAuthenticationRequest createRedirectAuthenticationRequest(
Saml2AuthenticationRequestContext context) {
AuthnRequest authnRequest = this.authenticationRequestContextConverter.convert(context);
RelyingPartyRegistration registration = context.getRelyingPartyRegistration();
String xml = OpenSamlSigningUtils.serialize(authnRequest);
Saml2RedirectAuthenticationRequest.Builder result = Saml2RedirectAuthenticationRequest
.withAuthenticationRequestContext(context);
String deflatedAndEncoded = Saml2Utils.samlEncode(Saml2Utils.samlDeflate(xml));
result.samlRequest(deflatedAndEncoded).relayState(context.getRelayState());
if (registration.getAssertingPartyDetails().getWantAuthnRequestsSigned()) {
QueryParametersPartial partial = OpenSamlSigningUtils.sign(registration)
.param(Saml2ParameterNames.SAML_REQUEST, deflatedAndEncoded);
if (StringUtils.hasText(context.getRelayState())) {
partial.param(Saml2ParameterNames.RELAY_STATE, context.getRelayState());
}
Map<String, String> parameters = partial.parameters();
return result.sigAlg(parameters.get(Saml2ParameterNames.SIG_ALG))
.signature(parameters.get(Saml2ParameterNames.SIGNATURE)).build();
}
return result.build();
}
private AuthnRequest createAuthnRequest(Saml2AuthenticationRequestContext context) {
String issuer = context.getIssuer();
String destination = context.getDestination();
String assertionConsumerServiceUrl = context.getAssertionConsumerServiceUrl();
String protocolBinding = context.getRelyingPartyRegistration().getAssertionConsumerServiceBinding().getUrn();
AuthnRequest auth = this.authnRequestBuilder.buildObject();
if (auth.getID() == null) {
auth.setID("ARQ" + UUID.randomUUID().toString().substring(1));
}
if (auth.getIssueInstant() == null) {
auth.setIssueInstant(Instant.now(this.clock));
}
if (auth.isForceAuthn() == null) {
auth.setForceAuthn(Boolean.FALSE);
}
if (auth.isPassive() == null) {
auth.setIsPassive(Boolean.FALSE);
}
if (auth.getProtocolBinding() == null) {
auth.setProtocolBinding(SAMLConstants.SAML2_POST_BINDING_URI);
}
auth.setProtocolBinding(protocolBinding);
if (auth.getNameIDPolicy() == null) {
setNameIdPolicy(auth, context.getRelyingPartyRegistration());
}
Issuer iss = this.issuerBuilder.buildObject();
iss.setValue(issuer);
auth.setIssuer(iss);
auth.setDestination(destination);
auth.setAssertionConsumerServiceURL(assertionConsumerServiceUrl);
return auth;
}
private void setNameIdPolicy(AuthnRequest authnRequest, RelyingPartyRegistration registration) {
if (!StringUtils.hasText(registration.getNameIdFormat())) {
return;
}
NameIDPolicy nameIdPolicy = this.nameIdPolicyBuilder.buildObject();
nameIdPolicy.setFormat(registration.getNameIdFormat());
authnRequest.setNameIDPolicy(nameIdPolicy);
}
/**
* Set the strategy for building an {@link AuthnRequest} from a given context
* @param authenticationRequestContextConverter the conversion strategy to use
*/
public void setAuthenticationRequestContextConverter(
Converter<Saml2AuthenticationRequestContext, AuthnRequest> authenticationRequestContextConverter) {
Assert.notNull(authenticationRequestContextConverter, "authenticationRequestContextConverter cannot be null");
this.authenticationRequestContextConverter = authenticationRequestContextConverter;
}
/**
* Use this {@link Clock} with {@link Instant#now()} for generating timestamps
* @param clock the {@link Clock} to use
*/
public void setClock(Clock clock) {
Assert.notNull(clock, "clock cannot be null");
this.clock = clock;
}
}

View File

@ -1,286 +0,0 @@
/*
* Copyright 2002-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 org.springframework.security.saml2.provider.service.authentication;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.saml2.core.AuthnRequest;
import org.opensaml.saml.saml2.core.impl.AuthnRequestUnmarshaller;
import org.opensaml.xmlsec.signature.support.SignatureConstants;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.springframework.core.convert.converter.Converter;
import org.springframework.security.saml2.Saml2Exception;
import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.credentials.TestSaml2X509Credentials;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/**
* Tests for {@link OpenSaml4AuthenticationRequestFactory}
*/
public class OpenSaml4AuthenticationRequestFactoryTests {
private OpenSaml4AuthenticationRequestFactory factory;
private Saml2AuthenticationRequestContext.Builder contextBuilder;
private Saml2AuthenticationRequestContext context;
private RelyingPartyRegistration.Builder relyingPartyRegistrationBuilder;
private RelyingPartyRegistration relyingPartyRegistration;
private AuthnRequestUnmarshaller unmarshaller;
@BeforeEach
public void setUp() {
this.relyingPartyRegistrationBuilder = RelyingPartyRegistration.withRegistrationId("id")
.assertionConsumerServiceLocation("template")
.providerDetails((c) -> c.webSsoUrl("https://destination/sso"))
.providerDetails((c) -> c.entityId("remote-entity-id")).localEntityIdTemplate("local-entity-id")
.credentials((c) -> c.add(TestSaml2X509Credentials.relyingPartySigningCredential()));
this.relyingPartyRegistration = this.relyingPartyRegistrationBuilder.build();
this.contextBuilder = Saml2AuthenticationRequestContext.builder().issuer("https://issuer")
.relyingPartyRegistration(this.relyingPartyRegistration)
.assertionConsumerServiceUrl("https://issuer/sso");
this.context = this.contextBuilder.build();
this.factory = new OpenSaml4AuthenticationRequestFactory();
this.unmarshaller = (AuthnRequestUnmarshaller) XMLObjectProviderRegistrySupport.getUnmarshallerFactory()
.getUnmarshaller(AuthnRequest.DEFAULT_ELEMENT_NAME);
}
@Test
public void createAuthenticationRequestWhenInvokingDeprecatedMethodThenReturnsXML() {
Saml2AuthenticationRequest request = Saml2AuthenticationRequest.withAuthenticationRequestContext(this.context)
.build();
String result = this.factory.createAuthenticationRequest(request);
assertThat(result.replace("\n", ""))
.startsWith("<?xml version=\"1.0\" encoding=\"UTF-8\"?><saml2p:AuthnRequest");
}
@Test
public void createRedirectAuthenticationRequestWhenUsingContextThenAllValuesAreSet() {
this.context = this.contextBuilder.relayState("Relay State Value").build();
Saml2RedirectAuthenticationRequest result = this.factory.createRedirectAuthenticationRequest(this.context);
assertThat(result.getSamlRequest()).isNotEmpty();
assertThat(result.getRelayState()).isEqualTo("Relay State Value");
assertThat(result.getSigAlg()).isNotEmpty();
assertThat(result.getSignature()).isNotEmpty();
assertThat(result.getBinding()).isEqualTo(Saml2MessageBinding.REDIRECT);
}
@Test
public void createRedirectAuthenticationRequestWhenNotSignRequestThenNoSignatureIsPresent() {
this.context = this.contextBuilder.relayState("Relay State Value")
.relyingPartyRegistration(
RelyingPartyRegistration.withRelyingPartyRegistration(this.relyingPartyRegistration)
.providerDetails((c) -> c.signAuthNRequest(false)).build())
.build();
Saml2RedirectAuthenticationRequest result = this.factory.createRedirectAuthenticationRequest(this.context);
assertThat(result.getSamlRequest()).isNotEmpty();
assertThat(result.getRelayState()).isEqualTo("Relay State Value");
assertThat(result.getSigAlg()).isNull();
assertThat(result.getSignature()).isNull();
assertThat(result.getBinding()).isEqualTo(Saml2MessageBinding.REDIRECT);
}
@Test
public void createRedirectAuthenticationRequestWhenSignRequestThenSignatureIsPresent() {
this.context = this.contextBuilder.relayState("Relay State Value")
.relyingPartyRegistration(this.relyingPartyRegistration).build();
Saml2RedirectAuthenticationRequest request = this.factory.createRedirectAuthenticationRequest(this.context);
assertThat(request.getRelayState()).isEqualTo("Relay State Value");
assertThat(request.getSigAlg()).isEqualTo(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA256);
assertThat(request.getSignature()).isNotNull();
}
@Test
public void createRedirectAuthenticationRequestWhenSignRequestThenCredentialIsRequired() {
Saml2X509Credential credential = org.springframework.security.saml2.core.TestSaml2X509Credentials
.relyingPartyVerifyingCredential();
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.noCredentials()
.assertingPartyDetails((party) -> party.verificationX509Credentials((c) -> c.add(credential))).build();
this.context = this.contextBuilder.relayState("Relay State Value").relyingPartyRegistration(registration)
.build();
assertThatExceptionOfType(Saml2Exception.class)
.isThrownBy(() -> this.factory.createPostAuthenticationRequest(this.context));
}
@Test
public void createPostAuthenticationRequestWhenNotSignRequestThenNoSignatureIsPresent() {
this.context = this.contextBuilder.relayState("Relay State Value")
.relyingPartyRegistration(
RelyingPartyRegistration.withRelyingPartyRegistration(this.relyingPartyRegistration)
.providerDetails((c) -> c.signAuthNRequest(false)).build())
.build();
Saml2PostAuthenticationRequest result = this.factory.createPostAuthenticationRequest(this.context);
assertThat(result.getSamlRequest()).isNotEmpty();
assertThat(result.getRelayState()).isEqualTo("Relay State Value");
assertThat(result.getBinding()).isEqualTo(Saml2MessageBinding.POST);
assertThat(new String(Saml2Utils.samlDecode(result.getSamlRequest()), StandardCharsets.UTF_8))
.doesNotContain("ds:Signature");
}
@Test
public void createPostAuthenticationRequestWhenSignRequestThenSignatureIsPresent() {
this.context = this.contextBuilder.relayState("Relay State Value")
.relyingPartyRegistration(
RelyingPartyRegistration.withRelyingPartyRegistration(this.relyingPartyRegistration).build())
.build();
Saml2PostAuthenticationRequest result = this.factory.createPostAuthenticationRequest(this.context);
assertThat(result.getSamlRequest()).isNotEmpty();
assertThat(result.getRelayState()).isEqualTo("Relay State Value");
assertThat(result.getBinding()).isEqualTo(Saml2MessageBinding.POST);
assertThat(new String(Saml2Utils.samlDecode(result.getSamlRequest()), StandardCharsets.UTF_8))
.contains("ds:Signature");
}
@Test
public void createPostAuthenticationRequestWhenSignRequestThenCredentialIsRequired() {
Saml2X509Credential credential = org.springframework.security.saml2.core.TestSaml2X509Credentials
.relyingPartyVerifyingCredential();
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.noCredentials()
.assertingPartyDetails((party) -> party.verificationX509Credentials((c) -> c.add(credential))).build();
this.context = this.contextBuilder.relayState("Relay State Value").relyingPartyRegistration(registration)
.build();
assertThatExceptionOfType(Saml2Exception.class)
.isThrownBy(() -> this.factory.createPostAuthenticationRequest(this.context));
}
@Test
public void createAuthenticationRequestWhenDefaultThenReturnsPostBinding() {
AuthnRequest authn = getAuthNRequest(Saml2MessageBinding.POST);
Assertions.assertEquals(SAMLConstants.SAML2_POST_BINDING_URI, authn.getProtocolBinding());
}
@Test
public void createPostAuthenticationRequestWhenAuthnRequestConsumerThenUses() {
Converter<Saml2AuthenticationRequestContext, AuthnRequest> authenticationRequestContextConverter = mock(
Converter.class);
given(authenticationRequestContextConverter.convert(this.context)).willReturn(authnRequest());
this.factory.setAuthenticationRequestContextConverter(authenticationRequestContextConverter);
this.factory.createPostAuthenticationRequest(this.context);
verify(authenticationRequestContextConverter).convert(this.context);
}
@Test
public void createRedirectAuthenticationRequestWhenAuthnRequestConsumerThenUses() {
Converter<Saml2AuthenticationRequestContext, AuthnRequest> authenticationRequestContextConverter = mock(
Converter.class);
given(authenticationRequestContextConverter.convert(this.context)).willReturn(authnRequest());
this.factory.setAuthenticationRequestContextConverter(authenticationRequestContextConverter);
this.factory.createRedirectAuthenticationRequest(this.context);
verify(authenticationRequestContextConverter).convert(this.context);
}
@Test
public void setAuthenticationRequestContextConverterWhenNullThenException() {
// @formatter:off
assertThatIllegalArgumentException()
.isThrownBy(() -> this.factory.setAuthenticationRequestContextConverter(null));
// @formatter:on
}
@Test
public void createPostAuthenticationRequestWhenAssertionConsumerServiceBindingThenUses() {
RelyingPartyRegistration relyingPartyRegistration = this.relyingPartyRegistrationBuilder
.assertionConsumerServiceBinding(Saml2MessageBinding.REDIRECT).build();
Saml2AuthenticationRequestContext context = this.contextBuilder
.relyingPartyRegistration(relyingPartyRegistration).build();
Saml2PostAuthenticationRequest request = this.factory.createPostAuthenticationRequest(context);
String samlRequest = request.getSamlRequest();
String inflated = new String(Saml2Utils.samlDecode(samlRequest));
assertThat(inflated).contains("ProtocolBinding=\"" + SAMLConstants.SAML2_REDIRECT_BINDING_URI + "\"");
}
@Test
public void createRedirectAuthenticationRequestWhenSHA1SignRequestThenSignatureIsPresent() {
RelyingPartyRegistration relyingPartyRegistration = this.relyingPartyRegistrationBuilder
.assertingPartyDetails(
(a) -> a.signingAlgorithms((algs) -> algs.add(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1)))
.build();
Saml2AuthenticationRequestContext context = this.contextBuilder.relayState("Relay State Value")
.relyingPartyRegistration(relyingPartyRegistration).build();
Saml2RedirectAuthenticationRequest result = this.factory.createRedirectAuthenticationRequest(context);
assertThat(result.getSamlRequest()).isNotEmpty();
assertThat(result.getRelayState()).isEqualTo("Relay State Value");
assertThat(result.getSigAlg()).isEqualTo(SignatureConstants.ALGO_ID_SIGNATURE_RSA_SHA1);
assertThat(result.getSignature()).isNotNull();
assertThat(result.getBinding()).isEqualTo(Saml2MessageBinding.REDIRECT);
}
@Test
public void createAuthenticationRequestWhenSetNameIDPolicyThenReturnsCorrectNameIDPolicy() {
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.full().nameIdFormat("format").build();
this.context = this.contextBuilder.relayState("Relay State Value").relyingPartyRegistration(registration)
.build();
AuthnRequest authn = getAuthNRequest(Saml2MessageBinding.POST);
assertThat(authn.getNameIDPolicy()).isNotNull();
assertThat(authn.getNameIDPolicy().getAllowCreate()).isFalse();
assertThat(authn.getNameIDPolicy().getFormat()).isEqualTo("format");
assertThat(authn.getNameIDPolicy().getSPNameQualifier()).isNull();
}
private AuthnRequest authnRequest() {
AuthnRequest authnRequest = TestOpenSamlObjects.authnRequest();
authnRequest.setIssueInstant(Instant.now());
return authnRequest;
}
private AuthnRequest getAuthNRequest(Saml2MessageBinding binding) {
AbstractSaml2AuthenticationRequest result = (binding == Saml2MessageBinding.REDIRECT)
? this.factory.createRedirectAuthenticationRequest(this.context)
: this.factory.createPostAuthenticationRequest(this.context);
String samlRequest = result.getSamlRequest();
assertThat(samlRequest).isNotEmpty();
if (result.getBinding() == Saml2MessageBinding.REDIRECT) {
samlRequest = Saml2Utils.samlInflate(Saml2Utils.samlDecode(samlRequest));
}
else {
samlRequest = new String(Saml2Utils.samlDecode(samlRequest), StandardCharsets.UTF_8);
}
try {
Document document = XMLObjectProviderRegistrySupport.getParserPool()
.parse(new ByteArrayInputStream(samlRequest.getBytes(StandardCharsets.UTF_8)));
Element element = document.getDocumentElement();
return (AuthnRequest) this.unmarshaller.unmarshall(element);
}
catch (Exception ex) {
throw new Saml2Exception(ex);
}
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2019 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -26,7 +26,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.security.converter.RsaKeyConverters; import org.springframework.security.converter.RsaKeyConverters;
import org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType; import org.springframework.security.saml2.core.Saml2X509Credential;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException; import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
@ -79,66 +79,66 @@ public class Saml2X509CredentialTests {
@Test @Test
public void constructorWhenRelyingPartyWithCredentialsThenItSucceeds() { public void constructorWhenRelyingPartyWithCredentialsThenItSucceeds() {
new Saml2X509Credential(this.key, this.certificate, Saml2X509CredentialType.SIGNING); new Saml2X509Credential(this.key, this.certificate, Saml2X509Credential.Saml2X509CredentialType.SIGNING);
new Saml2X509Credential(this.key, this.certificate, Saml2X509CredentialType.SIGNING, new Saml2X509Credential(this.key, this.certificate, Saml2X509Credential.Saml2X509CredentialType.SIGNING,
Saml2X509CredentialType.DECRYPTION); Saml2X509Credential.Saml2X509CredentialType.DECRYPTION);
new Saml2X509Credential(this.key, this.certificate, Saml2X509CredentialType.DECRYPTION); new Saml2X509Credential(this.key, this.certificate, Saml2X509Credential.Saml2X509CredentialType.DECRYPTION);
} }
@Test @Test
public void constructorWhenAssertingPartyWithCredentialsThenItSucceeds() { public void constructorWhenAssertingPartyWithCredentialsThenItSucceeds() {
new Saml2X509Credential(this.certificate, Saml2X509CredentialType.VERIFICATION); new Saml2X509Credential(this.certificate, Saml2X509Credential.Saml2X509CredentialType.VERIFICATION);
new Saml2X509Credential(this.certificate, Saml2X509CredentialType.VERIFICATION, new Saml2X509Credential(this.certificate, Saml2X509Credential.Saml2X509CredentialType.VERIFICATION,
Saml2X509CredentialType.ENCRYPTION); Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION);
new Saml2X509Credential(this.certificate, Saml2X509CredentialType.ENCRYPTION); new Saml2X509Credential(this.certificate, Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION);
} }
@Test @Test
public void constructorWhenRelyingPartyWithoutCredentialsThenItFails() { public void constructorWhenRelyingPartyWithoutCredentialsThenItFails() {
assertThatIllegalArgumentException().isThrownBy( assertThatIllegalArgumentException().isThrownBy(() -> new Saml2X509Credential(null, (X509Certificate) null,
() -> new Saml2X509Credential(null, (X509Certificate) null, Saml2X509CredentialType.SIGNING)); Saml2X509Credential.Saml2X509CredentialType.SIGNING));
} }
@Test @Test
public void constructorWhenRelyingPartyWithoutPrivateKeyThenItFails() { public void constructorWhenRelyingPartyWithoutPrivateKeyThenItFails() {
assertThatIllegalArgumentException() assertThatIllegalArgumentException().isThrownBy(() -> new Saml2X509Credential(null, this.certificate,
.isThrownBy(() -> new Saml2X509Credential(null, this.certificate, Saml2X509CredentialType.SIGNING)); Saml2X509Credential.Saml2X509CredentialType.SIGNING));
} }
@Test @Test
public void constructorWhenRelyingPartyWithoutCertificateThenItFails() { public void constructorWhenRelyingPartyWithoutCertificateThenItFails() {
assertThatIllegalArgumentException() assertThatIllegalArgumentException().isThrownBy(
.isThrownBy(() -> new Saml2X509Credential(this.key, null, Saml2X509CredentialType.SIGNING)); () -> new Saml2X509Credential(this.key, null, Saml2X509Credential.Saml2X509CredentialType.SIGNING));
} }
@Test @Test
public void constructorWhenAssertingPartyWithoutCertificateThenItFails() { public void constructorWhenAssertingPartyWithoutCertificateThenItFails() {
assertThatIllegalArgumentException() assertThatIllegalArgumentException()
.isThrownBy(() -> new Saml2X509Credential(null, Saml2X509CredentialType.SIGNING)); .isThrownBy(() -> new Saml2X509Credential(null, Saml2X509Credential.Saml2X509CredentialType.SIGNING));
} }
@Test @Test
public void constructorWhenRelyingPartyWithEncryptionUsageThenItFails() { public void constructorWhenRelyingPartyWithEncryptionUsageThenItFails() {
assertThatIllegalStateException().isThrownBy( assertThatIllegalStateException().isThrownBy(() -> new Saml2X509Credential(this.key, this.certificate,
() -> new Saml2X509Credential(this.key, this.certificate, Saml2X509CredentialType.ENCRYPTION)); Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION));
} }
@Test @Test
public void constructorWhenRelyingPartyWithVerificationUsageThenItFails() { public void constructorWhenRelyingPartyWithVerificationUsageThenItFails() {
assertThatIllegalStateException().isThrownBy( assertThatIllegalStateException().isThrownBy(() -> new Saml2X509Credential(this.key, this.certificate,
() -> new Saml2X509Credential(this.key, this.certificate, Saml2X509CredentialType.VERIFICATION)); Saml2X509Credential.Saml2X509CredentialType.VERIFICATION));
} }
@Test @Test
public void constructorWhenAssertingPartyWithSigningUsageThenItFails() { public void constructorWhenAssertingPartyWithSigningUsageThenItFails() {
assertThatIllegalStateException() assertThatIllegalStateException().isThrownBy(
.isThrownBy(() -> new Saml2X509Credential(this.certificate, Saml2X509CredentialType.SIGNING)); () -> new Saml2X509Credential(this.certificate, Saml2X509Credential.Saml2X509CredentialType.SIGNING));
} }
@Test @Test
public void constructorWhenAssertingPartyWithDecryptionUsageThenItFails() { public void constructorWhenAssertingPartyWithDecryptionUsageThenItFails() {
assertThatIllegalStateException() assertThatIllegalStateException().isThrownBy(() -> new Saml2X509Credential(this.certificate,
.isThrownBy(() -> new Saml2X509Credential(this.certificate, Saml2X509CredentialType.DECRYPTION)); Saml2X509Credential.Saml2X509CredentialType.DECRYPTION));
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -27,7 +27,7 @@ import java.security.cert.X509Certificate;
import org.opensaml.security.crypto.KeySupport; import org.opensaml.security.crypto.KeySupport;
import org.springframework.security.saml2.Saml2Exception; import org.springframework.security.saml2.Saml2Exception;
import org.springframework.security.saml2.credentials.Saml2X509Credential.Saml2X509CredentialType; import org.springframework.security.saml2.core.Saml2X509Credential;
public final class TestSaml2X509Credentials { public final class TestSaml2X509Credentials {
@ -35,28 +35,32 @@ public final class TestSaml2X509Credentials {
} }
public static Saml2X509Credential assertingPartySigningCredential() { public static Saml2X509Credential assertingPartySigningCredential() {
return new Saml2X509Credential(idpPrivateKey(), idpCertificate(), Saml2X509CredentialType.SIGNING); return new Saml2X509Credential(idpPrivateKey(), idpCertificate(),
Saml2X509Credential.Saml2X509CredentialType.SIGNING);
} }
public static Saml2X509Credential assertingPartyEncryptingCredential() { public static Saml2X509Credential assertingPartyEncryptingCredential() {
return new Saml2X509Credential(spCertificate(), Saml2X509CredentialType.ENCRYPTION); return new Saml2X509Credential(spCertificate(), Saml2X509Credential.Saml2X509CredentialType.ENCRYPTION);
} }
public static Saml2X509Credential assertingPartyPrivateCredential() { public static Saml2X509Credential assertingPartyPrivateCredential() {
return new Saml2X509Credential(idpPrivateKey(), idpCertificate(), Saml2X509CredentialType.SIGNING, return new Saml2X509Credential(idpPrivateKey(), idpCertificate(),
Saml2X509CredentialType.DECRYPTION); Saml2X509Credential.Saml2X509CredentialType.SIGNING,
Saml2X509Credential.Saml2X509CredentialType.DECRYPTION);
} }
public static Saml2X509Credential relyingPartyVerifyingCredential() { public static Saml2X509Credential relyingPartyVerifyingCredential() {
return new Saml2X509Credential(idpCertificate(), Saml2X509CredentialType.VERIFICATION); return new Saml2X509Credential(idpCertificate(), Saml2X509Credential.Saml2X509CredentialType.VERIFICATION);
} }
public static Saml2X509Credential relyingPartySigningCredential() { public static Saml2X509Credential relyingPartySigningCredential() {
return new Saml2X509Credential(spPrivateKey(), spCertificate(), Saml2X509CredentialType.SIGNING); return new Saml2X509Credential(spPrivateKey(), spCertificate(),
Saml2X509Credential.Saml2X509CredentialType.SIGNING);
} }
public static Saml2X509Credential relyingPartyDecryptingCredential() { public static Saml2X509Credential relyingPartyDecryptingCredential() {
return new Saml2X509Credential(spPrivateKey(), spCertificate(), Saml2X509CredentialType.DECRYPTION); return new Saml2X509Credential(spPrivateKey(), spCertificate(),
Saml2X509Credential.Saml2X509CredentialType.DECRYPTION);
} }
private static X509Certificate certificate(String cert) { private static X509Certificate certificate(String cert) {

View File

@ -1,66 +0,0 @@
/*
* Copyright 2002-2020 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 org.springframework.security.saml2.provider.service.authentication;
import java.util.UUID;
import org.junit.jupiter.api.Test;
import org.springframework.security.saml2.credentials.TestSaml2X509Credentials;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link Saml2AuthenticationRequestFactory} default interface methods
*/
public class Saml2AuthenticationRequestFactoryTests {
private RelyingPartyRegistration registration = RelyingPartyRegistration.withRegistrationId("id")
.assertionConsumerServiceUrlTemplate("template")
.providerDetails((c) -> c.webSsoUrl("https://example.com/destination"))
.providerDetails((c) -> c.entityId("remote-entity-id")).localEntityIdTemplate("local-entity-id")
.credentials((c) -> c.add(TestSaml2X509Credentials.relyingPartySigningCredential())).build();
@Test
public void createAuthenticationRequestParametersWhenRedirectDefaultIsUsedMessageIsDeflatedAndEncoded() {
final String value = "Test String: " + UUID.randomUUID().toString();
Saml2AuthenticationRequestFactory factory = (request) -> value;
Saml2AuthenticationRequestContext request = Saml2AuthenticationRequestContext.builder()
.relyingPartyRegistration(this.registration).issuer("https://example.com/issuer")
.assertionConsumerServiceUrl("https://example.com/acs-url").build();
Saml2RedirectAuthenticationRequest response = factory.createRedirectAuthenticationRequest(request);
String resultValue = response.getSamlRequest();
byte[] decoded = Saml2Utils.samlDecode(resultValue);
String inflated = Saml2Utils.samlInflate(decoded);
assertThat(inflated).isEqualTo(value);
}
@Test
public void createAuthenticationRequestParametersWhenPostDefaultIsUsedMessageIsEncoded() {
final String value = "Test String: " + UUID.randomUUID().toString();
Saml2AuthenticationRequestFactory factory = (request) -> value;
Saml2AuthenticationRequestContext request = Saml2AuthenticationRequestContext.builder()
.relyingPartyRegistration(this.registration).issuer("https://example.com/issuer")
.assertionConsumerServiceUrl("https://example.com/acs-url").build();
Saml2PostAuthenticationRequest response = factory.createPostAuthenticationRequest(request);
String resultValue = response.getSamlRequest();
byte[] decoded = Saml2Utils.samlDecode(resultValue);
assertThat(new String(decoded)).isEqualTo(value);
}
}

View File

@ -18,6 +18,7 @@ package org.springframework.security.saml2.provider.service.authentication;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
import org.springframework.util.SerializationUtils; import org.springframework.util.SerializationUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -48,8 +49,7 @@ class Saml2PostAuthenticationRequestTests {
private Saml2PostAuthenticationRequest.Builder getAuthenticationRequestBuilder() { private Saml2PostAuthenticationRequest.Builder getAuthenticationRequestBuilder() {
return Saml2PostAuthenticationRequest return Saml2PostAuthenticationRequest
.withAuthenticationRequestContext( .withRelyingPartyRegistration(TestRelyingPartyRegistrations.relyingPartyRegistration().build())
TestSaml2AuthenticationRequestContexts.authenticationRequestContext().build())
.samlRequest("request").authenticationRequestUri(IDP_SSO_URL); .samlRequest("request").authenticationRequestUri(IDP_SSO_URL);
} }

View File

@ -18,6 +18,7 @@ package org.springframework.security.saml2.provider.service.authentication;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
import org.springframework.util.SerializationUtils; import org.springframework.util.SerializationUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
@ -48,8 +49,7 @@ class Saml2RedirectAuthenticationRequestTests {
private Saml2RedirectAuthenticationRequest.Builder getAuthenticationRequestBuilder() { private Saml2RedirectAuthenticationRequest.Builder getAuthenticationRequestBuilder() {
return Saml2RedirectAuthenticationRequest return Saml2RedirectAuthenticationRequest
.withAuthenticationRequestContext( .withRelyingPartyRegistration(TestRelyingPartyRegistrations.relyingPartyRegistration().build())
TestSaml2AuthenticationRequestContexts.authenticationRequestContext().build())
.samlRequest("request").authenticationRequestUri(IDP_SSO_URL); .samlRequest("request").authenticationRequestUri(IDP_SSO_URL);
} }

View File

@ -1,35 +0,0 @@
/*
* Copyright 2002-2020 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 org.springframework.security.saml2.provider.service.authentication;
import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
/**
* Test {@link Saml2AuthenticationRequestContext}s
*/
public final class TestSaml2AuthenticationRequestContexts {
private TestSaml2AuthenticationRequestContexts() {
}
public static Saml2AuthenticationRequestContext.Builder authenticationRequestContext() {
return Saml2AuthenticationRequestContext.builder().relayState("relayState").issuer("issuer")
.relyingPartyRegistration(TestRelyingPartyRegistrations.relyingPartyRegistration().build())
.assertionConsumerServiceUrl("assertionConsumerServiceUrl");
}
}

View File

@ -40,31 +40,24 @@ public class RelyingPartyRegistrationTests {
private void compareRegistrations(RelyingPartyRegistration registration, RelyingPartyRegistration copy) { private void compareRegistrations(RelyingPartyRegistration registration, RelyingPartyRegistration copy) {
assertThat(copy.getRegistrationId()).isEqualTo(registration.getRegistrationId()).isEqualTo("simplesamlphp"); assertThat(copy.getRegistrationId()).isEqualTo(registration.getRegistrationId()).isEqualTo("simplesamlphp");
assertThat(copy.getProviderDetails().getEntityId()).isEqualTo(registration.getProviderDetails().getEntityId()) assertThat(copy.getAssertingPartyDetails().getEntityId())
.isEqualTo(copy.getAssertingPartyDetails().getEntityId())
.isEqualTo(registration.getAssertingPartyDetails().getEntityId()) .isEqualTo(registration.getAssertingPartyDetails().getEntityId())
.isEqualTo("https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/metadata.php"); .isEqualTo("https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/metadata.php");
assertThat(copy.getAssertionConsumerServiceUrlTemplate()) assertThat(copy.getAssertionConsumerServiceLocation())
.isEqualTo(registration.getAssertionConsumerServiceUrlTemplate())
.isEqualTo(copy.getAssertionConsumerServiceLocation())
.isEqualTo(registration.getAssertionConsumerServiceLocation()) .isEqualTo(registration.getAssertionConsumerServiceLocation())
.isEqualTo("{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI); .isEqualTo("{baseUrl}" + Saml2WebSsoAuthenticationFilter.DEFAULT_FILTER_PROCESSES_URI);
assertThat(copy.getCredentials()).containsAll(registration.getCredentials()) assertThat(copy.getSigningX509Credentials()).containsAll(registration.getSigningX509Credentials());
.containsExactly(registration.getCredentials().get(0), registration.getCredentials().get(1)); assertThat(copy.getDecryptionX509Credentials()).containsAll(registration.getDecryptionX509Credentials());
assertThat(copy.getLocalEntityIdTemplate()).isEqualTo(registration.getLocalEntityIdTemplate()) assertThat(copy.getEntityId()).isEqualTo(registration.getEntityId()).isEqualTo(copy.getEntityId())
.isEqualTo(copy.getEntityId()).isEqualTo(registration.getEntityId()) .isEqualTo(registration.getEntityId())
.isEqualTo("{baseUrl}/saml2/service-provider-metadata/{registrationId}"); .isEqualTo("{baseUrl}/saml2/service-provider-metadata/{registrationId}");
assertThat(copy.getProviderDetails().getWebSsoUrl()).isEqualTo(registration.getProviderDetails().getWebSsoUrl()) assertThat(copy.getAssertingPartyDetails().getSingleSignOnServiceLocation())
.isEqualTo(copy.getAssertingPartyDetails().getSingleSignOnServiceLocation())
.isEqualTo(registration.getAssertingPartyDetails().getSingleSignOnServiceLocation()) .isEqualTo(registration.getAssertingPartyDetails().getSingleSignOnServiceLocation())
.isEqualTo("https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/SSOService.php"); .isEqualTo("https://simplesaml-for-spring-saml.apps.pcfone.io/saml2/idp/SSOService.php");
assertThat(copy.getProviderDetails().getBinding()).isEqualTo(registration.getProviderDetails().getBinding()) assertThat(copy.getAssertingPartyDetails().getSingleSignOnServiceBinding())
.isEqualTo(copy.getAssertingPartyDetails().getSingleSignOnServiceBinding())
.isEqualTo(registration.getAssertingPartyDetails().getSingleSignOnServiceBinding()) .isEqualTo(registration.getAssertingPartyDetails().getSingleSignOnServiceBinding())
.isEqualTo(Saml2MessageBinding.POST); .isEqualTo(Saml2MessageBinding.POST);
assertThat(copy.getProviderDetails().isSignAuthNRequest()) assertThat(copy.getAssertingPartyDetails().getWantAuthnRequestsSigned())
.isEqualTo(registration.getProviderDetails().isSignAuthNRequest())
.isEqualTo(copy.getAssertingPartyDetails().getWantAuthnRequestsSigned())
.isEqualTo(registration.getAssertingPartyDetails().getWantAuthnRequestsSigned()).isFalse(); .isEqualTo(registration.getAssertingPartyDetails().getWantAuthnRequestsSigned()).isFalse();
assertThat(copy.getAssertionConsumerServiceBinding()) assertThat(copy.getAssertionConsumerServiceBinding())
.isEqualTo(registration.getAssertionConsumerServiceBinding()); .isEqualTo(registration.getAssertionConsumerServiceBinding());

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2022 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -16,7 +16,7 @@
package org.springframework.security.saml2.provider.service.registration; package org.springframework.security.saml2.provider.service.registration;
import org.springframework.security.saml2.credentials.Saml2X509Credential; import org.springframework.security.saml2.core.Saml2X509Credential;
import org.springframework.security.saml2.credentials.TestSaml2X509Credentials; import org.springframework.security.saml2.credentials.TestSaml2X509Credentials;
import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter; import org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter;
@ -40,9 +40,10 @@ public final class TestRelyingPartyRegistrations {
String singleLogoutServiceLocation = "{baseUrl}/logout/saml2/slo"; String singleLogoutServiceLocation = "{baseUrl}/logout/saml2/slo";
return RelyingPartyRegistration.withRegistrationId(registrationId).entityId(rpEntityId) return RelyingPartyRegistration.withRegistrationId(registrationId).entityId(rpEntityId)
.assertionConsumerServiceLocation(assertionConsumerServiceLocation) .assertionConsumerServiceLocation(assertionConsumerServiceLocation)
.singleLogoutServiceLocation(singleLogoutServiceLocation).credentials((c) -> c.add(signingCredential)) .singleLogoutServiceLocation(singleLogoutServiceLocation)
.providerDetails((c) -> c.entityId(apEntityId).webSsoUrl(singleSignOnServiceLocation)) .signingX509Credentials((c) -> c.add(signingCredential)).assertingPartyDetails(
.credentials((c) -> c.add(verificationCertificate)); (a) -> a.entityId(apEntityId).singleSignOnServiceLocation(singleSignOnServiceLocation)
.verificationX509Credentials((c) -> c.add(verificationCertificate)));
} }
public static RelyingPartyRegistration.Builder noCredentials() { public static RelyingPartyRegistration.Builder noCredentials() {

View File

@ -31,23 +31,14 @@ import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.saml2.credentials.TestSaml2X509Credentials; import org.springframework.security.saml2.credentials.TestSaml2X509Credentials;
import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.AbstractSaml2AuthenticationRequest;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestContext;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestFactory;
import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.Saml2PostAuthenticationRequest;
import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest; import org.springframework.security.saml2.provider.service.authentication.Saml2RedirectAuthenticationRequest;
import org.springframework.security.saml2.provider.service.authentication.TestSaml2AuthenticationRequestContexts;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; 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.RelyingPartyRegistrationRepository;
import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding; import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations; import org.springframework.security.saml2.provider.service.registration.TestRelyingPartyRegistrations;
import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.DefaultSaml2AuthenticationRequestContextResolver;
import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestContextResolver;
import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository; import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationRequestRepository;
import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver; import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.web.util.HtmlUtils; import org.springframework.web.util.HtmlUtils;
import org.springframework.web.util.UriUtils; import org.springframework.web.util.UriUtils;
@ -58,7 +49,6 @@ import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
public class Saml2WebSsoAuthenticationRequestFilterTests { public class Saml2WebSsoAuthenticationRequestFilterTests {
@ -68,10 +58,6 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
private RelyingPartyRegistrationRepository repository = mock(RelyingPartyRegistrationRepository.class); private RelyingPartyRegistrationRepository repository = mock(RelyingPartyRegistrationRepository.class);
private Saml2AuthenticationRequestFactory factory = mock(Saml2AuthenticationRequestFactory.class);
private Saml2AuthenticationRequestContextResolver resolver = mock(Saml2AuthenticationRequestContextResolver.class);
private Saml2AuthenticationRequestResolver authenticationRequestResolver = mock( private Saml2AuthenticationRequestResolver authenticationRequestResolver = mock(
Saml2AuthenticationRequestResolver.class); Saml2AuthenticationRequestResolver.class);
@ -88,7 +74,7 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
@BeforeEach @BeforeEach
public void setup() { public void setup() {
this.filter = new Saml2WebSsoAuthenticationRequestFilter(this.resolver, this.factory); this.filter = new Saml2WebSsoAuthenticationRequestFilter(this.authenticationRequestResolver);
this.request = new MockHttpServletRequest(); this.request = new MockHttpServletRequest();
this.response = new MockHttpServletResponse(); this.response = new MockHttpServletResponse();
this.request.setPathInfo("/saml2/authenticate/registration-id"); this.request.setPathInfo("/saml2/authenticate/registration-id");
@ -99,30 +85,26 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
} }
}; };
this.rpBuilder = RelyingPartyRegistration.withRegistrationId("registration-id") this.rpBuilder = RelyingPartyRegistration.withRegistrationId("registration-id")
.providerDetails((c) -> c.entityId("idp-entity-id")).providerDetails((c) -> c.webSsoUrl(IDP_SSO_URL)) .assertingPartyDetails((c) -> c.entityId("idp-entity-id"))
.assertionConsumerServiceUrlTemplate("template") .assertingPartyDetails((c) -> c.singleSignOnServiceLocation(IDP_SSO_URL))
.credentials((c) -> c.add(TestSaml2X509Credentials.assertingPartyPrivateCredential())); .assertionConsumerServiceLocation("template")
.signingX509Credentials((c) -> c.add(TestSaml2X509Credentials.assertingPartyPrivateCredential()))
.decryptionX509Credentials((c) -> c.add(TestSaml2X509Credentials.assertingPartyPrivateCredential()));
this.filter.setAuthenticationRequestRepository(this.authenticationRequestRepository); this.filter.setAuthenticationRequestRepository(this.authenticationRequestRepository);
} }
@Test @Test
public void doFilterWhenNoRelayStateThenRedirectDoesNotContainParameter() throws ServletException, IOException { public void doFilterWhenNoRelayStateThenRedirectDoesNotContainParameter() throws ServletException, IOException {
Saml2AuthenticationRequestContext context = authenticationRequestContext().relayState(null).build(); Saml2RedirectAuthenticationRequest request = redirectAuthenticationRequest().build();
Saml2RedirectAuthenticationRequest request = redirectAuthenticationRequest(context).build(); given(this.authenticationRequestResolver.resolve(any())).willReturn(request);
given(this.resolver.resolve(any())).willReturn(context);
given(this.factory.createRedirectAuthenticationRequest(any())).willReturn(request);
this.filter.doFilterInternal(this.request, this.response, this.filterChain); this.filter.doFilterInternal(this.request, this.response, this.filterChain);
assertThat(this.response.getHeader("Location")).doesNotContain("RelayState=").startsWith(IDP_SSO_URL); assertThat(this.response.getHeader("Location")).doesNotContain("RelayState=").startsWith(IDP_SSO_URL);
} }
private static Saml2AuthenticationRequestContext.Builder authenticationRequestContext() { private static Saml2RedirectAuthenticationRequest.Builder redirectAuthenticationRequest() {
return TestSaml2AuthenticationRequestContexts.authenticationRequestContext(); return Saml2RedirectAuthenticationRequest
} .withRelyingPartyRegistration(TestRelyingPartyRegistrations.relyingPartyRegistration().build())
.samlRequest("request").authenticationRequestUri(IDP_SSO_URL);
private static Saml2RedirectAuthenticationRequest.Builder redirectAuthenticationRequest(
Saml2AuthenticationRequestContext context) {
return Saml2RedirectAuthenticationRequest.withAuthenticationRequestContext(context).samlRequest("request")
.authenticationRequestUri(IDP_SSO_URL);
} }
private static Saml2RedirectAuthenticationRequest.Builder redirectAuthenticationRequest( private static Saml2RedirectAuthenticationRequest.Builder redirectAuthenticationRequest(
@ -131,18 +113,16 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
.authenticationRequestUri(IDP_SSO_URL); .authenticationRequestUri(IDP_SSO_URL);
} }
private static Saml2PostAuthenticationRequest.Builder postAuthenticationRequest( private static Saml2PostAuthenticationRequest.Builder postAuthenticationRequest() {
Saml2AuthenticationRequestContext context) { return Saml2PostAuthenticationRequest
return Saml2PostAuthenticationRequest.withAuthenticationRequestContext(context).samlRequest("request") .withRelyingPartyRegistration(TestRelyingPartyRegistrations.relyingPartyRegistration().build())
.authenticationRequestUri(IDP_SSO_URL); .samlRequest("request").authenticationRequestUri(IDP_SSO_URL);
} }
@Test @Test
public void doFilterWhenRelayStateThenRedirectDoesContainParameter() throws ServletException, IOException { public void doFilterWhenRelayStateThenRedirectDoesContainParameter() throws ServletException, IOException {
Saml2AuthenticationRequestContext context = authenticationRequestContext().build(); Saml2RedirectAuthenticationRequest request = redirectAuthenticationRequest().relayState("relayState").build();
Saml2RedirectAuthenticationRequest request = redirectAuthenticationRequest(context).build(); given(this.authenticationRequestResolver.resolve(any())).willReturn(request);
given(this.resolver.resolve(any())).willReturn(context);
given(this.factory.createRedirectAuthenticationRequest(any())).willReturn(request);
this.filter.doFilterInternal(this.request, this.response, this.filterChain); this.filter.doFilterInternal(this.request, this.response, this.filterChain);
assertThat(this.response.getHeader("Location")).contains("RelayState=relayState").startsWith(IDP_SSO_URL); assertThat(this.response.getHeader("Location")).contains("RelayState=relayState").startsWith(IDP_SSO_URL);
} }
@ -151,10 +131,9 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
public void doFilterWhenRelayStateThatRequiresEncodingThenRedirectDoesContainsEncodedParameter() throws Exception { public void doFilterWhenRelayStateThatRequiresEncodingThenRedirectDoesContainsEncodedParameter() throws Exception {
String relayStateValue = "https://my-relay-state.example.com?with=param&other=param"; String relayStateValue = "https://my-relay-state.example.com?with=param&other=param";
String relayStateEncoded = UriUtils.encode(relayStateValue, StandardCharsets.ISO_8859_1); String relayStateEncoded = UriUtils.encode(relayStateValue, StandardCharsets.ISO_8859_1);
Saml2AuthenticationRequestContext context = authenticationRequestContext().relayState(relayStateValue).build(); Saml2RedirectAuthenticationRequest request = redirectAuthenticationRequest().relayState(relayStateValue)
Saml2RedirectAuthenticationRequest request = redirectAuthenticationRequest(context).build(); .build();
given(this.resolver.resolve(any())).willReturn(context); given(this.authenticationRequestResolver.resolve(any())).willReturn(request);
given(this.factory.createRedirectAuthenticationRequest(any())).willReturn(request);
this.filter.doFilterInternal(this.request, this.response, this.filterChain); this.filter.doFilterInternal(this.request, this.response, this.filterChain);
assertThat(this.response.getHeader("Location")).contains("RelayState=" + relayStateEncoded) assertThat(this.response.getHeader("Location")).contains("RelayState=" + relayStateEncoded)
.startsWith(IDP_SSO_URL); .startsWith(IDP_SSO_URL);
@ -162,11 +141,9 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
@Test @Test
public void doFilterWhenSimpleSignatureSpecifiedThenSignatureParametersAreInTheRedirectURL() throws Exception { public void doFilterWhenSimpleSignatureSpecifiedThenSignatureParametersAreInTheRedirectURL() throws Exception {
Saml2AuthenticationRequestContext context = authenticationRequestContext().build(); Saml2RedirectAuthenticationRequest request = redirectAuthenticationRequest().sigAlg("sigalg")
Saml2RedirectAuthenticationRequest request = redirectAuthenticationRequest(context).sigAlg("sigalg")
.signature("signature").build(); .signature("signature").build();
given(this.resolver.resolve(any())).willReturn(context); given(this.authenticationRequestResolver.resolve(any())).willReturn(request);
given(this.factory.createRedirectAuthenticationRequest(any())).willReturn(request);
this.filter.doFilterInternal(this.request, this.response, this.filterChain); this.filter.doFilterInternal(this.request, this.response, this.filterChain);
assertThat(this.response.getHeader("Location")).contains("SigAlg=").contains("Signature=") assertThat(this.response.getHeader("Location")).contains("SigAlg=").contains("Signature=")
.startsWith(IDP_SSO_URL); .startsWith(IDP_SSO_URL);
@ -174,10 +151,8 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
@Test @Test
public void doFilterWhenSignatureIsDisabledThenSignatureParametersAreNotInTheRedirectURL() throws Exception { public void doFilterWhenSignatureIsDisabledThenSignatureParametersAreNotInTheRedirectURL() throws Exception {
Saml2AuthenticationRequestContext context = authenticationRequestContext().build(); Saml2RedirectAuthenticationRequest request = redirectAuthenticationRequest().build();
Saml2RedirectAuthenticationRequest request = redirectAuthenticationRequest(context).build(); given(this.authenticationRequestResolver.resolve(any())).willReturn(request);
given(this.resolver.resolve(any())).willReturn(context);
given(this.factory.createRedirectAuthenticationRequest(any())).willReturn(request);
this.filter.doFilterInternal(this.request, this.response, this.filterChain); this.filter.doFilterInternal(this.request, this.response, this.filterChain);
assertThat(this.response.getHeader("Location")).doesNotContain("SigAlg=").doesNotContain("Signature=") assertThat(this.response.getHeader("Location")).doesNotContain("SigAlg=").doesNotContain("Signature=")
.startsWith(IDP_SSO_URL); .startsWith(IDP_SSO_URL);
@ -190,11 +165,9 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
RelyingPartyRegistration registration = this.rpBuilder RelyingPartyRegistration registration = this.rpBuilder
.assertingPartyDetails((asserting) -> asserting.singleSignOnServiceBinding(Saml2MessageBinding.POST)) .assertingPartyDetails((asserting) -> asserting.singleSignOnServiceBinding(Saml2MessageBinding.POST))
.build(); .build();
Saml2AuthenticationRequestContext context = authenticationRequestContext().relayState(relayStateValue) Saml2PostAuthenticationRequest request = Saml2PostAuthenticationRequest
.relyingPartyRegistration(registration).build(); .withRelyingPartyRegistration(registration).samlRequest("request").relayState(relayStateValue).build();
Saml2PostAuthenticationRequest request = postAuthenticationRequest(context).build(); given(this.authenticationRequestResolver.resolve(any())).willReturn(request);
given(this.resolver.resolve(any())).willReturn(context);
given(this.factory.createPostAuthenticationRequest(any())).willReturn(request);
this.filter.doFilterInternal(this.request, this.response, this.filterChain); this.filter.doFilterInternal(this.request, this.response, this.filterChain);
assertThat(this.response.getHeader("Location")).isNull(); assertThat(this.response.getHeader("Location")).isNull();
assertThat(this.response.getContentAsString()) assertThat(this.response.getContentAsString())
@ -203,62 +176,25 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
.contains("value=\"" + relayStateEncoded + "\""); .contains("value=\"" + relayStateEncoded + "\"");
} }
@Test
public void doFilterWhenSetAuthenticationRequestFactoryThenUses() throws Exception {
Saml2AuthenticationRequestContext context = authenticationRequestContext().build();
Saml2RedirectAuthenticationRequest authenticationRequest = redirectAuthenticationRequest(context).build();
Saml2AuthenticationRequestFactory factory = mock(Saml2AuthenticationRequestFactory.class);
given(this.resolver.resolve(any())).willReturn(context);
given(factory.createRedirectAuthenticationRequest(any())).willReturn(authenticationRequest);
this.filter.setAuthenticationRequestFactory(factory);
this.filter.doFilterInternal(this.request, this.response, this.filterChain);
verify(factory).createRedirectAuthenticationRequest(any());
}
@Test
public void setRequestMatcherWhenNullThenException() {
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter(this.resolver,
this.factory);
assertThatIllegalArgumentException().isThrownBy(() -> filter.setRedirectMatcher(null));
}
@Test
public void setAuthenticationRequestFactoryWhenNullThenException() {
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter(this.resolver,
this.factory);
assertThatIllegalArgumentException().isThrownBy(() -> filter.setAuthenticationRequestFactory(null));
}
@Test
public void doFilterWhenRequestMatcherFailsThenSkipsFilter() throws Exception {
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter(this.resolver,
this.factory);
filter.setRedirectMatcher((request) -> false);
filter.doFilter(this.request, this.response, this.filterChain);
verifyNoInteractions(this.resolver, this.factory);
}
@Test @Test
public void doFilterWhenRelyingPartyRegistrationNotFoundThenUnauthorized() throws Exception { public void doFilterWhenRelyingPartyRegistrationNotFoundThenUnauthorized() throws Exception {
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter(this.resolver, Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter(
this.factory); this.authenticationRequestResolver);
filter.doFilter(this.request, this.response, this.filterChain); filter.doFilter(this.request, this.response, this.filterChain);
assertThat(this.response.getStatus()).isEqualTo(401); assertThat(this.response.getStatus()).isEqualTo(401);
} }
@Test @Test
public void setAuthenticationRequestRepositoryWhenNullThenException() { public void setAuthenticationRequestRepositoryWhenNullThenException() {
Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter(this.resolver, Saml2WebSsoAuthenticationRequestFilter filter = new Saml2WebSsoAuthenticationRequestFilter(
this.factory); this.authenticationRequestResolver);
assertThatIllegalArgumentException().isThrownBy(() -> filter.setAuthenticationRequestRepository(null)); assertThatIllegalArgumentException().isThrownBy(() -> filter.setAuthenticationRequestRepository(null));
} }
@Test @Test
public void doFilterWhenRedirectThenSaveRedirectRequest() throws ServletException, IOException { public void doFilterWhenRedirectThenSaveRedirectRequest() throws ServletException, IOException {
Saml2AuthenticationRequestContext context = authenticationRequestContext().build(); Saml2RedirectAuthenticationRequest request = redirectAuthenticationRequest().build();
Saml2RedirectAuthenticationRequest request = redirectAuthenticationRequest(context).build(); given(this.authenticationRequestResolver.resolve(any())).willReturn(request);
given(this.resolver.resolve(any())).willReturn(context);
given(this.factory.createRedirectAuthenticationRequest(any())).willReturn(request);
this.filter.doFilterInternal(this.request, this.response, this.filterChain); this.filter.doFilterInternal(this.request, this.response, this.filterChain);
verify(this.authenticationRequestRepository).saveAuthenticationRequest( verify(this.authenticationRequestRepository).saveAuthenticationRequest(
any(Saml2RedirectAuthenticationRequest.class), eq(this.request), eq(this.response)); any(Saml2RedirectAuthenticationRequest.class), eq(this.request), eq(this.response));
@ -269,41 +205,14 @@ public class Saml2WebSsoAuthenticationRequestFilterTests {
RelyingPartyRegistration registration = this.rpBuilder RelyingPartyRegistration registration = this.rpBuilder
.assertingPartyDetails((asserting) -> asserting.singleSignOnServiceBinding(Saml2MessageBinding.POST)) .assertingPartyDetails((asserting) -> asserting.singleSignOnServiceBinding(Saml2MessageBinding.POST))
.build(); .build();
Saml2AuthenticationRequestContext context = authenticationRequestContext() Saml2PostAuthenticationRequest request = Saml2PostAuthenticationRequest
.relyingPartyRegistration(registration).build(); .withRelyingPartyRegistration(registration).samlRequest("request").build();
Saml2PostAuthenticationRequest request = postAuthenticationRequest(context).build(); given(this.authenticationRequestResolver.resolve(any())).willReturn(request);
given(this.resolver.resolve(any())).willReturn(context);
given(this.factory.createPostAuthenticationRequest(any())).willReturn(request);
this.filter.doFilterInternal(this.request, this.response, this.filterChain); this.filter.doFilterInternal(this.request, this.response, this.filterChain);
verify(this.authenticationRequestRepository).saveAuthenticationRequest( verify(this.authenticationRequestRepository).saveAuthenticationRequest(
any(Saml2PostAuthenticationRequest.class), eq(this.request), eq(this.response)); any(Saml2PostAuthenticationRequest.class), eq(this.request), eq(this.response));
} }
@Test
public void doFilterWhenPathStartsWithRegistrationIdThenPosts() throws Exception {
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.full()
.assertingPartyDetails((party) -> party.singleSignOnServiceBinding(Saml2MessageBinding.POST)).build();
RequestMatcher matcher = new AntPathRequestMatcher("/{registrationId}/saml2/authenticate");
DefaultRelyingPartyRegistrationResolver delegate = new DefaultRelyingPartyRegistrationResolver(this.repository);
RelyingPartyRegistrationResolver resolver = (request, id) -> {
String registrationId = matcher.matcher(request).getVariables().get("registrationId");
return delegate.resolve(request, registrationId);
};
Saml2AuthenticationRequestContextResolver authenticationRequestContextResolver = new DefaultSaml2AuthenticationRequestContextResolver(
resolver);
Saml2PostAuthenticationRequest authenticationRequest = mock(Saml2PostAuthenticationRequest.class);
given(authenticationRequest.getAuthenticationRequestUri()).willReturn("uri");
given(authenticationRequest.getRelayState()).willReturn("relay");
given(authenticationRequest.getSamlRequest()).willReturn("saml");
given(this.repository.findByRegistrationId("registration-id")).willReturn(registration);
given(this.factory.createPostAuthenticationRequest(any())).willReturn(authenticationRequest);
this.filter = new Saml2WebSsoAuthenticationRequestFilter(authenticationRequestContextResolver, this.factory);
this.filter.setRedirectMatcher(matcher);
this.request.setPathInfo("/registration-id/saml2/authenticate");
this.filter.doFilter(this.request, this.response, new MockFilterChain());
verify(this.repository).findByRegistrationId("registration-id");
}
@Test @Test
public void doFilterWhenCustomAuthenticationRequestResolverThenUses() throws Exception { public void doFilterWhenCustomAuthenticationRequestResolverThenUses() throws Exception {
RelyingPartyRegistration registration = TestRelyingPartyRegistrations.relyingPartyRegistration().build(); RelyingPartyRegistration registration = TestRelyingPartyRegistrations.relyingPartyRegistration().build();

View File

@ -1,104 +0,0 @@
/*
* Copyright 2002-2020 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 org.springframework.security.saml2.provider.service.web;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.security.saml2.core.Saml2ParameterNames;
import org.springframework.security.saml2.credentials.TestSaml2X509Credentials;
import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationRequestContext;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
/**
* Tests for {@link DefaultSaml2AuthenticationRequestContextResolver}
*
* @author Shazin Sadakath
* @author Josh Cummings
*/
public class DefaultSaml2AuthenticationRequestContextResolverTests {
private static final String ASSERTING_PARTY_SSO_URL = "https://idp.example.com/sso";
private static final String RELYING_PARTY_SSO_URL = "https://sp.example.com/sso";
private static final String ASSERTING_PARTY_ENTITY_ID = "asserting-party-entity-id";
private static final String RELYING_PARTY_ENTITY_ID = "relying-party-entity-id";
private static final String REGISTRATION_ID = "registration-id";
private MockHttpServletRequest request;
private RelyingPartyRegistration.Builder relyingPartyBuilder;
private RelyingPartyRegistrationResolver relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver(
(id) -> this.relyingPartyBuilder.build());
private Saml2AuthenticationRequestContextResolver authenticationRequestContextResolver = new DefaultSaml2AuthenticationRequestContextResolver(
this.relyingPartyRegistrationResolver);
@BeforeEach
public void setup() {
this.request = new MockHttpServletRequest();
this.request.setPathInfo("/saml2/authenticate/registration-id");
this.relyingPartyBuilder = RelyingPartyRegistration.withRegistrationId(REGISTRATION_ID)
.localEntityIdTemplate(RELYING_PARTY_ENTITY_ID)
.providerDetails((c) -> c.entityId(ASSERTING_PARTY_ENTITY_ID))
.providerDetails((c) -> c.webSsoUrl(ASSERTING_PARTY_SSO_URL))
.assertionConsumerServiceUrlTemplate(RELYING_PARTY_SSO_URL)
.credentials((c) -> c.add(TestSaml2X509Credentials.relyingPartyVerifyingCredential()));
}
@Test
public void resolveWhenRequestAndRelyingPartyNotNullThenCreateSaml2AuthenticationRequestContext() {
this.request.addParameter(Saml2ParameterNames.RELAY_STATE, "relay-state");
Saml2AuthenticationRequestContext context = this.authenticationRequestContextResolver.resolve(this.request);
assertThat(context).isNotNull();
assertThat(context.getAssertionConsumerServiceUrl()).isEqualTo(RELYING_PARTY_SSO_URL);
assertThat(context.getRelayState()).isEqualTo("relay-state");
assertThat(context.getDestination()).isEqualTo(ASSERTING_PARTY_SSO_URL);
assertThat(context.getIssuer()).isEqualTo(RELYING_PARTY_ENTITY_ID);
assertThat(context.getRelyingPartyRegistration().getRegistrationId())
.isSameAs(this.relyingPartyBuilder.build().getRegistrationId());
}
@Test
public void resolveWhenAssertionConsumerServiceUrlTemplateContainsRegistrationIdThenResolves() {
this.relyingPartyBuilder.assertionConsumerServiceLocation("/saml2/authenticate/{registrationId}");
Saml2AuthenticationRequestContext context = this.authenticationRequestContextResolver.resolve(this.request);
assertThat(context.getAssertionConsumerServiceUrl()).isEqualTo("/saml2/authenticate/registration-id");
}
@Test
public void resolveWhenAssertionConsumerServiceUrlTemplateContainsBaseUrlThenResolves() {
this.relyingPartyBuilder.assertionConsumerServiceLocation("{baseUrl}/saml2/authenticate/{registrationId}");
Saml2AuthenticationRequestContext context = this.authenticationRequestContextResolver.resolve(this.request);
assertThat(context.getAssertionConsumerServiceUrl())
.isEqualTo("http://localhost/saml2/authenticate/registration-id");
}
@Test
public void resolveWhenRelyingPartyNullThenException() {
assertThatIllegalArgumentException().isThrownBy(() -> this.authenticationRequestContextResolver.resolve(null));
}
}

View File

@ -25,7 +25,6 @@ import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension; import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.ClassPathResource;
import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ErrorCodes;
@ -50,7 +49,7 @@ import static org.mockito.Mockito.mock;
public class Saml2AuthenticationTokenConverterTests { public class Saml2AuthenticationTokenConverterTests {
@Mock @Mock
Converter<HttpServletRequest, RelyingPartyRegistration> relyingPartyRegistrationResolver; RelyingPartyRegistrationResolver relyingPartyRegistrationResolver;
RelyingPartyRegistration relyingPartyRegistration = TestRelyingPartyRegistrations.relyingPartyRegistration() RelyingPartyRegistration relyingPartyRegistration = TestRelyingPartyRegistrations.relyingPartyRegistration()
.build(); .build();
@ -59,7 +58,7 @@ public class Saml2AuthenticationTokenConverterTests {
public void convertWhenSamlResponseThenToken() { public void convertWhenSamlResponseThenToken() {
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter( Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter(
this.relyingPartyRegistrationResolver); this.relyingPartyRegistrationResolver);
given(this.relyingPartyRegistrationResolver.convert(any(HttpServletRequest.class))) given(this.relyingPartyRegistrationResolver.resolve(any(HttpServletRequest.class), any()))
.willReturn(this.relyingPartyRegistration); .willReturn(this.relyingPartyRegistration);
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter(Saml2ParameterNames.SAML_RESPONSE, request.setParameter(Saml2ParameterNames.SAML_RESPONSE,
@ -74,7 +73,7 @@ public class Saml2AuthenticationTokenConverterTests {
public void convertWhenSamlResponseInvalidBase64ThenSaml2AuthenticationException() { public void convertWhenSamlResponseInvalidBase64ThenSaml2AuthenticationException() {
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter( Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter(
this.relyingPartyRegistrationResolver); this.relyingPartyRegistrationResolver);
given(this.relyingPartyRegistrationResolver.convert(any(HttpServletRequest.class))) given(this.relyingPartyRegistrationResolver.resolve(any(HttpServletRequest.class), any()))
.willReturn(this.relyingPartyRegistration); .willReturn(this.relyingPartyRegistration);
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter(Saml2ParameterNames.SAML_RESPONSE, "invalid"); request.setParameter(Saml2ParameterNames.SAML_RESPONSE, "invalid");
@ -90,7 +89,7 @@ public class Saml2AuthenticationTokenConverterTests {
public void convertWhenNoSamlResponseThenNull() { public void convertWhenNoSamlResponseThenNull() {
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter( Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter(
this.relyingPartyRegistrationResolver); this.relyingPartyRegistrationResolver);
given(this.relyingPartyRegistrationResolver.convert(any(HttpServletRequest.class))) given(this.relyingPartyRegistrationResolver.resolve(any(HttpServletRequest.class), any()))
.willReturn(this.relyingPartyRegistration); .willReturn(this.relyingPartyRegistration);
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
assertThat(converter.convert(request)).isNull(); assertThat(converter.convert(request)).isNull();
@ -100,7 +99,7 @@ public class Saml2AuthenticationTokenConverterTests {
public void convertWhenNoRelyingPartyRegistrationThenNull() { public void convertWhenNoRelyingPartyRegistrationThenNull() {
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter( Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter(
this.relyingPartyRegistrationResolver); this.relyingPartyRegistrationResolver);
given(this.relyingPartyRegistrationResolver.convert(any(HttpServletRequest.class))).willReturn(null); given(this.relyingPartyRegistrationResolver.resolve(any(HttpServletRequest.class), any())).willReturn(null);
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
assertThat(converter.convert(request)).isNull(); assertThat(converter.convert(request)).isNull();
} }
@ -109,7 +108,7 @@ public class Saml2AuthenticationTokenConverterTests {
public void convertWhenGetRequestThenInflates() { public void convertWhenGetRequestThenInflates() {
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter( Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter(
this.relyingPartyRegistrationResolver); this.relyingPartyRegistrationResolver);
given(this.relyingPartyRegistrationResolver.convert(any(HttpServletRequest.class))) given(this.relyingPartyRegistrationResolver.resolve(any(HttpServletRequest.class), any()))
.willReturn(this.relyingPartyRegistration); .willReturn(this.relyingPartyRegistration);
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET"); request.setMethod("GET");
@ -126,7 +125,7 @@ public class Saml2AuthenticationTokenConverterTests {
public void convertWhenGetRequestInvalidDeflatedThenSaml2AuthenticationException() { public void convertWhenGetRequestInvalidDeflatedThenSaml2AuthenticationException() {
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter( Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter(
this.relyingPartyRegistrationResolver); this.relyingPartyRegistrationResolver);
given(this.relyingPartyRegistrationResolver.convert(any(HttpServletRequest.class))) given(this.relyingPartyRegistrationResolver.resolve(any(HttpServletRequest.class), any()))
.willReturn(this.relyingPartyRegistration); .willReturn(this.relyingPartyRegistration);
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
request.setMethod("GET"); request.setMethod("GET");
@ -145,7 +144,7 @@ public class Saml2AuthenticationTokenConverterTests {
public void convertWhenUsingSamlUtilsBase64ThenXmlIsValid() throws Exception { public void convertWhenUsingSamlUtilsBase64ThenXmlIsValid() throws Exception {
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter( Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter(
this.relyingPartyRegistrationResolver); this.relyingPartyRegistrationResolver);
given(this.relyingPartyRegistrationResolver.convert(any(HttpServletRequest.class))) given(this.relyingPartyRegistrationResolver.resolve(any(HttpServletRequest.class), any()))
.willReturn(this.relyingPartyRegistration); .willReturn(this.relyingPartyRegistration);
MockHttpServletRequest request = new MockHttpServletRequest(); MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter(Saml2ParameterNames.SAML_RESPONSE, getSsoCircleEncodedXml()); request.setParameter(Saml2ParameterNames.SAML_RESPONSE, getSsoCircleEncodedXml());
@ -161,7 +160,7 @@ public class Saml2AuthenticationTokenConverterTests {
Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter( Saml2AuthenticationTokenConverter converter = new Saml2AuthenticationTokenConverter(
this.relyingPartyRegistrationResolver); this.relyingPartyRegistrationResolver);
converter.setAuthenticationRequestRepository(authenticationRequestRepository); converter.setAuthenticationRequestRepository(authenticationRequestRepository);
given(this.relyingPartyRegistrationResolver.convert(any(HttpServletRequest.class))) given(this.relyingPartyRegistrationResolver.resolve(any(HttpServletRequest.class), any()))
.willReturn(this.relyingPartyRegistration); .willReturn(this.relyingPartyRegistration);
given(authenticationRequestRepository.loadAuthenticationRequest(any(HttpServletRequest.class))) given(authenticationRequestRepository.loadAuthenticationRequest(any(HttpServletRequest.class)))
.willReturn(authenticationRequest); .willReturn(authenticationRequest);
@ -177,8 +176,7 @@ public class Saml2AuthenticationTokenConverterTests {
@Test @Test
public void constructorWhenResolverIsNullThenIllegalArgument() { public void constructorWhenResolverIsNullThenIllegalArgument() {
assertThatIllegalArgumentException() assertThatIllegalArgumentException().isThrownBy(() -> new Saml2AuthenticationTokenConverter(null));
.isThrownBy(() -> new Saml2AuthenticationTokenConverter((RelyingPartyRegistrationResolver) null));
} }
@Test @Test

View File

@ -105,7 +105,7 @@ public class Saml2MetadataFilterTests {
.build(); .build();
String generatedMetadata = "<xml>test</xml>"; String generatedMetadata = "<xml>test</xml>";
given(this.resolver.resolve(validRegistration)).willReturn(generatedMetadata); given(this.resolver.resolve(validRegistration)).willReturn(generatedMetadata);
this.filter = new Saml2MetadataFilter((request) -> validRegistration, this.resolver); this.filter = new Saml2MetadataFilter((request, registrationId) -> validRegistration, this.resolver);
this.filter.doFilter(this.request, this.response, this.chain); this.filter.doFilter(this.request, this.response, this.chain);
verifyNoInteractions(this.chain); verifyNoInteractions(this.chain);
assertThat(this.response.getStatus()).isEqualTo(200); assertThat(this.response.getStatus()).isEqualTo(200);
@ -131,7 +131,7 @@ public class Saml2MetadataFilterTests {
String generatedMetadata = "<xml>test</xml>"; String generatedMetadata = "<xml>test</xml>";
this.request.setPathInfo("/saml2/service-provider-metadata/registration-id"); this.request.setPathInfo("/saml2/service-provider-metadata/registration-id");
given(this.resolver.resolve(validRegistration)).willReturn(generatedMetadata); given(this.resolver.resolve(validRegistration)).willReturn(generatedMetadata);
this.filter = new Saml2MetadataFilter((request) -> validRegistration, this.resolver); this.filter = new Saml2MetadataFilter((request, registrationId) -> validRegistration, this.resolver);
this.filter.setMetadataFilename(testMetadataFilename); this.filter.setMetadataFilename(testMetadataFilename);
this.filter.doFilter(this.request, this.response, this.chain); this.filter.doFilter(this.request, this.response, this.chain);
assertThat(this.response.getHeaderValue(HttpHeaders.CONTENT_DISPOSITION)).asString() assertThat(this.response.getHeaderValue(HttpHeaders.CONTENT_DISPOSITION)).asString()