Issue
I am integrating SAML into a Spring Boot application using the implementation built into Spring Security 5.6. Much of the online help references the now deprecated external library implementation (https://github.com/spring-projects/spring-security-saml) so I am following this document:
https://docs.spring.io/spring-security/reference/servlet/saml2/login/index.html
I have this interaction working and I am authenticating from SAML now. Here is the configuration:
spring:
security:
saml2:
relyingparty:
registration:
adfs:
signing:
credentials:
- private-key-location: "file:///C:/tmp/keys/private.key"
certificate-location: "file:///C:/tmp/keys/public.crt"
identityprovider:
entity-id: << SNIPPED >>
verification.credentials:
- certificate-location: "classpath:saml-certificate/adfs.crt"
singlesignon:
url: << SNIPPED >>
sign-request: true
The code looks like this now:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final RelyingPartyRegistrationRepository _relyingPartyRegistrationRepository;
@Autowired
public WebSecurityConfig(RelyingPartyRegistrationRepository relyingPartyRegistrationRepository {
_relyingPartyRegistrationRepository = relyingPartyRegistrationRepository;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// add auto-generation of ServiceProvider Metadata at {baseUrl}/saml2/service-provider-metadata/ims-adfs
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver(_relyingPartyRegistrationRepository);
Saml2MetadataFilter filter = new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver());
http
.authorizeRequests()
.antMatchers("/seer.ico", "/monitor", "/**/check").permitAll()
.anyRequest().authenticated()
.and().sessionManagement()
.and().csrf().ignoringAntMatchers("/servers/**/searches")
.and()
.saml2Login(withDefaults())
.saml2Logout(withDefaults())
.addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class);
}
}
The issue is that I need to remap the user details to set up correct roles and also limit the logins to users who have the correct Linux permissions. The permissions are being correcting returned in the assertion; I just need to verify they are correct or fail the login.
The Spring Security documentation has a section on coordinating with a UserDetailsService which seems like exactly what I need.
However when I implement it like the example, I now get the following error from Spring:
No assertions found in response.
Here is the updated code:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final RelyingPartyRegistrationRepository _relyingPartyRegistrationRepository;
private final AuthenticationService _userDetailsService;
@Autowired
public WebSecurityConfig(RelyingPartyRegistrationRepository relyingPartyRegistrationRepository, AuthenticationService userDetailsService) {
_relyingPartyRegistrationRepository = relyingPartyRegistrationRepository;
_userDetailsService = userDetailsService;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
OpenSaml4AuthenticationProvider authenticationProvider = new OpenSaml4AuthenticationProvider();
authenticationProvider.setResponseAuthenticationConverter(responseToken -> {
Saml2Authentication authentication = OpenSaml4AuthenticationProvider.createDefaultResponseAuthenticationConverter().convert(responseToken);
Assertion assertion = responseToken.getResponse().getAssertions().get(0);
String username = assertion.getSubject().getNameID().getValue();
UserDetails userDetails = _userDetailsService.loadUserByUsername(username);
authentication.setDetails(userDetails);
return authentication;
});
// add auto-generation of ServiceProvider Metadata at {baseUrl}/saml2/service-provider-metadata/ims-adfs
RelyingPartyRegistrationResolver relyingPartyRegistrationResolver = new DefaultRelyingPartyRegistrationResolver(_relyingPartyRegistrationRepository);
Saml2MetadataFilter filter = new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver());
http
.authorizeRequests()
.antMatchers("/seer.ico", "/monitor", "/**/check").permitAll()
.anyRequest().authenticated()
.and().sessionManagement()
.and().csrf().ignoringAntMatchers("/servers/**/searches")
.and()
.saml2Login(saml2 -> saml2.authenticationManager(new ProviderManager(authenticationProvider)))
.saml2Logout(withDefaults())
.addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class);
}
}
So basically this gets a correct response from SAML:
.saml2Login(withDefaults())
and when I switch it to this then the SAML response is missing the Assertion:
.saml2Login(saml2 -> saml2.authenticationManager(new ProviderManager(authenticationProvider)))
I've been looking all over for other solutions but like I said there are very few examples that don't use the old deprecated SAML library for Spring.
Any thoughts?
Solution
Check if Spring Boot is importing version 3 and version 4 of Open SAML. If it is use only version 4.
Spring Security Samples has an example for SAML2. The build.gradle in the project contains the following:
repositories {
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://build.shibboleth.net/nexus/content/repositories/releases/" }
}
dependencies {
constraints {
implementation "org.opensaml:opensaml-core:4.1.1"
implementation "org.opensaml:opensaml-saml-api:4.1.1"
implementation "org.opensaml:opensaml-saml-impl:4.1.1"
}
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.security:spring-security-saml2-service-provider'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
testImplementation 'net.sourceforge.htmlunit:htmlunit:2.44.0'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.awaitility:awaitility:4.2.0'
}
References:
- Customizing OpenSaml4AuthenticationProvider in Spring Security SAML2
- https://github.com/spring-projects/spring-security-samples/blob/main/servlet/spring-boot/java/saml2/login/build.gradle
- https://docs.spring.io/spring-security/reference/servlet/saml2/login/authentication.html
Answered By - pringi
Answer Checked By - Marie Seifert (JavaFixing Admin)