I was following some tutorial for basic authentication using OAuth2. Whole thing works, but tests no. There are even simple class unit tests not working. I've got:
No qualifying bean of type org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder'.
AuthorizationServerConfiguration:
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
private AuthenticationManager authenticationManager;
#Autowired
public AuthorizationServerConfig(AuthenticationManager authenticationManager, PasswordEncoder passwordEncoder){
this.authenticationManager = authenticationManager;
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("clientId")
.authorizedGrantTypes("client_credentials", "password")
.authorities("ROLE_CLIENT","ROLE_TRUSTED_CLIENT").scopes("read","write","trust")
.resourceIds("oauth2-resource").accessTokenValiditySeconds(3600).secret("secret");
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.checkTokenAccess("isAuthenticated()");
}
}
UserDetails implementation:
public class CustomUserDetails implements UserDetails {
private static final long serialVersionUID = -3962786160780714576L;
private Collection<? extends GrantedAuthority> authorities;
private String password;
private String username;
private boolean enabled;
public CustomUserDetails(User user) {
this.username = user.getUsername();
this.password = user.getPassword();
this.authorities = translate(user.getRoles());
this.enabled = user.getEnabled();
}
private Collection<? extends GrantedAuthority> translate(List<Role> roles) {
List<GrantedAuthority> authorities = new ArrayList<>();
roles.stream().forEach(x -> authorities.add(new SimpleGrantedAuthority(x.getName())));
return authorities;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return username;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return enabled;
}
}
ResourceServerConfigurerAdapter:
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.headers().frameOptions().disable().and()
.authorizeRequests()
.antMatchers("/","/home","/register","/login").permitAll()
.antMatchers("/dev/hello-world").authenticated();
}
}
#SpringBootApplication
public class LimeApplication {
public static void main(String[] args) {
SpringApplication.run(LimeApplication.class, args);
}
Main class:
#SpringBootApplication
public class SomeApplication {
public static void main(String[] args) {
SpringApplication.run(SomeApplication.class, args);
}
#Autowired
public void authenticationManager(AuthenticationManagerBuilder builder, IUserDAO dao, PasswordEncoder encoder) throws Exception {
builder.userDetailsService(userDetailsService(dao)).passwordEncoder(encoder);
}
private UserDetailsService userDetailsService(final IUserDAO dao) {
return username -> new CustomUserDetails(dao.findByUsername(username));
}
}
application.yml
security:
oauth2:
resource:
filter-order: 3
I was looking and I was trying to disable authentication in test/resources/application.yml by
security:
basic:
enabled: false
But this does not work. I cannot find any answer how to correct or mock this. Can anyone help me? Does anyone know how to mock it? Or get this bean in tests?
Edit:
Tests are running with #DataJpaTest #RunWith(SpringRunner.class) annotations
Related
I added spring security to my app. I would like to secure any endpoints, and open "/users" for all
User configuration:
#Entity
#Table(name = "users")
#AllArgsConstructor
#NoArgsConstructor
public class UserEntity implements UserDetails {
#Id
private String id;
private String login;
private String password;
private String role;
public UserEntity(UserCreateRequestModel userCreateRequestModel) {
this.id = UUID.randomUUID().toString();
this.login = userCreateRequestModel.getLogin();
this.password = PasswordService.codePassword(userCreateRequestModel.getPassword());
this.role = "USER";
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<SimpleGrantedAuthority> list = new ArrayList<>();
list.add(new SimpleGrantedAuthority(role));
return new ArrayList<SimpleGrantedAuthority>();
}
#Override
public String getUsername() {
return login;
}
#Override
public String getPassword() {
return password;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
My custom WebSecurityConfigurerAdapter:
#Configuration
#EnableWebSecurity
#RequiredArgsConstructor
public class MyWebSecurityConfig extends WebSecurityConfigurerAdapter {
private final MyUserDetailsService myUserDetailsService;
#Override
public void configure(HttpSecurity http) throws Exception {
http
.cors().and().csrf().disable()
.authorizeRequests()
.antMatchers("/users", "/users/**").permitAll()
.anyRequest().hasAuthority("USER")
;
}
#Override
protected UserDetailsService userDetailsService() {
return myUserDetailsService;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(myUserDetailsService);
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
and next I added custom UserDetailsService
#Service
#RequiredArgsConstructor
public class MyUserDetailsService implements UserDetailsService {
private final UserEntityRepository userEntityRepository;
#Override
public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException {
System.out.println(userEntityRepository.findByLogin(login));
return userEntityRepository.findByLogin(login).orElseThrow((() -> new ObjectNotFoundException(login)));
}
and now I am getting problem. Endpoint for "/users" is open to all, I can send request with any problem. But when I am trying for example any #PostMapping on endpoint "/shapes"
I am getting 403 status response. In postman I think everything is OK:
of course user exists in database. In UserEntity user isEnabled, isAccountNonExpired, isAccountNonLocked and isCredentialsNonExpired - everything is on true.
In your getAuthorities() method of UserEntity class you're returning an empty List, so spring-security sees no authorities (roles) for an authenticated user.
Change this method like this:
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.singletonList(new SimpleGrantedAuthority(role));
}
#ComponentScan(basePackages = {"conf"})
#ComponentScan(basePackages = {"application.controller"})
#ComponentScan(basePackages = {"applicaion.model"})
#ComponentScan(basePackages = {"applicaion.dao"})
#ComponentScan(basePackages = {"usersDetails"})
#SpringBootApplication
#EnableJpaRepositories
#EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Security config part
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Bean
#Override
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
#Override
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll();
}
#Bean
public PasswordEncoder passwordEncoder() {return NoOpPasswordEncoder.getInstance();}
}
User Entity
"felhasznalonev"==username and "felhasznalo"==user
in hungarian
in the database table has theese names
#Entity
#Table( name="felhasznalo")
public class User {
#Id
#GeneratedValue
private int id;
#Column( unique=true, nullable=false )
private String felhasznalonev;
#Column( nullable=false )
private String jelszo;
private int statusz;
public User() {}
public User(String felhasznalonev,String jelszo,int statusz) {
this.felhasznalonev=felhasznalonev;
this.jelszo=jelszo;
this.statusz=statusz;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFelhasznalonev() {
return felhasznalonev;
}
public void setFelhasznalonev(String email) {
this.felhasznalonev = email;
}
public String getJelszo() {
return this.jelszo;
}
public void setPassword(String password) {
this.jelszo = password;
}
#Override
public String toString() {
return null;
}
public int getStatusz() {
return statusz;
}
public void setStatusz(int statusz) {
this.statusz = statusz;
}
}
userServiceimpl part
#Service("userDetailsService")
public class UserServiceImpl implements UserService, UserDetailsService {
#Autowired
private UserRepository userRepository;
#Autowired
public UserServiceImpl(UserRepository userRepository){
this.userRepository = userRepository;
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = findByUsername(username);
return new UserDetailsImpl(user);
}
#Override
public User findByUsername(String username) {
return userRepository.findByUsername(username);
}
}
UserDetailsImpl part
public class UserDetailsImpl implements UserDetails {
private User user;
public UserDetailsImpl(User user) {
this.user = user;
}
public UserDetailsImpl() {}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Arrays.asList(new SimpleGrantedAuthority("USER"));
}
#Override
public String getPassword() {
return user.getJelszo();
}
#Override
public String getUsername() {
return user.getFelhasznalonev();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
UserService part
public interface UserService {
public User findByUsername(String username);
}
UserRepository
public interface UserRepository extends JpaRepository<User,Integer> {
User findByUsername(String username);
}
When i run the code everything looks fine, the basic login page come in, i enter the username/password from the database but nothing happen
and IntellIj write this:
2021-11-25 13:12:48.870 ERROR 13928 --- [nio-8080-exec-5] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Filter execution threw an exception] with root cause
java.lang.StackOverflowError: null
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:472) ~[spring-security-config-5.3.4.RELEASE.jar:5.3.4.RELEASE]
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$UserDetailsServiceDelegator.loadUserByUsername(WebSecurityConfigurerAdapter.java:472) ~[spring-security-config-5.3.4.RELEASE.jar:5.3.4.RELEASE]
-||-
the connection with database is good, i can list users as well
Thanks for reading all this and sorry for bad english and mistakes, have a good day!
java.lang.StackOverflowError error tell you method declaration in service layer is not linked with any JpaRepository. Problem is came up from loadUserByUsername method in userServiceimpl. You declare method findByUsername without linked with Repository.
Change
User user = findByUsername(username);
To
User user = userRepository.findByUsername(username);
And UserServiceImpl Implements with UserDetailsService only. You need to change inSecurity config code because it has more problem like add wrong annotation and two method declare with same name etc...
Modified Security config
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
private UserDetailsService userDetailsService;
#Bean
public AuthenticationProvider authProvider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(passwordEncoder());
return provider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.formLogin()
.permitAll();
}
#Bean
public PasswordEncoder passwordEncoder()
{
return new BCryptPasswordEncoder();
}
}
You have doubly declared userDetailsService with the same name,
First:
#Bean
#Override
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
Second:
#Service("userDetailsService")
public class UserServiceImpl implements UserService, UserDetailsService {
It may cause the problem. You should have only one instance of userDetailService.
In your SecurityConfig Can you try removing
#Bean
#Override
public UserDetailsService userDetailsService() {
return super.userDetailsService();
}
And changing the implementation for
#Override
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
to
#Autowired
private UserDetailsService userDetailsService;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
Here is the config snippet:
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Bean
#Override
protected UserDetailsService userDetailsService() {
return super.userDetailsService();
}
#Autowired
private UserDetailsService userDetailsService;
#Bean
AuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsService);
provider.setPasswordEncoder(new BCryptPasswordEncoder());
return provider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/register", "/registration")
.permitAll()
.antMatchers("/home")
.hasAuthority("USER")
.antMatchers("/admin")
.hasAuthority("ADMIN")
.anyRequest()
.authenticated()
.and()
.httpBasic();
}
}
Here is another relevant class named CustomUserDetails:
#Component
public class CustomUserDetails implements UserDetails {
private User user;
public CustomUserDetails(User user) {
super();
this.user = user;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.singleton(new SimpleGrantedAuthority("USER"));
//return Collections.emptyList();
}
#Override
public String getPassword() {
return user.getPassword();
}
#Override
public String getUsername() {
return user.getEmail();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
}
Here is the #service:
#Service
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email);
if(user ==null) {
throw new UsernameNotFoundException("User Not Found");
}
return new CustomUserDetails(user);
}
}
The URL /home must be accessible to only USERS, but when I am sending a GET request to it, it is accessible and doesn't require any authorization or even authentication. I think I am overlooking something please help.
I changed OAUTH2 version from 2.0.3 to 2.0.14 and Authorization Server is not working.
I had this message from server:
o.s.s.o.provider.endpoint.TokenEndpoint : Handling error: InsufficientAuthenticationException, There is no client authentication. Try adding an appropriate authentication filter.
Could you help me and say what is wrong ? I have token storage in database and I want to use ClientDetailsService from memory, but Spring not recognized this.
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfiguration extends
AuthorizationServerConfigurerAdapter implements EnvironmentAware {
private static final String ENV_OAUTH = "authentication.oauth.";
private static final String PROP_CLIENTID = "clientid";
private static final String PROP_SECRET = "secret";
private static final String PROP_TOKEN_VALIDITY_SECONDS =
"tokenValidityInSeconds";
private RelaxedPropertyResolver propertyResolver;
#Autowired
private DataSource dataSource;
private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Autowired
private AuthenticationManager authenticationManager;
#Bean
protected AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource);
}
#Override
public void configure(AuthorizationServerSecurityConfigurer security) throws
Exception {
security.passwordEncoder(passwordEncoder);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.tokenStore(tokenStore())
.authenticationManager(authenticationManager);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws
Exception {
clients.inMemory()
.withClient(propertyResolver.getProperty(PROP_CLIENTID)).scopes("read",
"write").authorities(Authorities.ROLE_ADMIN.name(),
Authorities.ROLE_USER.name())
.authorizedGrantTypes("password",
"refresh_token").secret(propertyResolver.getProperty(PROP_SECRET))
.accessTokenValiditySeconds(
propertyResolver.getProperty(PROP_TOKEN_VALIDITY_SECONDS, Integer.class,
1800));
}
#Override
public void setEnvironment(Environment environment) {
this.propertyResolver = new RelaxedPropertyResolver(environment,
ENV_OAUTH);
}
}
Security configuration
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsComponent;
#Bean
public PasswordEncoder passwordEncoder() {
return new StandardPasswordEncoder();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws
Exception {
auth
.userDetailsService(userDetailsComponent)
.passwordEncoder(passwordEncoder());
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/register").antMatchers("/console/*")
.antMatchers("/oauth/**");
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
Method security configuration.
#EnableGlobalMethodSecurity(prePostEnabled = true,
proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration
{
}
Custom UserDetailsService.
#Component("userDetailsComponent")
public class UserDetailsComponent implements UserDetailsService {
private final Logger log =
LoggerFactory.getLogger(UserDetailsComponent.class);
#Autowired
private UsersRepository usersRepository;
#Override
public UserDetails loadUserByUsername(String login) {
log.debug("Authenticating {}", login);
Users userFromDatabase = null;
if (login.contains("#")) {
userFromDatabase = usersRepository.findByEmail(login);
} else {
userFromDatabase = usersRepository.findByUsername(login);
}
if (userFromDatabase == null) {
throw new UsernameNotFoundException("User " + login + " was not
found in the database");
} else if (!userFromDatabase.getActivated()) {
throw new UserNotActivatedException("User " + login + " is not
activated");
}
Collection<GrantedAuthority> grantedAuthorities = new
ArrayList<GrantedAuthority>();
for (OauthAuthority authority : userFromDatabase.getOauthAuthorities())
{
GrantedAuthority grantedAuthority = new
SimpleGrantedAuthority(authority.getAuthority().getRole());
grantedAuthorities.add(grantedAuthority);
}
return new User(userFromDatabase.getUsername(),
userFromDatabase.getPassword(), grantedAuthorities);
}
}
Properties
authentication.oauth.clientid=game
authentication.oauth.secret=secret
authentication.oauth.tokenValidityInSeconds=2000
I can't seem to get my security configuration right. No matter what I do when using hasRole my endpoints always return 403.
Also I can't get anything to work unless I duplicate my antMatchers under both .requestMatchers() and .authorizeRequests(). I'm clearly missing something here.
Basically I want everything to require authentication but a few endpoints only to be accessable if the user is member of certain groups (for now just admin).
My security configuration is as follows. Everything beside hasRole works.
#EnableGlobalMethodSecurity(prePostEnabled = true)
#EnableWebSecurity
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.requestMatchers()
.antMatchers(HttpMethod.GET, "/v2/api-docs", "/swagger-resources/**", "/swagger-ui.html")
.antMatchers(HttpMethod.GET, "/users")
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/v2/api-docs", "/swagger-resources/**", "/swagger-ui.html").permitAll()
.antMatchers(HttpMethod.GET, "/users").hasRole("ADMIN")
.anyRequest().authenticated();
}
// Inspiration: https://spring.io/blog/2015/06/08/cors-support-in-spring-framework#comment-2416096114
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**");
}
}
My AuthenticationConfiguration is as follows
#Configuration
#EnableResourceServer
public class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter {
private final UserDetailsService userService;
private final PasswordEncoder passwordEncoder;
public AuthenticationConfiguration(UserDetailsService userService, PasswordEncoder passwordEncoder) {
this.userService = userService;
this.passwordEncoder = passwordEncoder;
}
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userService)
.passwordEncoder(passwordEncoder);
}
}
My AuthorizationServerConfiguration is as follows
#Configuration
#EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private final AuthenticationManager authenticationManager;
public AuthorizationServerConfiguration(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager);
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("html5")
.secret("password")
.authorizedGrantTypes("password")
.scopes("openid");
}
}
I'll happily post my user service and other stuff. But everything seems to work beside hasRole and Principal is loaded with the right authorities (roles). But please let me know if I should post any more code.
The entire source code can be found here.
Have you tried with "ROLE_ADMIN" rather than just "ADMIN"? Take a look at this for reference:
Spring security added prefix "ROLE_" to all roles name?
Following up on my comments to the question I'll provide sample OAuth2 Configuration classes I've used for testing. I always use two different webapps, because I want a clear line between auth server and resource server(and because it makes configurations so much harder....), so my example probably needs some adjustments when used in a single webapp.
Configuration for the auth server:
#EnableAuthorizationServer
#Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
private TokenStore tokenStore;
private DataSource dataSource;
#Autowired
public OAuth2Config(TokenStore tokenStore,
DataSource dataSource) {
this.tokenStore = tokenStore;
this.dataSource = dataSource;
}
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore);
}
#Configuration
public static class TokenStoreConfiguration {
#Bean
public TokenStore tokenStore(DataSource dataSource) {
return new JdbcTokenStore(dataSource);
}
}
}
Configuration for resource server:
#EnableResourceServer
#Configuration
public class OAuth2Config extends ResourceServerConfigurerAdapter {
public static final String PROPERTY_RESOURCE_ID = "com.test.oauth.resourceId";
private Environment environment;
private TokenStore tokenStore;
#Autowired
public OAuth2Config(Environment environment,
TokenStore tokenStore) {
this.environment = environment;
this.tokenStore = tokenStore;
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore)
.resourceId(environment.getProperty(PROPERTY_RESOURCE_ID))
.stateless(true);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/demo")
.access("hasRole('DEMO')")
.anyRequest().denyAll()
.and()
.formLogin().disable()
.logout().disable()
.jee().disable()
.x509().disable();
}
#Configuration
public static class TokenStoreConfiguration {
#Bean
public TokenStore tokenStore(DataSource dataSource) {
return new JdbcTokenStore(dataSource);
}
}
}
Obviously this requires that you have a DataSource bean configured. This implementation uses the default tables as provided by spring security OAuth2(they are far from ideal, but can be customized if required).
There are a few things you might want to adjust for your case(I'll leave the classes I provided as is for a reference if people might want to use it with JDBC):
Create only one bean of type TokenStore and use InMemoryTokenStore instead of JdbcTokenStore
replace the configuration for clients with your inMemory() implementation and remove all references to my autowired DataSource
Provide requestMatchers() before specifying authorizeRequests() in your resource server configuration. Depending on the order the configuration is processed and the filter chains are added this might be required to allow the oauth endpoints to be reached without requiring an OAuth token.
Edit: Seeing the answer by ritesh.garg I think that what I provided might not resolve your issues, but might help some figuring out where and how to start configuring Spring Security OAuth2(When I did it the first time I found it hard to do, because back then I couldn't find any clear examples, though this might have changed)
I had the same problem, I just forgot to implements getAuthorities() method from UserDetails (SpringSecurity class). Look my entity:
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
#Entity
#Table(name = "tb_user")
public class User implements UserDetails, Serializable {
private static final long serialVersionUID = -6519124777839966091L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String firstName;
private String lastName;
#Column(unique = true)
private String email;
private String password;
#ManyToMany(fetch = FetchType.EAGER)
#JoinTable(
name = "tb_user_role",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "role_id")
)
private Set<Role> roles = new HashSet<>();
public User() {
}
public User(Long id, String firstName, String lastName, String email, String password) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
this.password = password;
}
public Long getId() {
return id;
}
public void setId(Long 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 void setPassword(String password) {
this.password = password;
}
public Set<Role> getRoles() {
return roles;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return roles.stream().map(role -> new SimpleGrantedAuthority(role.getAuthority()))
.collect(Collectors.toList());
}
public String getPassword() {
return password;
}
#Override
public String getUsername() {
return email;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(id, user.id);
}
#Override
public int hashCode() {
return Objects.hash(id);
}
}
The method getAuthorities return null by default when you extends UserDetails class from security package, you need implement something like that:
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return roles.stream().map(role -> new SimpleGrantedAuthority(role.getAuthority()))
.collect(Collectors.toList());
}
I hope this help someone, sorry about my english errors! hehe