Rainer Schlund
Rainer Schlund

Reputation: 95

Unable to customize principal object, no matter how it always stays a string

Initially the principal object in the authentication of spring security is a string, that simply contains the user id. By defining a custom user detail service or a custom authentication provider and extending the user object in spring security, the user information should be stored in the principal object. But no matter which of both i choose, the principal object always stays a string. For security we are using an authentication server with oauth2.

This is the version with a customized authentication provider. I already found a hint, that a field called forcePrincipleAsString might be the reason for my problem, although it should initially be set to false, and the customized authentication provider i use has no such field.

This is my custom authentication provider:

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    public Authentication authenticate(Authentication authentication ) throws AuthenticationException {
        String password = authentication.getCredentials().toString().trim();
        SecurityUser appUser = new SecurityUser();
        return new UsernamePasswordAuthenticationToken(appUser, password, new ArrayList<>());
  }
  @Override
  public boolean supports(Class<? extends Object> authentication) {
      return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
  }

} 

This is my web security config:

@Configuration
@EnableOAuth2Sso
@EnableGlobalMethodSecurity(prePostEnabled = true)
@ComponentScan("edu.kit.tm.cm.bamsg.bffweb.iamservice")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private static final String REALM = "bam";

    @Autowired
    private CustomAuthenticationProvider authProvider; 

    @Autowired
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
      auth.authenticationProvider(authProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
      http
            .logout()
            .and()
            //endpoints without authentication
            .authorizeRequests().antMatchers("/logged", "/userData").permitAll()
            .and()
            // default with authentication
            .authorizeRequests().anyRequest().authenticated()
            .and()
            .csrf()
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
}

    @Bean
    public OAuth2FeignRequestInterceptor oAuth2FeignRequestInterceptor(OAuth2ClientContext context, OAuth2ProtectedResourceDetails details) {
        return new OAuth2FeignRequestInterceptor(context, details);
    }
    // I added this code from an advice, but it didn't help
    @Bean
    BasicAuthenticationEntryPoint getBasicAuthEntryPoint() {
        BasicAuthenticationEntryPoint basicAuth = new BasicAuthenticationEntryPoint();
        basicAuth.setRealmName(REALM);
        return basicAuth;
    }
}

The extended user class looks like that:

public class SecurityUser extends User{

    String firstName;
    String name;
    String password;

    private static final long serialVersionUID = 1L;

    public SecurityUser() {
        super("user", "none", new ArrayList<>());
        firstName = "Rainer";
        name = "Schlund";
        password = "meins";
    }

    public String getRole(){
        return "Student";
    }


}

And at least after authentication at the code line with the System.out.println the customized services should have been called, but unfortunately they are not. Breakpoints in the customized services have never been reached and the principal is still a string and not my customized user:

@ComponentScan("edu.kit.tm.cm.bamsg.bffweb.iamservice")
@RestController
@RequestMapping("/api/theses")
public class ThesisController {

    @Autowired
    private ThesisClient thesisClient;

    @Autowired
    private ThesisPersonLinker linker;

    @Autowired
    private ThesisPersonFilter filter;

    @GetMapping
    @PreAuthorize("hasRole('theses')")
    public ResponseEntity<Collection<ThesisFrontendDTO>> findAllTheses() {
       System.out.println(SecurityContextHolder.getContext().getAuthentication().getPrincipal());

The code contains some simplifications for testing like SecurityPerson always returning the same person, but i think that should not be a problem.

Upvotes: 2

Views: 3257

Answers (1)

Juzer Ali
Juzer Ali

Reputation: 4167

Declaring a CustomAuthenticationProvider only adds Authentication object to security context. In order to customize the Principal object you want in the security context, you will have to implement a UserDetailsService.

Baeldung is a good primer.

Upvotes: 1

Related Questions