简体   繁体   中英

Spring Security SAML and UserDetailsService

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.

https://docs.spring.io/spring-security/reference/servlet/saml2/login/authentication.html#servlet-saml2login-opensamlauthenticationprovider-userdetailsservice

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?

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:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM