I am new in Java Spring Security and have an issue with Java Spring Security.
I have the problem that despite of using authorities and WebSecurityConfigurerAdapter
in Java Spring, users not having certain authorities can still go e.g. to /trainingsplan/**.
Concrete problem: When I am logged in as a user with only the authority "Constants.TRAINER", why am I able to access the url in the server /trainingsplan/all? This user is able to get all the training plans despite of not having the ADMIN authority :/
Do you see a mistake?
My implementation in UserPrincipalDetailsService:
package auth;
import entity.User;
import entity.UserPrincipal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import repository.UserRepository;
import role.AuthorizationService;
import java.sql.SQLException;
import java.util.List;
#Component
#Service
public class UserPrincipalDetailsService implements UserDetailsService {
private UserRepository userRepository;
#Autowired
private ApplicationContext appContext;
private AuthorizationService authService;
// todo: autowire authservice here
#Lazy
#Autowired
private PasswordEncoder encoder;
public UserPrincipalDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
this.authService = new AuthorizationService(appContext);
}
#Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
User user = this.userRepository.findByUsername(s);
// String encodedPassword = encoder.encode(user.getPassword());
//user.setPassword(encodedPassword);
//user.setPassword(Bcrypter.getInstance().encode(user.getPassword()));
// encoder.encode(user.getPassword());
try {
List<String> roles = this.authService.getRolesToString(user.getId());
UserPrincipal userPrincipal = new UserPrincipal(user, roles.toArray(new String[0]));
return userPrincipal;
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
My implementation in UserPrincipal:
package entity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import role.Role;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public class UserPrincipal implements UserDetails {
private String[] roles;
private User user;
public UserPrincipal(User user, String[] rolesString) {
this.user = user;
this.roles = rolesString;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> authorities = new ArrayList<>();
List<String> listRoles =
new ArrayList<String>(Arrays.asList(this.roles));
listRoles.forEach(p -> {
GrantedAuthority authority = new SimpleGrantedAuthority(p);
authorities.add(authority);
});
/**
// Extract list of permissions (name)
this.user.getPermissionList().forEach(p -> {
GrantedAuthority authority = new SimpleGrantedAuthority(p);
authorities.add(authority);
});
// Extract list of roles (ROLE_name)
this.user.getRoleList().forEach(r -> {
GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + r);
authorities.add(authority);
});
*/
return authorities;
}
#Override
public String getPassword() {
return this.user.getPassword();
}
#Override
public String getUsername() {
return this.user.getUsername();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return true; //this.user.getActive() == 1;
}
}
My implementation in the SecurityConfiguration:
package auth;
import org.springframework.context.ApplicationContext;
import repository.IUserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import repository.UserRepository;
import util.Constants;
import java.util.Arrays;
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final ApplicationContext context;
private UserPrincipalDetailsService userPrincipalDetailsService;
private UserRepository userRepository;
#Lazy
#Autowired
private PasswordEncoder encoder;
public SecurityConfiguration(UserPrincipalDetailsService userPrincipalDetailsService, UserRepository userRepository, ApplicationContext applicationContext) {
this.userPrincipalDetailsService = userPrincipalDetailsService;
this.userRepository = userRepository;
this.context = applicationContext;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.addFilter(new JwtAuthenticationFilter(authenticationManager(), encoder, context))
.addFilter(new JwtAuthorizationFilter(authenticationManager(), this.userRepository, context))
.authorizeRequests()
.antMatchers(HttpMethod.POST,"/login").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers(HttpMethod.POST,"/admin/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.GET,"/admin/**").permitAll()
.antMatchers(HttpMethod.PUT,"/admin/**").hasAnyAuthority(Constants.ADMIN, Constants.TRAINER)
.antMatchers(HttpMethod.GET,"/trainingsplan/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.POST,"/trainingsplan/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.PUT,"/trainingsplan/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.GET,"/trainingsplanexecuted/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.POST,"/trainingsplanexecuted/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.PUT,"/trainingsplanexecuted/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.GET,"/subscription/**").hasAnyAuthority(Constants.TRAINER, Constants.ADMIN, Constants.CUSTOMER)
.antMatchers(HttpMethod.POST,"/subscription/**").hasAnyAuthority(Constants.TRAINER, Constants.ADMIN)
.antMatchers(HttpMethod.PUT,"/subscription/**").hasAnyAuthority(Constants.TRAINER, Constants.ADMIN)
.antMatchers(HttpMethod.GET,"/trainer/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.POST,"/trainer/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.PUT,"/trainer/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.GET,"/customer/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.POST,"/customer/**").hasAuthority(Constants.ADMIN)
.antMatchers(HttpMethod.PUT,"/customer/**").hasAuthority(Constants.ADMIN)
.and().
httpBasic().and().csrf().disable();
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("*"));
configuration.setAllowedMethods(Arrays.asList("*"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.addAllowedOriginPattern("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
#Bean
DaoAuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
daoAuthenticationProvider.setUserDetailsService(this.userPrincipalDetailsService);
return daoAuthenticationProvider;
}
#Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
I can ensure you that the authorities in the UserPrincipal are correct (in my example "TRAINER").
If there is something missing, please tell me.
I would be really thankful if someone could help me.
the above things..................
Related
I want to require authentication for my endpoints that start with "/chat/..." (on GET requisitions). I have done some basic configuration but it doesn't seem to be working. Even after authenticating a user and using its generated JWT Token, Postman still returns code 403 (Forbidden) for me. What could I be doing wrong?
My SecurityConfig class:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
private Environment env;
#Autowired
private JWTUtil jwtUtil;
private static final String[] PUBLIC_MATCHERS_GET = {
"/usuarios/**",
};
private static final String[] PUBLIC_MATCHERS = {
"/login/**"
};
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable();
http.authorizeRequests()
.antMatchers(HttpMethod.GET, PUBLIC_MATCHERS_GET).permitAll()
.antMatchers(PUBLIC_MATCHERS).permitAll()
.antMatchers(HttpMethod.GET, "/chat/**").authenticated()
.anyRequest().authenticated();
http.addFilter(new JWTAuthenticationFilter(authenticationManager(), jwtUtil));
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}
#Bean
CorsConfigurationSource corsConfigurationSource() {
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
return source;
}
#Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
My ChatController class:
import com.example.chatonline.domain.Mensagem;
import com.example.chatonline.domain.Usuario;
import com.example.chatonline.services.ChatService;
import com.example.chatonline.services.UsuarioService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import java.util.List;
#RestController
#RequestMapping(value = "/chat")
public class ChatController {
#Autowired
private ChatService chatService;
#Autowired
UsuarioService usuarioService;
#PreAuthorize("isAuthenticated()")
#GetMapping(value = "/usuarios")
public ResponseEntity<List<Usuario>> findOnlineUsers(){
List<Usuario> usuarios = usuarioService.findByOnlineUsers();
return ResponseEntity.ok().body(usuarios);
}
#PreAuthorize("isAuthenticated()")
#GetMapping(value = "/mensagens")
public ResponseEntity<List<Mensagem>> findMessages(){
List<Mensagem> obj = chatService.findMessages();
return ResponseEntity.ok().body(obj);
}
#PostMapping
public ResponseEntity<Void> insertMessage(#RequestBody Mensagem obj){
obj = chatService.insertMessage(obj);
return ResponseEntity.status(HttpStatus.CREATED).build();
}
#RequestMapping(value = "/mensagens/{id}", method = RequestMethod.DELETE)
public ResponseEntity<Void> deleteMessage(#PathVariable Integer id){
chatService.deleteMessage(id);
return ResponseEntity.noContent().build();
}
}
I'm trying to configure Spring Security on a Spring Boot application as follows and as a result Postman gives 401 Unauthorized ,please can anyone help me to solve this error
controller
package com.example.demo.controller;
import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
#CrossOrigin(origins = "http://localhost:8080")
#RestController
#RequestMapping("/api")
public class UserController {
#Autowired
private UserService userService;
#PostConstruct
public void initRoleAndUser() {
userService.initRoleAndUser();
}
#PostMapping({"/registerNewUser"})
public User registerNewUser(#RequestBody User user) {
return userService.registerNewUser(user);
}
#GetMapping({"/forAdmin"})
#PreAuthorize("hasRole('Admin')")
public String forAdmin(){
return "This URL is only accessible to the admin";
}
#GetMapping({"/forUser"})
#PreAuthorize("hasRole('User')")
public String forUser(){
return "This URL is only accessible to the user";
}
}
configuration
package configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private JwtRequestFilter jwtRequestFilter;
#Autowired
private UserDetailsService jwtService;
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors();
httpSecurity.csrf().disable()
.authorizeRequests().antMatchers("/authenticate", "/registerNewUser").permitAll()
.antMatchers(HttpHeaders.ALLOW).permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
;
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(jwtService).passwordEncoder(passwordEncoder());
}
}
JwtService
package com.example.demo.service;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.example.demo.dao.UserDao;
import com.example.demo.Util.JwtUtil;
import com.example.demo.entity.User;
import com.example.demo.entity.JwtResponse;
import com.example.demo.entity.JwtRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.util.HashSet;
import java.util.Set;
#Service
public class JwtService implements UserDetailsService {
#Autowired
private JwtUtil jwtUtil;
#Autowired
private UserDao userDao;
private AuthenticationManager authenticationManager;
public JwtResponse createJwtToken(JwtRequest jwtRequest) throws Exception {
String userName = jwtRequest.getName();
String userPassword = jwtRequest.getUser_code();
authenticate(userName, userPassword);
UserDetails userDetails = loadUserByUsername(userName);
String newGeneratedToken = jwtUtil.generateToken(userDetails);
User user = userDao.findById(userName).get();
return new JwtResponse(user, newGeneratedToken);
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDao.findById(username).get();
if (user != null) {
return new org.springframework.security.core.userdetails.User(
user.getName(),
user.getUser_code(),
getAuthority(user)
);
} else {
throw new UsernameNotFoundException("User not found with username: " + username);
}
}
private Set getAuthority(User user) {
Set<SimpleGrantedAuthority> authorities = new HashSet<>();
user.getRoles().forEach(role -> {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleName()));
});
return authorities;
}
private void authenticate(String userName, String userPassword) throws Exception {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userName, userPassword));
} catch (DisabledException e) {
throw new Exception("USER_DISABLED");
} catch (BadCredentialsException e) {
throw new Exception("INVALID_CREDENTIALS");
}
}
}
I use postman to test and when I do a GET to "http://localhost:8080/forAdmin", I get an error 401 Unauthorized
You must load the user into memory from the database, and it should be converted to UserDetails. The user details has Roles, or Authorities. It dependes what you choose. Maybe these articles can help :)
https://www.baeldung.com/spring-security-authentication-with-a-database
https://www.baeldung.com/role-and-privilege-for-spring-security-registration
Can any one suggest me another solution or how i can fixed this issue please.and thank's by advance
cotroller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.example.demo.entity.JwtRequest;
import com.example.demo.entity.JwtResponse;
import com.example.demo.service.JwtService;
#RestController
#CrossOrigin
public class JwtController {
#Autowired
private JwtService jwtService;
#PostMapping({"/authenticate"})
public JwtResponse createJwtToken(#RequestBody JwtRequest jwtRequest) throws Exception {
return jwtService.createJwtToken(jwtRequest);
}
}
service
package com.example.demo.service;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.example.demo.dao.UserDao;
import com.example.demo.Util.JwtUtil;
import com.example.demo.entity.User;
import com.example.demo.entity.JwtResponse;
import com.example.demo.entity.JwtRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import java.util.HashSet;
import java.util.Set;
#Service
public class JwtService implements UserDetailsService {
#Autowired
private JwtUtil jwtUtil;
#Autowired
private UserDao userDao;
#Autowired
private AuthenticationManager authenticationManager;
public JwtResponse createJwtToken(JwtRequest jwtRequest) throws Exception {
String userName = jwtRequest.getName();
String userPassword = jwtRequest.getUser_code();
authenticate(userName, userPassword);
UserDetails userDetails = loadUserByUsername(userName);
String newGeneratedToken = jwtUtil.generateToken(userDetails);
User user = userDao.findById(userName).get();
return new JwtResponse(user, newGeneratedToken);
}
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDao.findById(username).get();
if (user != null) {
return new org.springframework.security.core.userdetails.User(
user.getName(),
user.getUser_code(),
getAuthority(user)
);
} else {
throw new UsernameNotFoundException("User not found with username: " + username);
}
}
private Set getAuthority(User user) {
Set<SimpleGrantedAuthority> authorities = new HashSet<>();
user.getRoles().forEach(role -> {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleName()));
});
return authorities;
}
private void authenticate(String userName, String userPassword) throws Exception {
try {
authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(userName, userPassword));
} catch (DisabledException e) {
throw new Exception("USER_DISABLED");
} catch (BadCredentialsException e) {
throw new Exception("INVALID_CREDENTIALS");
}
}
}
WebSecurityConfiguration
package configuration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
#Autowired
private JwtRequestFilter jwtRequestFilter;
#Autowired
private UserDetailsService jwtService;
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors();
httpSecurity.csrf().disable()
.authorizeRequests().antMatchers("/authenticate", "/registerNewUser").permitAll()
.antMatchers(HttpHeaders.ALLOW).permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
;
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(jwtService).passwordEncoder(passwordEncoder());
}
}
error
Description:
Field authenticationManager in com.example.demo.service.JwtService required a bean of type 'org.springframework.security.authentication.AuthenticationManager' that could not be found.
The injection point has the following annotations:
- #org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'org.springframework.security.authentication.AuthenticationManager' in your configuration.
i too had a same problem i fixed by
declaring name of the bean
#Bean(name= BeanIds.AUTHENTICATION_MANAGER)
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
spring security not using details from database for authentication and generating password in console also not using my customized login form.
Main class--
package mis.main;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#SpringBootApplication
#ComponentScan({"mis.controller", "mis.services"})
#EntityScan("mis.entity")
#EnableJpaRepositories("mis.dao")
public class BitmisApplication {
public static void main(String[] args) {
SpringApplication.run(BitmisApplication.class, args);
}
}
CustomUserDetails--
package mis.config;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import mis.entity.Roles;
import mis.entity.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class CustomUserDetails implements UserDetails {
private User user;
public CustomUserDetails(User user) {
this.user = user;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<Roles> roles = user.getRoles();
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Roles role : roles) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
return authorities;
}
#Override
public String getPassword() {
return user.getPassword();
}
#Override
public String getUsername() {
return user.getUsername();
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return true;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return user.isEnabled();
}
}
MyConfig class--
package mis.config;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
#Configuration
#EnableAutoConfiguration
#EnableWebSecurity
public class MyConfig extends WebSecurityConfigurerAdapter {
#Bean
public UserDetailsService userDetailsService() {
return new UserDetailsServiceImpl();
}
#Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService());
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").hasAnyAuthority("USER", "CREATOR", "EDITOR", "ADMIN")
.antMatchers("/new").hasAnyAuthority("ADMIN", "CREATOR")
.antMatchers("/admin/**").hasAnyAuthority("ADMIN", "EDITOR")
.antMatchers("/delete/**").hasAuthority("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin().permitAll()
.and()
.logout().permitAll()
.and()
.exceptionHandling().accessDeniedPage("/403")
;
}
}
UserDetailsServiceImpl--
package mis.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import mis.entity.User;
import mis.dao.UserRepository;
public class UserDetailsServiceImpl implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
User user = userRepository.getUserByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("Could not find user");
}
return new CustomUserDetails(user);
}
}
UserRepository--
" package mis.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import mis.entity.User;
public interface UserRepository extends JpaRepository<User, Long> {
#Query("SELECT u FROM User u WHERE u.username = :username")
public User getUserByUsername(#Param("username") String username);
}"
I think springboot is not able to read this authentication files
the spring application can't find your configs since your project structure is faulty and you have added faulty custom configuration.
the #SpringBootApplication class will per default scan the package it is in mis.main and all packages below this one (mis.main...* etc) in order to find all spring annotated classes and load them.
You have placed your configuration files in mis.config which is not directly below mis.main, and you have files in mis.entity which is also not beneath mis.main.
You have also added
#ComponentScan({"mis.controller", "mis.services"})
#EntityScan("mis.entity")
in order to try to find the configuration files but failed to specify mis.config as a folder to scan in.
The simplest solution would be to
remove to two annotations i mentioned above.
move the main class into the package mis and then delete the package mis.main so that the main class is at the project root.
some other things:
#Bean
public DaoAuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService());
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
is not needed and can be removed, because you have declared a custom UserDetailsService and PasswordEncoder as beans, they will automatically be picked up by the system and included into spring and it will set up DaoAuthentication for you automatically.
If you are learning you should read the spring security reference docs all this is mentioned there.
I have an OAuth2 implementation that is working fine for the grant type = password. Now I need to add a logic of restricting the same user/password combination to be allowed to login again if the user is logged in earlier.
For that, I researched and figured that I to create a new class (MyDefaultTokenService) that extends the DefaultTokenServices class and then add my logic in the overriden createAccessToken method. But for some reason when I debug and test, I dont hit the breakpoints placed in MyDefaultTokenService class. It always hits the Springboot's DefaultTokenServices class. I dont know where I am going wrong, could somebody please.
AuthorizationConfiguration.java
package com.company.config;
import java.util.Arrays;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.bind.RelaxedPropertyResolver;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import com.alcord.enums.Authorities;
import com.alcord.model.Account;
#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;
#Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
#Autowired
#Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
final TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer()));
endpoints.tokenStore(tokenStore()).tokenEnhancer(tokenEnhancerChain)
.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_DRIVER.name(),
Authorities.ROLE_PASSENGER.name())
.authorizedGrantTypes("password", "refresh_token", "authorization_code", "implicit")
.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);
}
#Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
#Bean
#Primary
public DefaultTokenServices tokenServices() {
MyTokenService tokenService = new MyTokenService();
tokenService.setTokenStore(tokenStore());
tokenService.setSupportRefreshToken(true);
tokenService.setTokenEnhancer(tokenEnhancer());
return tokenService;
}
class MyTokenService extends DefaultTokenServices {
public MyTokenService() {
}
#Override
public OAuth2AccessToken readAccessToken(String accessToken) {
return super.readAccessToken(accessToken);
}
#Override
public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
OAuth2AccessToken token = super.createAccessToken(authentication);
Account account = (Account) authentication.getPrincipal();
// This is where I will add my logic when it hits the breakpoint.
return token;
}
#Override
public OAuth2AccessToken refreshAccessToken(String refreshTokenValue, TokenRequest tokenRequest)
throws AuthenticationException {
OAuth2AccessToken token = super.refreshAccessToken(refreshTokenValue, tokenRequest);
return token;
}
}
}
Resource Server Configuration
package com.company.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import com.alcord.security.CustomAuthenticationEntryPoint;
import com.alcord.security.CustomLogoutSuccessHandler;
#Configuration
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
// The DefaultTokenServices bean provided at the AuthorizationConfig
#Autowired
private DefaultTokenServices tokenServices;
// The TokenStore bean provided at the AuthorizationConfig
#Autowired
private TokenStore tokenStore;
#Autowired
private CustomAuthenticationEntryPoint customAuthenticationEntryPoint;
#Autowired
private CustomLogoutSuccessHandler customLogoutSuccessHandler;
#Override
public void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(customAuthenticationEntryPoint).and().logout()
.logoutUrl("/oauth/logout").logoutSuccessHandler(customLogoutSuccessHandler).and().csrf().disable()
.headers().frameOptions().disable().exceptionHandling().and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll().antMatchers("/api/v1/login/**").permitAll()
.antMatchers("/api/v1/admin/**").permitAll().antMatchers("/api/v1/test/**").permitAll()
.antMatchers("/oauth/token").permitAll().antMatchers("/api/**").authenticated();
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.tokenServices(tokenServices).tokenStore(tokenStore).resourceId("oauth2_id");
}
}
The answer to this: needed a call to AuthorizationServerEndpointsConfigurer.tokenServices in the configure method.
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
final TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer()));
endpoints
.tokenStore(tokenStore())
.tokenServices(tokenServices()) // missed this!
.tokenEnhancer(tokenEnhancerChain)
.authenticationManager(authenticationManager);
}