1

This is my first project in Spring. I am trying to get the username of the logged in user but it returns null. I have also tried the AuthenticationPrincipal annotation and other ways as well, still it returns null.

WebSecurityConfiguration class:

@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter{

    @Autowired
    private UserDetailsService customUserDetailsService;

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .userDetailsService(customUserDetailsService)
            .passwordEncoder(encoder());
    }

    @Override
    protected void configure (HttpSecurity http) throws Exception {

        http
            .csrf().disable()
            .antMatcher("/**")
            .authorizeRequests()
                .antMatchers("/login**").permitAll()
                .anyRequest().authenticated();
    }

    public PasswordEncoder encoder() {
        return NoOpPasswordEncoder.getInstance();
    }
}

AuthorizationServerConfiguration class:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private DataSource dataSource;

    @Autowired 
    private CustomUserDetailsService userDetailsService;

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.checkTokenAccess("isAuthenticated()");
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        clients.jdbc(dataSource);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

        endpoints.authenticationManager(authenticationManager)
            .tokenStore(tokenStore())
            .userDetailsService(userDetailsService)
            .approvalStoreDisabled();
    }

    @Bean 
    public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
    }

}

ResourceServerConfiguration class:

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter{

    @Autowired
    TokenStore tokenStore;

    @Autowired
    DataSource dataSource;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("scout").tokenStore(tokenStore);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {

        http
            .authorizeRequests()
                .antMatchers("/oauth/token", "/oauth/authorize **").permitAll();
        http
            .requestMatchers()
                .antMatchers("/api/patients/**")
                .and()
            .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/api/patients/{\\d+}").access("hasAnyRole('PATIENT', 'DOCTOR')")
                .antMatchers("/api/patients/{\\d+}/medical-records").access("hasAnyRole ('PATIENT', 'DOCTOR')")
                .antMatchers("/api/patients/medical-records/{\\\\d+}/prescriptions").access("hasAnyRole('PATIENT', 'DOCTOR')")
                .antMatchers("/api/patients/**").access("hasRole('PATIENT')") 
                .and()
            .requestMatchers()
                .antMatchers("/api/doctors/**")
                .and()
            .authorizeRequests()
                .antMatchers("/api/doctors/**").access("hasRole('DOCTOR')"); 
    }
}

Below is the controller:

@GetMapping("/doctors")
public Doctor getDoctor(Authentication user) {
    System.out.println(user.getName());
    return doctorService.getDoctor(user.getName());
}

************************************Update********************************

I am using oauth2 for security. I am trying to get the username of the logged in user in my controller above. I have tried to print the Principal object and I get org.springframework.security.oauth2.provider.OAuth2Authentication@24d14be1: Principal: com.prescribr.rest.service.CustomUserDetails@56d40b2f; Credentials: [PROTECTED]; Authenticated: true; Details: remoteAddress=0:0:0:0:0:0:0:1, sessionId=<SESSION>, tokenType=bearertokenValue=<TOKEN>; Granted Authorities: ROLE_DOCTOR

On the other note, principal.getName() returns null.

I am using the access token in my header while sending the request as below in postman.

authorization: bearer theToken

CustomUserDetails class:

public class CustomUserDetails extends Users implements UserDetails {

    private static final long serialVersionUID = -8170449272852748515L;

    public CustomUserDetails(final Users user) {
        super(user);
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {

        return getRoles()
                .stream()
                .map(role -> new SimpleGrantedAuthority("ROLE_" + role.getRole()))
                .collect(Collectors.toList());
    }

    @Override
    public String getPassword() {
        // TODO Auto-generated method stub
        return super.getPassword();
    }

    @Override
    public String getUsername() {
        // TODO Auto-generated method stub
        return super.getEmail();
    }

    @Override
    public boolean isAccountNonExpired() {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        // TODO Auto-generated method stub
        return true;
    }

    @Override
    public boolean isEnabled() {
        // TODO Auto-generated method stub
        return true;
    }

}

CustomUserDetailsService class:

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    private UsersRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {

        Optional<Users> usersOptional = userRepository.findByEmail(email);

        Users user = null;

        if(usersOptional.isPresent()) {
            System.out.println(usersOptional.isPresent());
            user = usersOptional.get();
        }else {
            throw new RuntimeException("Email is not registered!");
        }

        return new CustomUserDetails(user);
    }

}

Users class:

@Entity
@Table(name="users")
public class Users {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name="id")
    private int id; 

    @Column(name="first_name")
    private String firstName;

    @Column(name="last_name")
    private String lastName;

    @Column(name="email")
    private String email;

    @Column(name="password")
    private String password;

    @Column(name="active")
    private int active;

    @OneToMany(cascade=CascadeType.ALL, 
               fetch=FetchType.EAGER
               )
    @JoinColumn(name="user_id")
    private Set<Role> roles;

    public Users() {}

    public Users(Users user) {
        this.id = user.id;
        this.firstName = user.firstName;
        this.lastName = user.lastName;
        this.email = user.email;
        this.password = user.password;
        this.active = user.active;
        this.roles = user.roles;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getActive() {
        return active;
    }

    public void setActive(int active) {
        this.active = active;
    }

    public Set<Role> getRoles() {
        return roles;
    }

    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }

}

Thanks again!

  • 1
    I think the annotation should be `@AuthenticationPrincipal` – Heuriskos Feb 15 '19 at 11:40
  • Yes, I have tried it. I meant @AuthenticationPrincipal I am sorry. I have been trying to resolve it from a long time. Still returns null – rajjput sufiyaan Feb 15 '19 at 13:40
  • You seem have two filter chains. Both of them capture `/**` URLs. One of them requires authentication, but doesn't show what type of authentication should be used. The other one doesn't protect /doctor. The order of your filter chain is important. Here is a good answer to understand multiple filter chains: https://stackoverflow.com/questions/54657163/springsecurity-make-restful-api-basic-auth-authentication-possible-via-only-a-s/54658476#54658476 – Filip Hanik VMware Feb 15 '19 at 19:29
  • Thanks for the reply. So should I order the resource server to one and the web security to 2? – rajjput sufiyaan Feb 15 '19 at 19:35
  • @rajjputsufiyaan: You code has too many errors. You have to read more documentation. Also you should reduce yoiur code to a minimal, just one controller method, just one URL. If this works, add more URLs. – dur Feb 15 '19 at 23:21
  • @rajjputsufiyaan For the other problems in your code, see https://stackoverflow.com/questions/39429104/spring-security-intercept-url-pattern-not-working and https://stackoverflow.com/questions/39457121/spring-security-multiple-url-ruleset-not-working-together – dur Feb 15 '19 at 23:35
  • @FilipHanikPivotal The order of the chains is right. `AuthorizationServerConfiguration`, `ResourceServerConfiguration` and last `WebSecurityConfiguration `. Last one is the fallback and matches `/**` (and also the login for authorization server). – dur Feb 15 '19 at 23:43
  • simplest: : `@RequestMapping getDoctor(Princcipal user);` (+1 & close-dup) ..see: [mvc annotation arguments](https://docs.spring.io/spring/docs/current/spring-framework-reference/web.html#mvc-ann-arguments) – xerx593 Feb 16 '19 at 01:00
  • @dur thanks for sharing the links. However, my issue is not a duplicate. I have tried injecting the principal and the authentication and also used security context in the controller, still it returns null. – rajjput sufiyaan Feb 16 '19 at 04:14
  • @xerrx593 I have tried using Principal it returns null – rajjput sufiyaan Feb 16 '19 at 04:16
  • @rajjputsufiyaan If the `Principal` is `null` or the `Authentication` in the context that means you are not logged in. You are anonymous. So you need to describe what you are doing step by step. At least you have to show your request with headers for your controller URL. – dur Feb 16 '19 at 08:48
  • @rajjputsufiyaan I think, all of us trying to help you, thought that your are getting `null` for the `Principal` or `Authentication` object. Your edit make it clear. Only the `getName()`method returns `null`. – dur Feb 16 '19 at 09:37
  • @rajjputsufiyaan You are using a custom `UserDetails` object, show the code. Maybe your not filling it in the right way? – dur Feb 16 '19 at 09:43
  • @dur I am sorry if my original post was not clear. I have added the classes in my question above. – rajjput sufiyaan Feb 16 '19 at 10:05
  • @rajjputsufiyaan Could you try to cast `Principal` to `CustomUserDetails` and call `getUsername()` instead of `getName()`? – dur Feb 16 '19 at 11:19
  • @dur I tried to cast the principal which is injected in the controller as: CustomUserDetails user = (CustomUserDetails) principal; and I got an error that It OauthAuthentication cannot be casted to CustomUserDetails and I also tried (CustomUserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal() which again gave me null for user.getUsername() – rajjput sufiyaan Feb 16 '19 at 11:27

0 Answers0