I have a CustomerUserDetailsService class, which is part of an implementation of Spring Boot authentication. I have tested my code manually, and it works correctly, allowing me to successfully log in to my app. However, I am unable to work out how to test the CustomerUserDetailsService.
As a unit test, I believe I would need to mock the userRepository member variable, but whatever I try in my test fails, the reason being userRepository is set to null. I've tried adding the #Repository annotation to userRepository but am told that is not allowed because it is an interface. There's also the fact that loadUserByUsername returns an instance of CustomUserDetails, which is just an implementation of an interface, so I have no idea how I'd mock that dependency?
I've also tried doing some kind of integration test but had similar issues, probably due to incorrect annotations on the test itself. In an ideal world, I'd prefer a unit test and would be extremely grateful for any guidance as to how to set it up.
These are the relevant classes...
CustomerUserDetailsService:
package com.phil.urlshortener.security;
import com.phil.urlshortener.model.User;
import com.phil.urlshortener.repositories.UserRepository;
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;
public class CustomUserDetailsService implements UserDetailsService {
#Autowired private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("User not found");
}
return new CustomUserDetails(user);
}
}
User:
package com.phil.urlshortener.model;
import lombok.Data;
import javax.persistence.*;
#Data
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable = false, unique = true, length = 50)
private String username;
#Column(nullable = false, length = 64)
private String password;
}
UserRepository:
package com.phil.urlshortener.repositories;
import com.phil.urlshortener.model.User;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, Long> {
#Query("SELECT u FROM User u WHERE u.username = ?1")
User findByUsername(String username);
}
CustomUserDetails:
package com.phil.urlshortener.security;
import com.phil.urlshortener.model.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
public class CustomUserDetails implements UserDetails {
private final User user;
public CustomUserDetails(User user) {
this.user = user;
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
#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 true;
}
}
Maybe you forgot to use mockito annotation #RunWith(MockitoJUnitRunner.class).
Here it's the unit test for CustomUserDetailsService :
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.test.util.ReflectionTestUtils;
import static org.junit.Assert.*;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
#RunWith(MockitoJUnitRunner.class)
public class CustomUserDetailsService {
#Mock
private UserRepository userRepository;
private CustomUserDetailsService customUserDetailsService;
#Before
public void setUp() throws Exception {
customUserDetailsService = new CustomUserDetailsService(userRepository);
}
#Test
public void GIVEN_username_THEN_return_user_details() {
//Arrange
final String username = "existingUserName";
final User user = mock(User.class);
when(userRepository.findByUsername(username)).thenReturn(user);
//Act
final UserDetails userDetails = customUserDetailsService.loadUserByUsername(username);
//Assert
assertNotNull(userDetails);
assertEquals(user, ReflectionTestUtils.getField(userDetails, "user"));
}
}
Related
While there is user in the database, another user with exactly the same credentials is "successfully" inserted in the database...
Hello! I'm building my own ecommerce app and I included spring security. Now, while I was developing security part of the app, I tried it to see if it's working and once I entered desired info in the request body, for the first request the user was successfully inserted in the database, but when I tried to do it the second time, to check if the userExists which throws and error that user is already registered, works, it just added another user with the same credentials (name, lastname, mail and so). I go to userRepository to check if there is already the user with the same email, it makes sense what i wrote, but it doesnt work...Please help...Here are all the files:
EDIT : Mistakenly copied UserRegistrationController twice...So here is the userService.java:
package com.marin.thrift.service;
import com.marin.thrift.dao.UserRepository;
import com.marin.thrift.entity.User;
import lombok.AllArgsConstructor;
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.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
#Service
#AllArgsConstructor
public class UserService implements UserDetailsService {
private final UserRepository userRepository;
private final static String USER_NOT_FOUND = "user with email %s not found";
private final BCryptPasswordEncoder bCryptPasswordEncoder;
#Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
return userRepository.findByUsername(email).orElseThrow(()-> new UsernameNotFoundException(String.format(USER_NOT_FOUND, email)));
}
public String singUpUser(User user){
boolean userExists = userRepository.findByUsername(user.getEmail()).isPresent();
if(userExists){
return "user already in place";
}
String encodedPassword = bCryptPasswordEncoder.encode(user.getPassword());
user.setPassword(encodedPassword);
userRepository.save(user);
return "it works";
}
}
package com.marin.thrift.registration;
import lombok.AllArgsConstructor;
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;
#RestController
#RequestMapping(path = "api/v1/registration")
#AllArgsConstructor
public class UserRegistrationController {
private RegistrationService registrationService;
#PostMapping
public String register(#RequestBody registrationRequest request){
return registrationService.register(request);
}
}
package com.marin.thrift.registration;
import lombok.AllArgsConstructor;
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;
#RestController
#RequestMapping(path = "api/v1/registration")
#AllArgsConstructor
public class UserRegistrationController {
private RegistrationService registrationService;
#PostMapping
public String register(#RequestBody registrationRequest request){
return registrationService.register(request);
}
}
package com.marin.thrift.registration;
import com.marin.thrift.entity.Role;
import com.marin.thrift.entity.User;
import com.marin.thrift.service.UserService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
#Service
#AllArgsConstructor
public class RegistrationService {
private final EmailValidator emailValidator;
private final UserService userService;
public String register(registrationRequest request) {
Boolean isValidEmail = emailValidator.test(request.getEmail());
if (!isValidEmail){
throw new IllegalStateException("Email is not valid");
}
return userService.singUpUser(new User(request.getFirstName(), request.getLastName(),
request.getPassword(), request.getEmail(), Role.USER));
}
}
package com.marin.thrift.entity;
import lombok.Data;
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.util.Collection;
import java.util.Date;
#Entity
#Data
#Table(name = "users")
public class User implements UserDetails {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "first_name")
private String firstName;
#Column(name = "last_name")
private String lastName;
#Column(name = "date_of_birth")
private Date dateOfBirth;
#Column(name = "username")
private String username;
#Column(name = "password")
private String password;
#Column(name = "email")
private String email;
private Role role;
private Boolean locked = false;
private Boolean enabled = false;
public User(String firstName, String lastName, String password, String email, Role role) {
this.firstName = firstName;
this.lastName = lastName;
this.password = password;
this.email = email;
this.role = role;
}
public User() {
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.name());
return null;
}
#Override
public String getPassword() {
return password;
}
#Override
public String getUsername(){
return email;
}
#Override
public boolean isAccountNonExpired() {
return true;
}
#Override
public boolean isAccountNonLocked() {
return !locked;
}
#Override
public boolean isCredentialsNonExpired() {
return true;
}
#Override
public boolean isEnabled() {
return enabled;
}
}
package com.marin.thrift.security.config;
import com.marin.thrift.service.UserService;
import lombok.AllArgsConstructor;
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.crypto.bcrypt.BCryptPasswordEncoder;
#Configuration
#AllArgsConstructor
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final UserService userService;
private final BCryptPasswordEncoder bCryptPasswordEncoder;
#Override
protected void configure(HttpSecurity http) throws Exception{
http.csrf()
.disable().authorizeRequests()
.antMatchers("/api/v*/registration/**").permitAll()
.anyRequest().authenticated().and().formLogin();
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.authenticationProvider(daoAuthenticationProvider());
}
#Bean
public DaoAuthenticationProvider daoAuthenticationProvider(){
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(bCryptPasswordEncoder);
provider.setUserDetailsService(userService);
return provider;
}
}
package com.marin.thrift.registration;
import lombok.*;
#Getter
#AllArgsConstructor
#EqualsAndHashCode
#ToString
public class registrationRequest {
private final String firstName;
private final String lastName;
private final String password;
private final String email;
}
Without UserService it's hard to say what is happen. But if I see your jpa mapping I can guess that if you want unique entry per unique user, you have to delete generated column id. And instead you have to put #Id annotation on email. In this case you need also make changes in sql table.
Or as alternative you can stay by current mapping and simply conduct findByEmail before save entity. And if Optional is not empty - then user is already in database registred.
I just fixed my mistake. The mistake was in the database where I forgot to set email as unique. Once I did that, the code works perfectly.
I finished creating a simple Spring-boot project in which I can enter users and through the Get command it returns me the name (from a list of identical names) with the oldest entry date. Unfortunately, every time I ask for Get it returns this ERROR:
D:\>curl -G localhost:8080/demo/first?=Biagio
{"timestamp":"2020-10-04T22:46:35.996+00:00","status":404,"error":"Not Found","message":"","path":"/demo/first"}
And to each of my POST / Add requests like this ERROR:
D:\>curl localhost:8080/demo/add -d name=Giovanni -d email=giovanni#gmail.com -d surname=Jackie
{"timestamp":"2020-10-04T22:40:51.928+00:00","status":404,"error":"Not Found","message":"","path":"/demo/add"}
Below I enter the interested parties of my project to try to get something out of it, because I have been stuck for days now
AccessingDataMysqlApplication.java
package com.example.accessingdatamysql;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
#SpringBootApplication
public class AccessingDataMysqlApplication {
public static void main(String[] args) {
SpringApplication.run(AccessingDataMysqlApplication.class, args);
}
}
MainController.java
package com.example.accessingdatamysql.rest;
import javax.persistence.NoResultException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.example.accessingdatamysql.model.UserDto;
import com.example.accessingdatamysql.service.UserService;
#RestController
#RequestMapping("/demo")
public class MainController {
#Autowired
private UserService userService;
#Transactional
//#RequestMapping(value = "/add/", method = RequestMethod.POST)
#PostMapping(path="/demo/add")
public String addNewUser(#PathVariable("name") String name, #PathVariable("email") String email,
#PathVariable("surname") String surname) {
UserDto n = new UserDto();
n.setName(name);
n.setSurname(surname);
n.setEmail(email);
userService.create(n);
return "User Saved in DB";
}
#SuppressWarnings({ "rawtypes", "unchecked" })
//#RequestMapping(value = "/fetchUser/{name}", method = RequestMethod.GET)
#GetMapping("/demo/first")
public ResponseEntity<UserDto> fetchUser(#PathVariable("name") String name) {
System.out.println(name);
try {
UserDto namefound = userService.findFirstByName(name);
System.out.println("Name found");
ResponseEntity<UserDto> user = new ResponseEntity<UserDto>(namefound, HttpStatus.OK);
return user;
} catch(NoResultException ne) {
System.out.println("User not found");
return new ResponseEntity("User not found with name : " + name, HttpStatus.NOT_FOUND);
}
}
}
UserService.java
package com.example.accessingdatamysql.service;
import org.springframework.stereotype.Service;
import com.example.accessingdatamysql.model.UserDto;
#Service
public interface UserService {
UserDto findFirstByName(String name);
void create(UserDto user);
}
UserServiceImpl.java
package com.example.accessingdatamysql.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import com.example.accessingdatamysql.model.UserDto;
import com.example.accessingdatamysql.model.UserEntity;
import com.example.accessingdatamysql.repo.UserRepository;
import com.example.accessingdatamysql.util.UserMapper;
#Service
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository userRepository;
#Autowired
UserMapper mapper;
#Override
public UserDto findFirstByName(String name) {
UserEntity entity = userRepository.findFirstByName(name);
return mapper.toDtoMapper(entity);
}
#Override
public void create(UserDto user) {
UserEntity entity = mapper.toEntityMapper(user);
userRepository.create(entity);
}
}
UserMapper.java
package com.example.accessingdatamysql.util;
import org.mapstruct.Mapper;
import com.example.accessingdatamysql.model.UserDto;
import com.example.accessingdatamysql.model.UserEntity;
#Mapper(componentModel = "spring")
public interface UserMapper {
public UserEntity toEntityMapper (UserDto user);
public UserDto toDtoMapper (UserEntity userEntity);
}
UserRepository.java
package com.example.accessingdatamysql.repo;
import org.springframework.stereotype.Repository;
import com.example.accessingdatamysql.model.UserEntity;
#Repository
public interface UserRepository {
UserEntity findFirstByName(String name);
void create(UserEntity entity);
}
UserRepositoryImpl.java
package com.example.accessingdatamysql.service;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import org.springframework.stereotype.Component;
import com.example.accessingdatamysql.model.UserEntity;
import com.example.accessingdatamysql.repo.UserRepository;
#Component
public class UserRepositoryImpl implements UserRepository {
private final EntityManager em;
public UserRepositoryImpl(EntityManager entityManager) {
this.em = entityManager;
}
#Override
public UserEntity findFirstByName(String name) {
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<UserEntity> criteria = builder.createQuery(UserEntity.class);
Root<UserEntity> root = criteria.from(UserEntity.class);
criteria.select(root).where(builder.equal(root.get("name"), name));
criteria.orderBy(builder.asc(root.get("timestamp")));
TypedQuery<UserEntity> query = em.createQuery(criteria).setMaxResults(1);
return query.getSingleResult();
}
#Override
// per la creazione//
public void create(UserEntity entity) {
em.persist(entity);
}
}
UserDto.java
package com.example.accessingdatamysql.model;
import java.io.Serializable;
import java.sql.Timestamp;
public class UserDto implements Serializable {
/**
*
*/
private static final long serialVersionUID = -7621330660870602403L;
/**
*
*/
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Timestamp getTimestamp() {
return timestamp;
}
public void setTimestamp(Timestamp timestamp) {
this.timestamp = timestamp;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getSurname() {
return surname;
}
public void setSurname(String surname) {
this.surname = surname;
}
private Timestamp timestamp;
private String email;
private String surname;
}
If you need I can also insert User.java and the pom, but the pom has no problems as the dependencies are all correct.
You have an additional demo in your path descriptions for GET and POST methods, you should remove it:
#GetMapping("/demo/first")
#PostMapping(path = "/demo/first")
It should be :
#GetMapping("/first")
#PostMapping(path = "/first")
This because you have already defined demo in the RequestMapping annotation in the class level.
i'm building a Java SpringBoot(Back-End),Vuejs(front)aplication , and im on this part of seting the web security application.
On my User Class the constructor might be like this :
package com.miniAmazon;
import org.hibernate.annotations.GenericGenerator;
import org.springframework.security.core.GrantedAuthority;
import javax.persistence.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO,generator = "native")
#GenericGenerator(name="native",strategy="native")
private Long id;
#OneToMany(mappedBy = "users",fetch= FetchType.EAGER)
Set<Product> productsSet= new HashSet<>();
#OneToMany(mappedBy="users", fetch=FetchType.EAGER)
Set<Purchase> purchaseSet=new HashSet<>();
private String userRole;
private String userName;
private String userEmail;
private String userPassword;
public User(){}
public User( String userEmail,String userName,String userPassword,String userRole){
this.userName=userName;
this.userEmail=userEmail;
this.userPassword=userPassword;
this.userRole=userRole;
}
public void addPurchase(Purchase purchase){ purchaseSet.add(purchase);}
public Set<Purchase>getUserPurchaseSet(){
return purchaseSet;
}
////////////////////////////////////////////setter/////////////////////////////////////////////
///////////////////////////////////////////getters////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////
#Override
xxxxx
}
}
user repository like this:
package com.miniAmazon;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
#RepositoryRestResource
public interface UserRepository extends JpaRepository<User,String> {
User findByuserName (String usertName);
}
and the web security application code was settled in this way:
package com.miniAmazon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.GlobalAuthenticationConfigurerAdapter;
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.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.WebAttributes;
import org.springframework.security.web.authentication.logout.HttpStatusReturningLogoutSuccessHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.util.Arrays;
import java.util.Date;
#SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#Bean
public PasswordEncoder passwordEncoder(){
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
#Bean
public CommandLineRunner initData(ProductRepository productRepository, UserRepository userRepository, PurchaseRepository purchaseRepository){
return(args)->{
User user1=new User("lolo#gmail.com","lolo gomex",passwordEncoder().encode("24"),"buyer");
User user2=new User("jhony#gmail.com","Jack Ripper",passwordEncoder().encode("mole"),"buyer");
User user3=new User("gothic#gmail.com","demo gago",passwordEncoder().encode("adu"),"seller");
User user4=new User("grau#gmail.com","grau gomex",passwordEncoder().encode("24"),"seller");
User user5=new User("goiy#gmail.com","divan Ripper",passwordEncoder().encode("mole"),"buyer");
User user6=new User("gatti#gmail.com","guti gago",passwordEncoder().encode("adu"),"admin");
userRepository.save(user1);
userRepository.save(user2);
userRepository.save(user3);
userRepository.save(user4);
userRepository.save(user5);
userRepository.save(user6);
};
}
}
#Configuration
#EnableWebSecurity
class WebSecurityConfiguration extends GlobalAuthenticationConfigurerAdapter {
#Autowired
UserRepository userRepository;
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(inputName-> {
User user =userRepository.findByuserName(inputName);
if (user != null) {
return new User(user.getUserName(), user.getUserPassword(),
AuthorityUtils.createAuthorityList("USER"));--------------------ERROR
} else {
throw new UsernameNotFoundException("Unknown user: " + inputName);
}
});
}
}
#Configuration
#EnableWebSecurity
class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// http.cors();///de heroku tambien
http.authorizeRequests()
.antMatchers("/mini/all_products").permitAll()
.antMatchers("mini/all_products/user_dashboard/purchase/{id}").permitAll()
.antMatchers("/mini/all_product/registering").permitAll()
.antMatchers("/h2-console/**").permitAll()
.antMatchers("/rest/**").hasAuthority("ADMIN")
.antMatchers("/**").hasAuthority("USER")
.anyRequest().fullyAuthenticated();
/////Autorizaciones y permisos para los distintos niveles de seguridad que tendria el usuario segun su casificacion
http.formLogin()
.usernameParameter("name")
.passwordParameter("password")
.loginPage("/api/login");
//
http.logout().logoutUrl("/api/logout");
http.csrf().disable();
http.exceptionHandling().authenticationEntryPoint((req, res, exc) -> res.sendError(HttpServletResponse.SC_UNAUTHORIZED));
http.formLogin().successHandler((req, res, auth) -> clearAuthenticationAttributes(req));
http.formLogin().failureHandler((req, res, exc) -> res.sendError(HttpServletResponse.SC_UNAUTHORIZED));
http.logout().logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler());
// http.headers().frameOptions().disable();
http.headers().frameOptions().sameOrigin();
}
private void clearAuthenticationAttributes(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session != null) {
session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
}
}
}
but keeps throwing me an error in the first WebSecurityConfiguration in the cosntructor of the new User, saying once i hover it
Cannot resolve constructor 'User(java.lang.String, java.lang.String, java.util.List<org.springframework.security.core.GrantedAuthority>)'
Any idea about why this is happening .Really sorry for having exposed all this code!!.
And thanks in advance!!!
I have checked your code. In your WebSecurityConfig class
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(inputName-> {
User user =userRepository.findByuserName(inputName);
if (user != null) {
return new User(user.getUserName(), user.getUserPassword(),
AuthorityUtils.createAuthorityList("USER"));--------------------ERROR
}
});
}
You are returning user object like this :
return new User(user.getUserName(),
user.getUserPassword(),
AuthorityUtils.createAuthorityList("USER"));
which is wrong.
Because you have created constructor with different argument:
public User(String userEmail,
String userName,
String userPassword,
String userRole);
So pass arguments correctly. It will work.
You can also return like this:
return new User(null, user.getUserName(), user.getUserPassword(),
AuthorityUtils.createAuthorityList("USER"));
You should return org.springframework.security.core.userdetails.User instead of your com.miniAmazon.User:
if (user != null) {
return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getUserPassword(),
AuthorityUtils.createAuthorityList("USER"));
} else {
throw new UsernameNotFoundException("Unknown user: " + inputName);
}
since the loadUserByUsername method from UserDetailsService return a org.springframework.security.core.userdetails.UserDetails instance and org.springframework.security.core.userdetails.User implements org.springframework.security.core.userdetails.UserDetails.
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
I'm new with Java Spring, I need a guidance with Mockito.
I tried to test my Service Layer but it keeps failing to verify the mock username and email address.
I'm currently really confused on how should I do it properly.
Thanks you!
UserService.java
package com.example.newproject.newproject.service;
import com.example.newproject.newproject.entity.User;
import java.util.List;
public interface UserService {
boolean addUser(String username,String email);
List<User> viewAllUsers();
}
UserServiceImpl.java
package com.example.newproject.newproject.service.impl;
import com.example.newproject.newproject.entity.User;
import com.example.newproject.newproject.repository.UserRepository;
import com.example.newproject.newproject.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
#Service
#Transactional
public class UserServiceImpl implements UserService {
#Autowired
private UserRepository userRepository;
#Override
public boolean addUser(String username, String email) {
if(userRepository.findByUsernameAndEmail(username, email) == null)
{
User user = new User();
user.setUsername(username);
user.setEmail(email);
userRepository.save(user);
return false;
}else{
return true;
}
}
#Override
public List<User> viewAllUsers() {
return userRepository.findAll();
}
}
My Mock
#Test
public void testAddUser(){
Mockito.when(userRepository.findByUsernameAndEmail("Google","google#google.com")).then(invocationOnMock -> {
User user = new User();
return user;
});
boolean result = userService.addUser("Google","google#google.com");
Assert.assertFalse(result);
Mockito.verify(userRepository, Mockito.times(1)).save(userArgumentCaptor.capture());
User user = userArgumentCaptor.getValue();
Assert.assertEquals("Google", user.getUsername());
Assert.assertEquals("google#google.com", user.getEmail());
}
The error I get is
java.lang.AssertionError
during run
This question already has answers here:
Springboot Security hasRole not working
(3 answers)
Closed 4 years ago.
I am using spring security in my spring boot app.
My app works well with in-memory authentication.
But when users are loaded from the database it does not authenticate. It returns 403 access denied error code. UserDetailsService is able to fetch the user information from the database but I dont know where it is going wrong. I am new to spring.
here is my complete code related to security
User.java
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToMany;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;
import lombok.Data;
#Entity
#Table(name = "user")
#Data
public class User {
#Id
#NotNull
#GeneratedValue(strategy = GenerationType.AUTO)
private Long userId;
#Column(name = "USERNAME", unique = true)
#NotNull
private String username;
#Column(name = "PASSWORD")
#NotNull
private String password;
#Column(name = "DISPLAY_NAME")
private String displayName;
#ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "id")
private Set<Role> userRoles;
private String profilePicturePath;
}
Role.java
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Data;
#Entity
#Table(name = "roles")
#Data
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String role;
}
UserRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.cloudsofts.cloudschool.people.users.pojos.User;
#Repository("userRepository")
public interface UserRepository extends JpaRepository<User, Long> {
User findByUsername(String username);
}
RoleRepository.java
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.cloudsofts.cloudschool.people.users.pojos.Role;
#Repository
public interface RoleRepository extends JpaRepository<Role, Long> {
}
UserService.java
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import com.cloudsofts.cloudschool.people.users.pojos.User;
import com.cloudsofts.cloudschool.people.users.repositories.UserRepository;
#Service
public class UserService {
#Autowired
UserRepository userRep;
#Autowired
private PasswordEncoder passwordEncoder;
public List<User> getAllUsers() {
List<User> users = userRep.findAll();
return users;
}
public void addUser(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
userRep.save(user);
}
public void updateUser(User user) {
user.setPassword(passwordEncoder.encode(user.getPassword()));
userRep.save(user);
}
public void deleteUser(Long id) {
userRep.delete(id);
}
public User getUser(Long id) {
return userRep.findOne(id);
}
}
RoleService.java
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.cloudsofts.cloudschool.people.users.pojos.Role;
import com.cloudsofts.cloudschool.people.users.repositories.RoleRepository;
#Service
public class RoleService {
#Autowired
RoleRepository userRoleRep;
public void addUserRole(Role role) {
userRoleRep.save(role);
}
public void updateUserRole(Role role) {
userRoleRep.save(role);
}
public void deleteUserRole(Long id) {
userRoleRep.delete(id);
}
public Role getUserRole(Long id) {
return userRoleRep.findOne(id);
}
public List<Role> getAllUserRoles() {
return userRoleRep.findAll();
}
}
CustomUserDetails.java
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import lombok.Data;
#Data
public class CustomUserDetails implements UserDetails {
private static final long serialVersionUID = 1L;
private User user;
public CustomUserDetails(final User user) {
this.user = user;
}
public CustomUserDetails() {
}
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
final Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
Set<Role> roles = null;
if (user != null) {
roles = user.getUserRoles();
}
if (roles != null) {
for (Role role : roles) {
authorities.add(new SimpleGrantedAuthority(role.getRole()));
}
}
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 true;
}
}
CustomUserDetailsService.java
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 org.springframework.stereotype.Service;
import com.cloudsofts.cloudschool.people.users.pojos.CustomUserDetails;
import com.cloudsofts.cloudschool.people.users.pojos.Role;
import com.cloudsofts.cloudschool.people.users.pojos.User;
import com.cloudsofts.cloudschool.people.users.repositories.UserRepository;
#Service("userDetailsService")
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException(username);
} else {
System.out.println("______________________________________________________________");
System.out.println("username: " + user.getUsername());
System.out.println("password: " + user.getPassword());
System.out.println("Roles: ");
for (Role role : user.getUserRoles()) {
System.out.println(role.getRole());
}
System.out.println("______________________________________________________________");
return new CustomUserDetails(user);
}
}
}
SecurityConfig.java
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.Configuration;
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.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import com.cloudsofts.cloudschool.security.CustomUserDetailsService;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Qualifier("userDetailsService")
#Autowired
CustomUserDetailsService userDetailsService;
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
try {
auth.userDetailsService(this.userDetailsService).passwordEncoder(passwordEncoder());
System.out.println("_________________________________________________");
String username = SecurityContextHolder.getContext().getAuthentication().getName();
System.out.println("_________________________________________________");
System.out.println("You have logged in as " + username);
System.out.println("_________________________________________________");
} catch (Exception e) {
System.out.println("_________________________________________________");
System.out.println(e.getMessage());
System.out.println("_________________________________________________");
}
}
#Bean(name = "passwordEncoder")
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/*
* #Autowired public void configureGlobal(AuthenticationManagerBuilder auth)
* throws Exception {
* auth.inMemoryAuthentication().withUser("student").password("student").roles(
* "student").and().withUser("admin") .password("admin").roles("admin"); }
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// http.authorizeRequests().anyRequest().permitAll();
// http.authorizeRequests().antMatchers("/api/**").permitAll();
http.authorizeRequests().antMatchers("/student/**").hasAnyRole("student", "admin");
http.authorizeRequests().antMatchers("/api/admin/**").hasRole("admin");
http.authorizeRequests().antMatchers("/library/**").hasAnyRole("librarian", "admin");
http.httpBasic();
// http.formLogin().and().logout().logoutSuccessUrl("/login?logout").permitAll();
}
}
Screenshots
Postman Screenshot
Browser Screenshot
Users in the db
Roles in the db
User-Role mapping
Console output after giving the credentials
You seems to using the BCryptPasswordEncoder to encrypt and decrypt password. But 'Users' table screenshot shows the password in plain text. Can you validate the place where you are saving or updating the user, it is actually encoding the password and also the password encoder bean is of type 'BCryptPasswordEncoder'
I got the problem solved.
I had to add ROLE_ as a prefix to the roles.
Now everything works fine