[...]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;
}