Spring Security cannot authenticate user although the user is exist in database - spring

please help me with this, I'm new to spring security and I have been trying to logged in but Spring Security just don't let me access and I still can't figure. My CustomUserDetailsService still working and print out the account I intend to use to login
SecurityConfig
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Autowired
BCryptPasswordEncoder passwordEncoder;
#Bean
#Override
protected AuthenticationManager authenticationManager() throws Exception {
// TODO Auto-generated method stub
return super.authenticationManager();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder builder) throws Exception {
builder.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login", "/logout").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.defaultSuccessUrl("/admin", true)
.and()
.exceptionHandling().accessDeniedPage("/accessDenied");
}
}
CustomUserDetailsService
#Service("customUserDetailsService")
#Transactional
#Slf4j
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Autowired
private RoleRepository roleRepository;
#Autowired
private PasswordEncoder passwordEncoder;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findUsersByUsername(username);
if (user == null) {
log.error("User not found");
throw new UsernameNotFoundException("User not found");
} else {
log.info("User found in the dbs", username);
System.out.println(user.getUsername());
System.out.println(user.getPassword());
}
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
//looping all roles from user -> for each role, create a new simpleGranted
//auth by passing the role name
for (Role role : user.getRoles()) {
authorities.add(new SimpleGrantedAuthority(role.getName()));
}
//return spring sec user (core userDetail)
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities);
}
}
User
#Entity
#Data
#NoArgsConstructor
#AllArgsConstructor
#Table(name = "user",
uniqueConstraints = {
#UniqueConstraint(columnNames = "username"),
#UniqueConstraint(columnNames = "email")
})
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#NotBlank(message = "Username is required")
private String username;
#NotBlank(message = "Password is required")
private String password;
#Email
#NotBlank(message = "Email is required")
private String email;
private Instant created;
private boolean enabled;
//load all the roles whenever load an user
#ManyToMany(fetch = FetchType.EAGER)
private Collection<Role> roles = new ArrayList<>();
}
Everytime I logged in with the right account, Spring Security always give me "Bad Credentials"
Edited: username and password (both passwords are 123)

It isn't working because you didn't specify the implementation of the UserDetailsService.So what spring is actually doing is, It is using the default username(user) and the random password(generated at runtime) as the required credentials. To make spring use your custom user details, please replace
This:
#Autowired
private UserDetailsService userDetailsService;
With that:
#Autowired
#Qualifier("customUserDetailsService")
private UserDetailsService userDetailsService;

Related

how get authfication user from PostMapping method controller

I can't get authfication user from post request method in controller. I am tryed use #AuthficationPrincipal UserDetails, Principal and SecurityContextHolder but his returns null. It's need me for upload images to datebase. Help me solve this problem please. (.csrf disabled)
Controller:
#Controller
#RequestMapping("/images")
public class ImageController {
private final ImageService imageService;
private final UserService userService;
#Autowired
public ImageController(ImageService imageService,
UserService userService) {
this.imageService = imageService;
this.userService = userService;
}
#PostMapping("/load-image")
public String loadImage(#RequestParam("image") MultipartFile image,
#AuthenticationPrincipal UserDetails user){
User authUser = userService.findUserByNickname(user.getUsername());
imageService.load(image, authUser);
return "redirect:/users/show/"+authUser.getId();
}
}
Security config:
#Configuration
#EnableWebSecurity
public class SecurityCFG extends WebSecurityConfigurerAdapter {
private final BCryptPasswordEncoder bCryptPasswordEncoder;
private final MyUserDetailsService userDetailsService;
#Autowired
public SecurityCFG(BCryptPasswordEncoder bCryptPasswordEncoder,
MyUserDetailsService userDetailsService) {
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
this.userDetailsService = userDetailsService;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
csrf().disable()
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/orders/**").authenticated()
.antMatchers("/users/orders").authenticated()
.antMatchers("/admin/**").hasRole("ADMIN")
.and()
.formLogin().loginPage("/users/login")
.usernameParameter("login")
.passwordParameter("password")
.and()
.logout().logoutSuccessUrl("/users/login?logout").permitAll();
}
}
UserDetails Service:
#Service
public class MyUserDetailsService implements UserDetailsService {
private final UserService userService;
#Autowired
public MyUserDetailsService(UserService userService) {
this.userService = userService;
}
#Override
#Transactional
public UserDetails loadUserByUsername(final String login){
User user;
if(login.contains("#")){
user = userService.findUserByEmail(login);
}else{
user = userService.findUserByNickname(login);
}
if(user!=null){
List<GrantedAuthority> authorities = getUserAuthority(user.getRoles());
return buildUserForAuthentication(user, authorities);
}
throw new BadCredentialsException(String.format("Логин %s неверный",login));
}
private List<GrantedAuthority> getUserAuthority(Set<Role> userRoles) {
Set<GrantedAuthority> roles = new HashSet<>();
for (Role role : userRoles) {
roles.add(new SimpleGrantedAuthority(role.getRole()));
}
return new ArrayList<>(roles);
}
private UserDetails buildUserForAuthentication(User user,
List<GrantedAuthority> authorities) {
UserDetails userDetails = new
org.springframework.security.core.userdetails.User(user.getNickname(),
user.getPassword(),user.isActive(), true,true,
user.isAccountNonLocked(), authorities);
new AccountStatusUserDetailsChecker().check(userDetails);
return userDetails;
}
}
Its because you are using #Controller and not #RestController
If you want to get your controller to work properly you should be using #RestController instead of only #Controller on your rest controller classes. #RestController is actually a shorthand for #Controller and #ResponseBody which basically tells spring that you want to serialize all responses from functions to something like json, or xml etc. etc.
you can read more about the annotation here.
Removing #RequestMapping("/images") from the controller fixed this problem, but I don't understand why this is happening.

Access is denied when user login as 'ADMIN' role but not in 'USER' role

WebSecurityConfiguration
#Configuration
#EnableWebSecurity
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
#Autowired
private MyUserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
String loginPage = "/login";
String logoutPage = "/logout";
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers(loginPage).permitAll()
//.antMatchers("/registration").permitAll()
.antMatchers("/user/**").hasAnyAuthority("USER","ADMIN")
.anyRequest().authenticated()
.and()
.csrf().disable()
.formLogin()
.loginPage(loginPage)
.loginPage("/")
.failureUrl("/login?error=true")
.defaultSuccessUrl("/user")
.usernameParameter("username")
.passwordParameter("password")
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher(logoutPage))
.logoutSuccessUrl(loginPage).and().exceptionHandling();
}
}
MyUserDetailsService
#Service
public class MyUserDetailsService implements UserDetailsService {
#Autowired
private UserService userService;
#Override
#Transactional
public UserDetails loadUserByUsername(String userName) {
User user = userService.findUserByUserName(userName);
List<GrantedAuthority> authorities = getUserAuthority(user.getRoles());
return buildUserForAuthentication(user, authorities);
}
private List<GrantedAuthority> getUserAuthority(Set<Role> userRoles) {
Set<GrantedAuthority> roles = new HashSet<>();
for (Role role : userRoles) {
roles.add(new SimpleGrantedAuthority(role.getRole()));
}
return new ArrayList<>(roles);
}
private UserDetails buildUserForAuthentication(User user, List<GrantedAuthority> authorities) {
return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(),
user.getActive(), true, true, true, authorities);
}
}
Model
#Entity
#Table(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
private long id;
#Column(name = "username")
private String userName;
#Column(name = "password")
private String password;
#Column(name = "active")
private Boolean active;
#ManyToMany(cascade = CascadeType.MERGE)
#JoinTable(name = "user_role", joinColumns = #JoinColumn(name = "user_id"), inverseJoinColumns = #JoinColumn(name = "role_id"))
private Set<Role> roles;
// getters and setters
}
#Entity
#Table(name = "roles")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "role_id")
private int id;
#Column(name = "role")
private String role;
// getters and setters
}
I got error Spring Boot security login. I got error in admin role login. But when I logged in user role it is working well. I don't understand why this is happening?
When I am trying to login as admin it redirects me http://localhost:8080/error page show this in body:
{"timestamp":"2020-09-11T14:10:05.108+00:00","status":999,"error":"None","message":""}
But when trying to login as user it works fine.
Probably you may have messed up with antMatchers!!
In your code you've mentioned like
.antMatchers("/user/**").hasAnyAuthority("USER","ADMIN")
Which means both user and admin can have access to url's that match "/user/**" ie,. all url's with prefix "/user/"
If incase you have a url for admin which with "/admin/*
" , then you should give access to "/admin/**" too!
Then you have to add one more antMatcher like
.antMatchers("/admin/**).hasRole("ADMIN")
which will give access only to admin url's ie,. with prefix "/admin/**"

String Boot REST security Error : type=Forbidden, status=403

This project I have used Spring boot, security authentication, JPA and REST
This gives me 403 error, which is of role base error. I have tried for 2 days could not solve please help.
Here I am sharing code.
This is my Security config class have roles based /hello for all user and /admin/all and /admin/add for admin user.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UserDetailsService userDetailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(encodePsw());
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests().antMatchers("/api/secure/admin/**").hasRole("ADMIN").antMatchers("/api/secure/**")
.hasAnyRole("USER", "ADMIN").anyRequest().authenticated().and().formLogin().permitAll();
}
#Bean
public BCryptPasswordEncoder encodePsw() {
return new BCryptPasswordEncoder();
}
}
This is my Controller class have 3 method which is or 3 role based /hello for all user and /admin/all and /admin/add for admin user.
#RestController
#RequestMapping("/api/secure")
public class AdminController {
#Autowired
private UserRepository userRepo;
#Autowired
private BCryptPasswordEncoder passEncp;
#RequestMapping(value = "/hello")
public String hello() {
return "Hello..";
}
//#PreAuthorize("hasAnyRole('ADMIN')")
#RequestMapping(value = "/admin/add", method = RequestMethod.POST)
public String addUserByAdmin(#RequestBody User user) {
user.setPassword(passEncp.encode(user.getPassword()));
userRepo.save(user);
return "Add User Successfully";
}
//#PreAuthorize("hasAnyRole('ADMIN')")
#GetMapping("/admin/all")
public String securedHello() {
return "Secured Hello";
}
}
This is Role bean
#Entity
#Data
public class Role {
#Id
#GeneratedValue
private int roleId;
private String role;
}
This User Bean
#Entity
#Setter
#Getter
public class User {
#Id
private int userId;
private String username;
private String password;
private String email;
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
#JoinTable(name="user_role", joinColumns = #JoinColumn(name="user_id"), inverseJoinColumns = #JoinColumn(name="role_id"))
private Set<Role> roles;
}
UserRepository interface
public interface UserRepository extends JpaRepository<User, Integer> {
User findByUsername(String username);
}
CustomUserDetails class
I think the problem in this part. I have save role like ROLE_USER, ROLE_ADMIN also tried without ROLE_
#Getter
#Setter
public class CustomUserDetails implements UserDetails {
private User user;
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getRoles().stream().map(role -> new SimpleGrantedAuthority(""+role))
.collect(Collectors.toList());
}
#Override
public String getPassword() {
// TODO Auto -generated method stub
return user.getPassword();
}
#Override
public String getUsername() {
// TODO Auto-generated method stub
return user.getUsername();
}
Service class CustomUserDetailsService
#Service
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepo;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepo.findByUsername(username);
CustomUserDetails userDetails = null;
if(user!=null) {
userDetails = new CustomUserDetails();
userDetails.setUser(user);
}else {
throw new UsernameNotFoundException("User not found with name "+username);
}
return userDetails;
}
}
I have another Controller class having different URL mapping which is running
WebSecurityConfigurerAdapter has a overloaded configure message that takes WebSecurity as argument which accepts ant matchers on requests to be ignored.
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/hello");
}
You can ignore /hello based url as its for all users.
Actual:
return user.getRoles().stream().map(role->new SimpleGrantedAuthority("ROLE_"+role)).collect(Collectors.toList());
Expected:
return user.getRoles().stream().map(role->new SimpleGrantedAuthority("ROLE_"+role.getRole_name())).collect(Collectors.toList());

Spring Security basic auth always getting 401

I learning Spring, and I integrated Spring security into my current APIs. To keep things simple, I am starting with Basic Auth.
However, the issue that I am facing is that, if I don't provide the credentials, I get the standard 401 along with a JSON response:
{
"timestamp": "2018-07-07T18:40:00.752+0000",
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/courses"
}
But if I do pass correct credentials, I get 401, but without any response body.
Here's my WebSecurityConfiguration:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
DetailsService detailsService;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(detailsService)
.passwordEncoder(User.encoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().disable();
}
}
Here's my DetailsService:
#Component
public class DetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByEmail(username);
if (user == null) {
throw new UsernameNotFoundException("User with email " + username + " was not found");
}
return new org.springframework.security.core.userdetails.User(
user.getEmail(),
user.getPassword(),
AuthorityUtils.createAuthorityList(user.getRoles())
);
}
}
I should point this out that I am looking up user by email instead of username.
Here's my user entity:
#Entity
#Table(name = "users")
public class User extends BaseEntity {
public static final PasswordEncoder encoder = new BCryptPasswordEncoder();
#Column(name = "first_name")
private String firstName;
#JoinColumn(name = "last_name")
private String lastName;
private String email;
#JsonIgnore
private String password;
#JsonIgnore
private String[] roles;
public User(String email, String firstName, String lastName, String password,
String[] roles) {
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
setPassword(password);
this.roles = roles;
}
// getters and setters
}
First: check that user.getRoles() is not throwing a LazyInitializationException
Second: if hash has been generated online, BCryptPasswordEncoder might not work

Get username in session Spring Security

I am in doubt as to how to get the user name in the session. I am using Spring Security 4.2
I have my Class Usuario
#Entity
#Data
public class Usuario {
#Id #GeneratedValue
private Integer id;
private String login;
private String senha;
private String papel;
}
My class UsuarioController
#Named
#ViewScoped
public class UsuarioController {
#Autowired
private UsuarioRepository usuarioRepository;
#Getter #Setter
private List<Usuario> usuarios;
#Getter #Setter
private Usuario usuario = new Usuario();
}
And my class SecurityConfig, which plays the role of the filter, already built into Spring Security.
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private UsuarioRepository usuarioRepository;
#Override
protected void configure(HttpSecurity http) {
try {
http.csrf().disable();
http
.userDetailsService(userDetailsService())
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/cliente.jsf").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.jsf")
.permitAll()
.failureUrl("/login.jsf?error=true")
.defaultSuccessUrl("/cliente.jsf")
.and()
.logout()
.logoutSuccessUrl("/login.jsf");
}
catch (Exception ex) {
throw new RuntimeException(ex);
}
}
#Override
protected UserDetailsService userDetailsService() {
List<Usuario> usuarios = usuarioRepository.findAll();
List<UserDetails> users = new ArrayList<>();
for(Usuario u: usuarios){
UserDetails user = new User(u.getLogin(), u.getSenha(), AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_"+u.getPapel()));
users.add(user);
} return new InMemoryUserDetailsManager(users);
}
}
I already researched other posts in the forum, did not help, any tips? Do I need to create another class?
If you want to get the username of the current user authenticated with Spring Security, you could use the following:
final String currentUserName = SecurityContextHolder.getContext().getAuthentication().getName();
Here, we find the current Authentication and query it for the username. For password-based authentiction, getName() returns user's login.
You can create your own SecurityUtility class like this:
public final class SecurityUtils {
private SecurityUtils() {
}
public static String getUserName() {
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
String userName = null;
if (authentication != null) {
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
userName = userDetails.getUsername();
}
return userName;
}
And call it from the class where you need the username, for example: SecurityUtils.getCurrentUserLogin();

Resources