Hibernate not fetching object from repository - java

Im making a basic reset password functionality in my API but when i try to fetch the PasswordResetToken object from the repository hibernate doesnt fetch it and instead sends back null. Im 99% sure the PasswordResetToken that im trying to fetch is inside of the repository because i did some system.out.println's and it shows the PasswordResetToken is in there with the matching token it just doesnt send anything back.
heres the email varification and token creation
#PostMapping("/resetPassword")
public String resetPassword(#RequestBody PasswordModel passwordModel, HttpServletRequest request) {
User user = userService.findUserByEmail(passwordModel.getEmail());
String url = "";
if(user!=null) {
String token = UUID.randomUUID().toString();
userService.createPasswordResetTokenForUser(user, token);
url = passwordResetTokenMail(user, applicationUrl(request), token);
}
return url;
}
service methods that go along with it
#Override
public User findUserByEmail(String email) {
return userRepository.findByEmail(email);
}
#Override
public void createPasswordResetTokenForUser(User user, String token) {
PasswordResetToken passwordResetToken
= new PasswordResetToken(user, token);
passwordResetTokenRepo.save(passwordResetToken);
}
save new password functionality where the issue happens
#PostMapping("/savePassword")
public String savePassword(#RequestParam("token") String token,
#RequestBody PasswordModel passwordModel) {
String result = userService.validatePasswordResetToken(token);
if(!result.equalsIgnoreCase("valid")) {
return "Invalid token";
}
Optional<User> userOptional = userService.getUserByPasswordResetToken(token);
if(userOptional.isPresent()) {
userService.changePassword(userOptional.get(), passwordModel.getNewPassword());
return "Password has been updated";
} else {
return "Invalid token";
}
}
service methods
#Override
public String validatePasswordResetToken(String token) {
PasswordResetToken passwordResetToken
= passwordResetTokenRepo.findByToken(token);
if(passwordResetToken == null) {
return "invalid";
}
User user = passwordResetToken.getUser();
Calendar cal = Calendar.getInstance();
if((passwordResetToken.getExpirationTime().getTime())
- cal.getTime().getTime() <=0) {
passwordResetTokenRepo.delete(passwordResetToken);
return "expired";
}
return "valid";
}
#Override
public Optional<User> getUserByPasswordResetToken(String token) {
return Optional.ofNullable(passwordResetTokenRepo.findByToken(token).getUser());
}
#Override
public void changePassword(User user, String newPassword) {
user.setPassword(passwordEncoder.encode(newPassword));
userRepository.save(user);
}
and finally the repository
#Repository
public interface PasswordResetTokenRepo extends JpaRepository<PasswordResetToken, Long> {
PasswordResetToken findByToken(String token);
}

Figured it out incase anyone runs into the same issue. I was using postman on the client side and for some reason when I was copying the URL and pasting it into postman it was adding a space after the url so the token ended up being token=xyz with a space after instead of just token xyz. That’s why it looked like the token was there in the repo because you couldn’t tell there was a space after it.

Related

JWT add different subject depending on the data in the body

I've been asked to generate a token depending on the username that is asking for it. Now I'm creating a token just with a single subject but I don't know how to change the subject dinamically before creating the token depending on the body of the request.
This is what I've done so far to generate a token with a single subject:
The service class:
#Component
#RequiredArgsConstructor
public class JwtService {
#Value("${issuer}")
private String issuer;
#Value("${kid}")
private String keyId;
#Value("#{'${audience}'.split(',')}")
private List<String> audiences;
#Value("#{'${subject}'.split(',')}")
private List<String> subject;
private final JwtKeyProvider jwtKeyProvider;
public String generateToken() throws JoseException {
JwtClaims claims = new JwtClaims();
claims.setIssuer(issuer);
claims.setAudience(Lists.newArrayList(audiences));
claims.setExpirationTimeMinutesInTheFuture(60);
claims.setJwtId(keyId);
claims.setIssuedAtToNow();
claims.setNotBeforeMinutesInThePast(0);
claims.setSubject(subject);
JsonWebSignature jws = new JsonWebSignature();
jws.setPayload(claims.toJson());
jws.setHeader("typ", "JWT");
jws.setKey(jwtKeyProvider.getPrivateKey());
jws.setKeyIdHeaderValue(keyId);
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
String jwt = jws.getCompactSerialization();
return jwt;
}
}
And the controller:
#RestController
#RequiredArgsConstructor
public class JWTController {
private final JwtService jwtService;
#PostMapping("/getToken")
public ResponseEntity getJwt(#RequestBody JwtRequest request) throws JoseException {
return ResponseEntity.ok(
JwtResponse.builder()
.token(jwtService.generateToken())
.build()
);
}
}
I could do it doing like this:
#PostMapping("/getToken")
public ResponseEntity getJwt(#RequestBody JwtRequest request) throws JoseException {
return ResponseEntity.ok(
JwtResponse.builder()
.token(jwtService.generateToken(request.getUsername()))
.build()
);
}
}
But I don't want to send any parameters in the generateToken function as I would have to change a lot of code then.
To resume I want to assign to the subject the value of the username that is sent in the body. So is there a way in the JwtService class to receive that username and set as the subject after?
Thanks in advance!
First you need to put whitelist=user1,user2 in your application.properties, because sometimes names might trigger as system variables (for example username does)
Then in JWTController you need to check if not user equals, but contains in list
#Value("#{'${whitelist}'.split(',')}")
private List<String> whitelist;
#PostMapping("/getToken")
public ResponseEntity<?> getJwt(#RequestBody JwtRequest request) throws JoseException {
if(whitelist.contains(request.username())) {
return ResponseEntity.ok(
JwtResponse.builder()
.token(jwtService.generateToken(request.username()))
.build()
);
} else {
return ResponseEntity.ok("Invalid username");
}
}
In your JWTService you need to set JWT Subject to username which passed through whitelist
claims.setSubject(username);
And finally you need to do JSON request to server
{
"username": "user2"
}

How to send Status Codes Along with my Custom Class Using Spring?

I am trying to make a log in system using spring. Problem is if username is not in the database I want to send a different status code and if username is in the database but password is wrong I want to send different status code. Because in my front end i am going to inform user using different alerts according to status code.
I cannot use HttpStatus.NOT_ACCEPTABLE or something like that because my controller is returning a User(my custom class). It will either return User or null.
#GetMapping("/users")
public User userLogin(#RequestParam String username,#RequestParam String password) {
User user = userService.findByUsername(username);
if(user==null) {
return null;
}
if(user.getPassword().equals(password)) {
return user;
} else {
return null;
}
}
Here I am trying to change status while returning nulls.
you can return ResponseEntity to meet your requirement
#GetMapping("/users")
public ResponseEntity<User> userLogin(#RequestParam String username,#RequestParam String password) {
User user = userService.findByUsername(username);
if(user==null) {
return new ResponseEntity<>(null,HttpStatus.NOT_FOUND);
}
if(user.getPassword().equals(password)) {
return new ResponseEntity<>(user,HttpStatus.OK);
} else {
return new ResponseEntity<>(null,HttpStatus.FORBIDDEN);
}
}
Spring 5 introduced the ResponseStatusException class. We can create an instance of it providing an HttpStatus and optionally a reason and a cause:
#GetMapping(value = "/{id}") public Foo findById(#PathVariable("id") Long id, HttpServletResponse response) {
try {
Foo resourceById = RestPreconditions.checkFound(service.findOne(id));
eventPublisher.publishEvent(new SingleResourceRetrievedEvent(this, response));
return resourceById;
}
catch (MyResourceNotFoundException exc) {
throw new ResponseStatusException(
HttpStatus.NOT_FOUND, "Foo Not Found", exc);
} }
Maybe this is which you looking for?
Detail in https://www.baeldung.com/exception-handling-for-rest-with-spring#controlleradvice

REST to return content after POST on Java service

New users are created with the POST method, and after this the database will attach it an unique ID, which is necessary to create a token.
The only way to create a token, is after the process of user creation. I query it from the database and now it should have ID on it, but I can't figure how to do that.
Is there any way to retrieve the entity from database right after creating it?
If looked at this similar question, but couldn't find an answer: Is it ok by REST to return content after POST?
#POST
#Consumes({MediaType.APPLICATION_JSON})
public Response create(#QueryParam("email") String email, #QueryParam("username") String userName, #QueryParam("password") String password) {
if (TextUtil.isEmpty(userName) || TextUtil.isEmpty(password) || TextUtil.isEmpty(email)) {
return Response.status(Response.Status.BAD_REQUEST).build();
} else {
User newUser = new User();
newUser.setEmail(email);
newUser.setUsername(userName);
newUser.setPass(password);
super.create(newUser); //ths line create user in database
String id = newUser.getUid() + ""; //the newUser has no id yet so it is null but I want this id from database
return Response.status(Response.Status.OK).entity("id: " + id).build();
}
}
Create super.method
public void create(T entity) {
getEntityManager().persist(entity);
}
I generate REST api using this tutorial
https://netbeans.org/kb/docs/websvc/rest.html
getEntityManager().persist(entity);
Set the id of the entity by calling entity.setId(...).
I my comments I show how to sync EntityManager. Maybe you should write a better create method:
public <T> T create(T t) throws Exception {
try {
entityManager.persist(t);
entityManager.flush();
} catch (Exception e) {
throw e;
} finally {
entityManager.clear();
}
return t;
}
And then
newUser = super.create(newUser);

How to activate a user through email verification

Right now I am sending a confirmation link containing JWT token created for user to recipients mail address. This token is saved in a database column.
The activation link looks like this:
http://localhost:7070/RTH_Sample14/eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczpcL1wvcnRoLmNvbSIsInN1YiI6IlJUSCIsInJvbGUiOiJVU0VSIiwiZXhwIjoxNDU2MjQ1MzM2LCJlbWFpbCI6Imtpcml0aS5rOTk5QGdtYWlsLmNvbSJ9.RJ54PhKcj9GGMq_VefQEMhY0x38wX1t5GgMldHCRmBZsPKoXAYg5vr39aXjHtKmIDsoqmDdzzjsrEIweWEATg3-jGe_PGfxwKZg1zsKiWlpavvKJn92VgffJi1yO54t-H31n2NKjVhAcay34pf3eUNqpPcDCEz9uf_GwSZl1ZTM
When the user clicks on the link, I want to be able to call a restful resource (#Path("/public/emailActivation")) which checks for token in database and change the account-status column from "pending" to "active"
The problem is how would I point the activation-link to rest resource method when clicked?
Is this the right approach to activate/verify user?
Rest Registration Service:
#Path("/public/registrationService")
public class RegistrationService {
public RegistrationService() {
}
#POST
#Path("/register")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public Response register(UserProfile user) {
String email = user.getEmail();
String token = "";
try {
RegistrationDAO registrationDao = new RegistrationDAO();
int count = registrationDao.insert(user);
if (count > 0) {
System.out.println("Registration successful");
TokenProvider jwtProvider = new TokenProvider();
token = jwtProvider.getToken(email);
Map<String, String> response = new HashMap<>();
response.put("token", token);
SendEmailConfirmation mailActivation = new SendEmailConfirmation();
mailActivation.sendMail(email, "http://localhost:7070/RTH_Sample14/"+token);
return Response.ok(response).build();
}
else {
return Response.status(Response.Status.UNAUTHORIZED).type("text/plain").entity("Registration failed!").build();
}
} catch (Exception e) {
e.printStackTrace();
return Response.status(Response.Status.NOT_FOUND).type("text/plain").entity("Error in Login Service web service class").build();
}
}
}
This method should be called for mail activation when user clicks on link:
#Path("/public/emailActivation")
public class EmailActivation {
#Path("/activate")
public void activateAccount(){
//Check Database for token and account status
}
}

Custom http code with Spring MVC

I use the following code to handle rest calls using Spring MVC.
#RequestMapping(value = "login", method = RequestMethod.GET)
public #ResponseBody
User login(#RequestParam String username, #RequestParam String password) {
User user = userService.login(username, password);
if (user == null)
...
return user;
}
I would like to send the client customer http codes for wrong username, wrong passwords, password changed and password expire conditions. How can I modify the existing code to send these error codes to the client?
You can use controller advice to map exception thrown within controller to some client specific data at runtime.
For example if user is not found, your controller should throw some exception (custom or existed one)
#RequestMapping(value = "login", method = RequestMethod.GET)
#ResponseBody
public User login(#RequestParam String username, #RequestParam String password) {
User user = userService.login(username, password);
if (user == null)
throw new UserNotFoundException(username); //or another exception, it's up to you
return user;
}
}
Then you should add #ControllerAdvice that will catch controller exceptions and make 'exception-to-status' mapping (pros: you will have single point of responsibility for 'exception-to-status-mapping'):
#ControllerAdvice
public class SomeExceptionResolver {
#ExceptionHandler(Exception.class)
public void resolveAndWriteException(Exception exception, HttpServletResponse response) throws IOException {
int status = ...; //you should resolve status here
response.setStatus(status); //provide resolved status to response
//set additional response properties like 'content-type', 'character encoding' etc.
//write additional error message (if needed) to response body
//for example IOUtils.write("some error message", response.getOutputStream());
}
}
Hope this helps.
One way is to add some additional classes for returning HTTP error. Your code will looks like this:
#RequestMapping(value = "login", method = RequestMethod.GET)
#ResponseBody
public User login(#RequestParam String username, #RequestParam String password) {
User user = userService.login(username, password);
if (user == null)
throw new UnauthorizedException();
return user;
}
}
#ResponseStatus(value = HttpStatus.UNAUTHORIZED)
public class UnauthorizedException extends RuntimeException{
}
In this case user will get 401 response status code
I hope it helps
You can return an HTTP 500 or code of your choosing (from the org.springframework.http.HttpStatus enumeration) and use a custom error to emulate something like a SOAP fault within the JSON response.
For example:
#ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
#ExceptionHandler(YourTargetException.class)
#ResponseBody
Fault caughtYourTargetException(HttpServletRequest req, Exception ex) {
String code = ex.getClass().getName();
String reason = "Caught YourTargetException."
return new Fault(code, reason);
}
The Fault class could look something like this (inspired by http://www.w3.org/TR/soap12-part1/#soapfault):
/**
* A Fault is an object that can be serialized as JSON when expected errors occur.
*/
public class Fault {
#JsonProperty("faultCode")
private final String code;
#JsonProperty("faultReason")
private final String reason;
#JsonProperty("faultDetails")
private final List<String> details = new ArrayList<>();
public Fault(String code, String reason) {
this.code = code;
this.reason = reason;
}
public Fault(String code, String reason, String... detailEntries) {
this.code = code;
this.reason = reason;
details.addAll(Arrays.asList(detailEntries));
}
public String getCode() {
return code;
}
public String getReason() {
return reason;
}
/**
* Zero or more details may be associated with the fault. It carries
* additional information relative to the fault. For example, the Detail
* element information item might contain information about a message
* not containing the proper credentials, a timeout, etc.
* #return Zero or more detail entries.
*/
public Iterable<String> getDetails() {
return details;
}
#Override
public String toString() {
return String.format("Fault %s occurred. The reason is %s.", getCode(),
getReason());
}
}
You could use one of the existing SOAPFaults in Java frameworks, but I have found they don't play well in REST. Creating my own simple version turned out to be simpler.
You can define your own status code and returning objects. In your code throw custom exceptions and then define an exception handler as follows:
#ControllerAdvice
public class GlobalControllerExceptionHandler {
#ExceptionHandler(MyException.class)
public ResponseEntity<MyRetObject> handleControllerError(HttpServletRequest req, MyException ex) {
LOG.warn("My error", ex);
MyRetObject errorMessage = new MyRetObject(ex.getMessage());
return ResponseEntity.status(600).body(errorMessage);
}
}
In your case replace MyExeption.class by UserNotFoundException.class and build your customer error response object and error code

Categories