Reputation: 313
I have implemented 2 distinct servers: auth server and a resource server using Spring Boot 2.1.6.RELEASE and spring-cloud-starter-oauth2 version Greenwich.RELEASE
I am able to successfully get an access_token from auth server, use it to access protected api on resource server.
However I am not able to get user_name in the response returned by auth server's /oauth/check_token endpoint I can confirm that user_name is present in user table.
curl http://localhost:5000/oauth/check_token?token=a3ee84ee-6d3a-4a8f-af19-5446b55c637f | jq .
returns following:
{
"aud": [
"article"
],
"user_name": null,
"scope": [
"READ",
"WRITE",
"UPDATE",
"DELETE"
],
"active": true,
"exp": 1563849438,
"authorities": [
"ROLE_administrator",
"create_article",
"read_article",
"delete_article",
"update_article"
],
"client_id": "myclient"
}
AuthorizationServerConfiguration
@Configuration
public class AuthorizationServerConfiguration implements AuthorizationServerConfigurer {
private PasswordEncoder passwordEncoder;
private DataSource dataSource;
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Autowired
public AuthorizationServerConfiguration(
PasswordEncoder passwordEncoder,
DataSource dataSource,
AuthenticationManager authenticationManager) {
this.passwordEncoder = passwordEncoder;
this.dataSource = dataSource;
this.authenticationManager = authenticationManager;
}
@Bean
TokenStore jdbcTokenStore() {
return new JdbcTokenStore(dataSource);
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
return new JwtAccessTokenConverter();
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) {
// security.checkTokenAccess("isAuthenticated()").tokenKeyAccess("permitAll()");
security.checkTokenAccess("permitAll()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource).passwordEncoder(passwordEncoder);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
endpoints.tokenStore(jdbcTokenStore());
endpoints.authenticationManager(authenticationManager);
//TODO JWT
// endpoints.accessTokenConverter(accessTokenConverter());
}
}
WebSecurityConfiguration
@EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/version").permitAll()
.antMatchers("/api/**").authenticated();
}
}
UserDetailsServiceImpl
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
private UserRepository userRepository;
@Autowired
public UserDetailsServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
Optional<User> optionalUser = userRepository.findByUserName(userName);
optionalUser.orElseThrow(() -> new UsernameNotFoundException("Username or password wrong"));
UserDetails userDetails = new AuthUserDetail(optionalUser.get());
new AccountStatusUserDetailsChecker().check(userDetails);
return userDetails;
}
}
Main application class
@SpringBootApplication
@EnableAuthorizationServer
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
AuthUserDetail
package com.myapplication.models;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class AuthUserDetail extends User implements UserDetails {
public AuthUserDetail(User user) {
super(user);
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
getRoles().forEach(role -> {
grantedAuthorities.add(new SimpleGrantedAuthority(role.getName()));
role.getPermissions().forEach(permission -> {
grantedAuthorities.add(new SimpleGrantedAuthority(permission.getName()));
});
});
return grantedAuthorities;
}
@Override
public String getPassword() {
return super.getPassword();
}
@Override
public String getUsername() {
return super.getUserName();
}
@Override
public boolean isAccountNonExpired() {
return super.isAccountNonExpired();
}
@Override
public boolean isAccountNonLocked() {
return super.isAccountNonLocked();
}
@Override
public boolean isCredentialsNonExpired() {
return super.isCredentialsNonExpired();
}
@Override
public boolean isEnabled() {
return super.isEnabled();
}
}
User
package com.myapplication.models;
import lombok.Data;
import javax.persistence.*;
import java.util.List;
@Entity
@Table(name = "user")
@Data
public class User {
public User() {
}
public User(User user) {
this.userName = user.getUserName();
this.password = user.getPassword();
this.email = user.getEmail();
this.enabled = user.isEnabled();
this.accountNonExpired = user.isAccountNonExpired();
this.credentialsNonExpired = user.isCredentialsNonExpired();
this.accountNonLocked = user.isAccountNonLocked();
this.roles = user.getRoles();
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@Column(name = "user_name")
private String userName;
@Column(name = "password")
private String password;
@Column(name = "email")
private String email;
@Column(name = "enabled")
private boolean enabled;
@Column(name = "account_non_expired")
private boolean accountNonExpired;
@Column(name = "credentials_non_expired")
private boolean credentialsNonExpired;
@Column(name = "account_non_locked")
private boolean accountNonLocked;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "role_user", joinColumns = {@JoinColumn(name = "user_id", referencedColumnName = "id")},
inverseJoinColumns = {
@JoinColumn(name = "role_id", referencedColumnName = "id")})
private List<Role> roles;
}
user table ddl
create table if not exists user
(
id int auto_increment
primary key,
user_name varchar(100) not null,
password varchar(1024) not null,
email varchar(1024) not null,
enabled tinyint not null,
account_non_expired tinyint not null,
credentials_non_expired tinyint not null,
account_non_locked tinyint not null,
constraint user_name
unique (user_name)
);
Upvotes: 2
Views: 1507
Reputation: 221
I got the same problem after I modified column names of my user table from camelCase to underscore_case.
To resolve this I made sure the user, permission and role class is implementing Serializable class
@Entity
@Table(name = "user")
public class User implements Serializable {
----
----
}
and also remove the following spring jpa property if added
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
Upvotes: 2