java ee bean validation - java

I'm trying to implement user authorization on java ee 7. For validation entered data I use Bean validation annotations.
#NotNull(message = "Please enter email address")
#Column(name = "email")
private String email;
#NotNull(message = "Please enter password")
#Size(min = 6, max = 255)
#Column(name = "password")
private String password;
Also I have #PrePersist method which hash entered password
#PrePersist
public void updatePassword(String password) {
//some code
}
Here is a method where I register user:
#EJB
private UserService userService;
public void register() {
if (userService.getByEmail(email) == null) {
try {
userService.register(email, password);
//log in if users is created
authController.setEmail(email);
authController.setPassword(password);
authController.login();
} catch (Exception e) {
setErrorMessage("Validation error");
}
} else {
setErrorMessage("Please choose another email address");
}
}
UserService
#Stateless
public class UserService {
#EJB
private UserDAO userDAO;
public void register(String email, String password){
User user = new User();
user.setEmail(email);
user.setPassword(password);
userDAO.create(user);
}
}
The problem is if password is null. At first called updatePassword method but not #NotNull annotation over the password field and thus i get NullPointerException. How to make that at first checks validation and then later other methods. Thanks in advance!

It seems that bean validation is not triggered soon enough.
One way to solve this would be to inject ValidatorFactory into UserService and then validate user object after it is created. Something like this:
#Stateless
public class UserService {
#EJB
private UserDAO userDAO;
#Inject
private ValidatorFactory validatorFactory;
public void register(String email, String password){
User user = new User();
user.setEmail(email);
user.setPassword(password);
Set<ConstraintViolation<User>> constraintViolations = validatorFactory.getValidator().validate(user);
if(constraintViolations.size() > 0){
// handle error
}else{
userDAO.create(user);
}
}
}
this answer could be helpful for clarification

Related

How to return a message to HTTP request in Java?

I am creating an API to simulate a vending machine and I'm using Spring, JPA and MySQL. I have an endpoint for a POST request that allows for new user creation by entering the user's details into a table called users. I have a check to see if the username already exists in the table and if it does, I want to return a message that says the creation of a new user was unsuccessful because that username is already in use. If the user name is not in the table, I want to return the User object.
How do I return this error message? From what I have found so far, suggestions include the usage of ResponseEntity or creating a custom exception handler which all seemed overly complicated for something that I feel is quite straightforward. Is there an easier way to do this?
So this is what I want the response to look like when a new user has been created successfully (which I have currently managed to get working successfully):
{
"username": "user",
"password": "password",
"role": "BUYER",
"deposit": 0.0,
"id": 12
}
And if it fails, I want it to return something that looks along the lines of:
Error: username already in use.
or:
{
"error" : "Username already in use"
}
User object:
#Entity
#Table(name = "users")
public class User
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private int userId;
#NotNull
#Column(name = "username", unique = true)
private String username;
#NotNull
#Column(name = "password")
private String password;
#NotNull
#Column(name = "role")
private Role role;
#NotNull
#Column(name = "deposit")
private BigDecimal deposit;
public User() {}
public User(String username, String password, Role role, BigDecimal deposit)
{
this.username = username;
this.password = password;
this.role = role;
this.deposit = deposit;
}
public int getId()
{
return userId;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public Role getRole()
{
return role;
}
public void setRole(String role)
{
this.role = Role.valueOf(role);
}
public void setRole(Role role) {
this.role = role;
}
public BigDecimal getDeposit()
{
return deposit;
}
public void setDeposit(BigDecimal deposit)
{
this.deposit = deposit;
}
}
Method in the controller that is being called:
#PostMapping(value = "/create-user", consumes = {"application/json"})
public User createUser(#RequestBody User user)
{
return userService.createUser(user);
}
createUser method in UserService:
public User createUser(User user)
{
// if(userRepository.userExists(user.getUsername()) == 0)
return userRepository.save(user);
}
UserRepository is an interface that extends JpaRepository.
If I have missed some information or have worded the question incorrectly, please let me know and I'll update accordingly.
This can be achieved in multiple ways.
You can use JpaRepository's existsById() or similar "exists" methods. This would return a boolean. If it's true, that is if the entry already exists for a given id, you can send an error response. Otherwise, new user object. For that, you can have a model class something like UserOrError which will either hold a user object or an error string at a time. Use #JsonView annotation from Jackson library to show/ hide the fields. Read more
Based on the result of the above "exists" method, wrap it with ResponseEntity<T>. The return type of your controller method should be ResponseEntity<T>. Here's the link. The advantage of this method is that you can send different HTTP status codes
Throw a custom RuntimeException in your service layer and use Spring's exception handling like the RestControllerAdvice annotation

Built in Spring-Boot BCrypt matches method doesn't work

I have a UserController that receives a UserDTO and creates/updates the user in the DB. The problem I'm getting is that I also have a login, and when I insert the username and password on the login form, I always get the 'Wrong Password.' exception, despite the credentials being correctly inserted.
One thing I suspect is that BCrypt is to blame, since due to the fact that it generates random salt while encoding, maybe, just maybe, the cipher text ends up being different and stuff, which is weird, since I assume that it should work. I want to know how can I fix this problem of the hashing being different & not being able to validate the userCredentials
I have tried for example encoding the received password and using the matches method via my autowired passwordEncoder, and I'm using my own authProvider.
Here's the code, let me know if you need anything else.
CustomAuthProvider.java
#Service
public class CustomAuthProvider implements AuthenticationProvider {
private final UserServiceImpl userServiceImpl;
private final BCryptPasswordEncoder passwordEncoder;
#Autowired
public CustomAuthProvider(UserServiceImpl userServiceImpl, BCryptPasswordEncoder passwordEncoder) {
this.userServiceImpl = userServiceImpl;
this.passwordEncoder = passwordEncoder;
}
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getName();
String password = authentication.getCredentials().toString();
UserDetails userDetails = userServiceImpl.loadUserByUsername(username);
if (!passwordEncoder.matches(password, userDetails.getPassword())) { //The problem is here evidently.
throw new BadCredentialsException("Wrong password.");
}
return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
Also, here's the loadUserByUsername method:
UserServiceImpl.java
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDTO user = this.getUserByUsername(username);
User anUser = convertToUser(user);
ModelMapper modelMapper = new ModelMapper();
return modelMapper.map(anUser,UserPrincipal.class);
}
}
And here is the save method I use to save and update users, as well as the LoginController;
#Override
public void save(UserDTO user) {
User aUser = this.convertToUser(user);
aUser.setPassword(passwordEncoder.encode(aUser.getPassword()));
this.userRepository.save(aUser); }
LoginController.java:
#RestController
public class LoginController{
private final CustomAuthProvider providerManager;
#Autowired
public LoginController(CustomAuthProvider providerManager) {
this.providerManager = providerManager;
}
#GetMapping("/login")
public String login() {
return "login";
}
#PostMapping("/login")
public String login(#RequestParam("username") #NotBlank String username,
#RequestParam("password") #NotBlank String password, Model model) {
if(username == null || password == null) { //This is probably not necessary
model.addAttribute("error", "Invalid credentials");
return "login";
}
try {
Authentication auth = providerManager.authenticate(
new UsernamePasswordAuthenticationToken(username, password)
);
SecurityContextHolder.getContext().setAuthentication(auth);
return "redirect:/notes";
} catch (AuthenticationException e) {
model.addAttribute("error", "Invalid credentials");
return "login";
}
}
}
UserPrincipal.java
#Data
public class UserPrincipal implements Serializable , UserDetails {
int id;
private String username;
private String password;
private Date accountCreationDate = new Date();
#Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return null;
}
#Override
public boolean isAccountNonExpired() {
return false;
}
#Override
public boolean isAccountNonLocked() {
return false;
}
#Override
public boolean isCredentialsNonExpired() {
return false;
}
#Override
public boolean isEnabled() {
return false;
}
}
UserDTO.java
#Data
public class UserDTO implements Serializable {
int id;
private String username;
private String password;
private List<Note> notes = new ArrayList<>();
}
I read several issues related to this topic, like
Spring Boot PasswordEncoder.matches always false
Spring Security - BcryptPasswordEncoder
Inconsistent hash with Spring Boot BCryptPasswordEncoder matches() method
How can bcrypt have built-in salts?
Decode the Bcrypt encoded password in Spring Security to deactivate user account
but none of those helped me solve my issue and there was no real solution to the problem since most of them don't even have an accepted answer.
EDIT: Found out that the 'matches' method only works if I insert the hashed password, not the raw password.
Found out my mistake:
The setPassword method in the User class was re-hashing the hashed password which was already being hashed on the save method, thus the modelMapper.map() method used that setPassword method, therefore the passwords never matched and the password I got from the user class never matched the actual password I could see on my database.

Optional and Java Spring Testing

I have a problem with my ControllerTest. I'm not sure how to test for the Optional - does someone know how? The other test gives me a NullPointerException for the stubbing : when(couponService.getCouponById(id)).thenReturn(expectedCoupon);
Would be awesome if someone could help me.
public class CouponControllerTest {
#MockBean
private CouponService couponService;
#MockBean
private UserService userService;
#Autowired
MockMvc mockMvc;
#Test
public void checkAndUpdateCoupon() throws Exception {
int id = 1;
int userId = 1;
Coupon expectedCoupon = new Coupon(1, 1);
when(couponService.getCouponById(id)).thenReturn(expectedCoupon);
List<User> userList = new ArrayList<User>();
when(userService.getAllUser()).thenReturn(userList);
List<Coupon> couponList = new ArrayList<Coupon>();
when(couponService.getAllCoupons()).thenReturn(couponList);
mockMvc.perform(get("/checkCoupon")
.param("id", "1")
.param("userId", "1"))
.andExpect(status().isOk())
.andExpect(view().name("couponPage"))
.andExpect(model().attribute("error", "Not correct user id or coupon id."))
.andExpect(model().attribute("users", userList))
.andExpect(model().attribute("coupons", couponList));
verify(couponService).updateCoupons(id, userId);
}
}
#Controller
public class CouponController {
#Autowired
CouponService couponService;
#Autowired
UserService userService;
#GetMapping("/checkCoupon")
public String checkCoupon(ModelMap model, #RequestParam Integer id, #RequestParam Integer userId, Coupon coupon) {
Optional<Coupon> couponFromDatabase = couponService.byUserIdAndId(coupon.getUserId(), coupon.getId());
if(couponFromDatabase.isEmpty()) {
String error = "Not correct user id or coupon id.";
model.addAttribute("error", error);
} else {
String message = couponService.updateCoupons(id, userId);
model.addAttribute("message", message);
}
List<User> userList = userService.getAllUser();
model.addAttribute("users", userList);
List<Coupon> couponList = couponService.getAllCoupons();
model.addAttribute("coupons", couponList);
return "couponPage";
}
}
I think you need to do some changes in mocking the first service.
when( couponService.byUserIdAndId(anyLong(), anyLong()) ).thenReturn( Optional.of(expectedCoupon) );
Here the anyLong() refer to any Incoming long data type number.
Override your existing code with this above line.

How to pass userid from one table to another table in spring mvc using hibernate

I'm using Spring security for the login. I have the User.java which contains user-details.
#Entity(name = "user_table")
//#Table(name = "user_table")
public class User {
#Id
#Column(name = "id")
private String userId;
#Column(name = "email" ,unique = true)
private String userEmail;
#Column(name = "password")
private String userPassword;
//getter and setters
}
I'm getting the whole data of the current user from the table by using spring security. This is the code:
public User findUserByEmail(String email) {
List<User> users = new ArrayList<User>();
try{
users = sessionFactory.getCurrentSession().createQuery("from user_table where email= ?").setParameter(0, email).list();
System.out.println("user is " +users);
}catch(Exception e){
System.out.println(e.getMessage());
e.printStackTrace();
}
if (users.size() > 0) {
return users.get(0);
} else {
return null;
}
}
#Override
public User getCurrentUser() {
Authentication auth = SecurityContextHolder.getContext()
.getAuthentication();
User currentUser = new User();
if (!(auth instanceof AnonymousAuthenticationToken)) {
UserDetails userDetails = (UserDetails) auth.getPrincipal();
System.out.println("User has authorities: "
+ userDetails.getAuthorities());
System.out.println("USERNAME:: "+userDetails.getUsername());
currentUser = findUserByEmail(userDetails
.getUsername());
System.out.println("currentUser "+currentUser);
System.out.println("currentUser "+currentUser.getUserId());
return currentUser;
}
return null;
}
What I want is to send the user id which I'm getting from currentUser.getUserId() to some other method. In that method I'm mapping to some other table like user_detail table where id is primary key. By sending id, I will get the other user_details which are not present in the user_table.
This is my UserDetail:
#Entity(name = "user_detail")
#Table(name = "user_detail")
public class UserDetail {
#Id
#GeneratedValue
#Column(name = "id")
private String userId;
//some other details like Address .
//getter and setter.
}
From controller I'm calling the above method like this:
UserService userService = new UserService();
User user=userDao.getCurrentUser();
String userId = user.getUserId();
System.out.println(userId);
UserDetail u=userDao.findUserById(userId);
and this is the method where I pass the current user id :
public UserDetail findUserById(String id) {
// TODO Auto-generated method stub
List<String> users = new ArrayList<String>();
try{
users = sessionFactory.getCurrentSession().createQuery("from user_detail where id= ?").setParameter(0, id).list();
System.out.println("user is " +users);
}catch(Exception e){
System.out.println(e.getMessage());
e.printStackTrace();
}
if (users.size() > 0) {
return null;
} else {
return null;
}
}
Now the result I'm getting here is null . Like user is null. What I'm doing wrong here?
There are several problems in your code. Just to point out some of them:
UserService userService = new UserService(); - you're manually creating the service object and not letting Spring-MVC injecting it into your controller, i.e. :
#Autowired
private UserService userService ;
UserDAO should be injected in your service, and not called from your controller :
class UserServiceImpl implements UserService{
#Autowired
private UserDAO userDAO;
}
All operations from your controller should call services methods and not DAO's methods. The service should use the DAO for database access. i.e.
UserDetail u=userDao.findUserById(userId);
should become
UserDetail u = userService.findUserById(userId);
and in your service :
class UserServiceImpl implements UserService{
#Autowire
private UserDAO userDAO;
#Override
public UserDetail findUserById(Long userId){
return userDAO.findUserById(userId);
}
}
if (users.size() > 0) {
return null;
} else {
return null;
}
is always returning null. Should be :
if (`users.isEmpty()){
return users.get(0);
}else { return null;}
users = sessionFactory.getCurrentSession().createQuery("from user_detail where id= ?").setParameter(0, id).list();
Your query is wrong. You should use your current bean class name and not the table name in your query, i.e. createQuery("FROM UserDetail WHERE id = ?")

Spring session bean and RESTEasy + Jackson nullPointerException

I am building a spring based WebApp including a RESTful method call.
I use RESTeasy and jackson to return the username of the current logged in user
(this information is stored in a session bean called "UserBean")
UserBean:
#Component("userBean")
#Scope("session")
public class UserBean implements Serializable {
#Autowired
private InitApp app;
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
OverviewBean is the bean that contains the rest method (including the jackson conversion to json):
#Component("overviewBean")
#Scope("view")
#Path("/repairs")
public class OverviewBean {
#Autowired
private InitApp app;
#Autowired
private UserBean userBean;
private List<Repair> openRepairsClient;
private List<Repair> closedRepairsClient;
#PostConstruct
public void fillRepairs() {
try {
String username = userBean.getUsername();
openRepairsClient = app.repairService.findOpenRepairsByClient((Client) app.userService.getUser(userBean.getUsername()));
closedRepairsClient = app.repairService.findClosedRepairsByClient((Client) app.userService.getUser(userBean.getUsername()));
} catch (UserServiceException ex) {
Logger.getLogger(OverviewBean.class.getName()).log(Level.SEVERE, null, ex);
}
}
//Getters and setters openRepairsClient/closedRepairsClient
#GET
#Path("/getrepairs")
#Produces("application/json")
public String getOpenRepairsInJson() {
String username = userBean.getUsername();
return "test";
}
}
fillRepairs() is able to use userBean without any errors. For example the "String username = userBean.getUsername();" within the try catch returns the username correctly.
My issue is that when getOpenRepairsInJson gets called it throws a nullPointerException
on "String username = userBean.getUsername();". It seems that my userBean is not "linked"
at the moment of the method call. What am I doing wrong?
Thanks in advance!

Categories