ulisesbocchio / spring-boot-security-saml

spring-security-saml integration with Spring Boot
MIT License
158 stars 73 forks source link

[...]SAMLUserDetails cannot be cast to models.generated.Person #74

Closed Jolley71717 closed 5 years ago

Jolley71717 commented 5 years ago

I was previously using version 1.7 with spring boot 1.x, but am trying to move up to version 1.16 with spring boot 2.x. I could previously cast the SAML object directly to my Person object by doing the following

Principal userPrincipal = httpServletRequest.getUserPrincipal();
            Person person;
            if(userPrincipal != null) {
                person = (Person) ((Authentication) userPrincipal).getPrincipal();
                // Then able to access all attributes of the person class
            }
            // Do other stuff

This was because of my SAMLUserDetailsServiceImpl implementing SAMLUserDetailsService, and when loadUserBySAML was called, I was able to couple the SAML authentication information with information from my database and return a Person object.

It appears as if my SAMLUserDetailsServiceImpl is not actually being relied on for the implementation any more.

Jolley71717 commented 5 years ago

It looks like it was not an issue so much as a new way that the configuration works. I was simply implementing the SAMLUserDetailsService. The other issue I was running into was that my repositories were null in my SAMLUserDetailsServiceImpl when I was piping them in through the @Autowired implementation. I ended up having to refactor the code a little bit to utilize services to call the repositories instead.

I also ended up needing to keep my extended WebSecurityConfigurerAdapter and then Autowire in my SAMLUserDetailsServiceImpl. This allowed me to add my AuthenticationManager Bean

ulisesbocchio commented 5 years ago

Ok, great @Jolley71717, thanks for the heads up. Would you mind sharing a snippet of what you did? That way I can incorporate it to the samples repo

Jolley71717 commented 5 years ago

@ulisesbocchio , I would love to help. Please see some of my code snippets below.

In my Application security configuration file, I had something like this

@Configuration
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    SAMLUserDetailsServiceImpl samlUserDetailsService;

    @Bean
    SAMLConfigurerBean saml() {
        return new SAMLConfigurerBean();
    }

        @Bean
    public SAMLUserDetailsService myuserDetailsService(){
        return samlUserDetailsService.userDetailsService();
    }

    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
    http.httpBasic()
                .disable()
                .csrf()
                .disable()
                .anonymous()
                .and()
                .apply(saml())
                .serviceProvider()
                .authenticationProvider()
                .userDetailsService(myuserDetailsService());
    }

Then, in my Service Provider:

@Configuration
@PropertySource("classpath:application.properties")
public class AppServiceProviderConfig extends ServiceProviderConfigurerAdapter {

    @Autowired
    SAMLUserDetailsServiceImpl samlUserDetailsService;

    Type valueName;

    // Most configuration properties are externalized in order to support security and additional Maven profiles
    public AppServiceProviderConfig(@Value("name.of.value.in.properties") Type valueName){

    this.valueName = valueName;

    }

    @Override
    public void configure(ServiceProviderBuilder serviceProvider) throws Exception {

        serviceProvider
            .[serviceProvider configuration] // I mimicked the configuration attributes in my application-[profile].properties 
            // I then added the authentication provider configuration information
            .and()
                .authenticationProvider()
                        .userDetailsService(samlUserDetailsService.userDetailsService()); 

    }

}

Finally, my SAMLUserDetailsService implementation:

@Service
public class SAMLUserDetailsServiceImpl {

    @Autowired
    private ServiceClass serviceClassName;

    public SAMLUserDetailsService userDetailsService() {

        return new SAMLUserDetailsService() {

            @Override
            public Object loadUserBySAML(SAMLCredential credential) throws UsernameNotFoundException {

            //Access SAMLCredentail attributes here and use them to in the service to find the appropriate User object and  authorization levels of the authenticated user
            YourUserType userObject = serviceClassName.findUserByCredentialID(credential.getNameID().getValue());

            return userObject;

}