ulisesbocchio/spring-boot-security-saml

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

Jolley71717 opened this issue · 3 comments

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.

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

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

@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;

}