Skip to content

Commit 4d822e0

Browse files
author
JEstebanC
committed
finish back-end sending mail to reset password with the token
1 parent 8fa5a9f commit 4d822e0

File tree

9 files changed

+200
-54
lines changed

9 files changed

+200
-54
lines changed

pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,12 @@
7070
<artifactId>java-jwt</artifactId>
7171
<version>3.18.3</version>
7272
</dependency>
73-
73+
74+
<!-- send email -->
75+
<dependency>
76+
<groupId>org.springframework.boot</groupId>
77+
<artifactId>spring-boot-starter-mail</artifactId>
78+
</dependency>
7479

7580
</dependencies>
7681

src/main/java/JEstebanC/FastFoodApp/controller/OrdersController.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import java.time.Instant;
44
import java.util.Map;
55

6-
import javax.servlet.http.HttpServletRequest;
76
import javax.validation.Valid;
87

98
import org.springframework.beans.factory.annotation.Autowired;
@@ -69,8 +68,7 @@ public ResponseEntity<Response> getOrder() {
6968
// UPDATE
7069
@PreAuthorize("hasRole('ROLE_ADMIN') OR hasRole('ROLE_EMPLOYEE')")
7170
@PutMapping(value = "/{id}")
72-
public ResponseEntity<Response> updateOrder(@PathVariable("id") Long id, @RequestBody @Valid Orders order,
73-
HttpServletRequest request) {
71+
public ResponseEntity<Response> updateOrder(@PathVariable("id") Long id, @RequestBody @Valid Orders order) {
7472
if (serviceImp.exist(id)) {
7573
return ResponseEntity.ok(Response.builder().timeStamp(Instant.now())
7674
.data(Map.of("order", serviceImp.update(id, order))).message("Update order with id:" + id)
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
*
3+
*/
4+
package JEstebanC.FastFoodApp.controller;
5+
6+
import java.time.Instant;
7+
import java.util.Map;
8+
9+
import javax.mail.MessagingException;
10+
import javax.servlet.http.HttpServletRequest;
11+
import javax.servlet.http.HttpServletResponse;
12+
13+
import org.springframework.beans.factory.annotation.Autowired;
14+
import org.springframework.http.HttpStatus;
15+
import org.springframework.http.ResponseEntity;
16+
import org.springframework.web.bind.annotation.GetMapping;
17+
import org.springframework.web.bind.annotation.PostMapping;
18+
import org.springframework.web.bind.annotation.RequestParam;
19+
import org.springframework.web.bind.annotation.RestController;
20+
21+
import JEstebanC.FastFoodApp.dto.UserDTO;
22+
import JEstebanC.FastFoodApp.model.Response;
23+
import JEstebanC.FastFoodApp.service.UserServiceImp;
24+
import lombok.RequiredArgsConstructor;
25+
26+
/**
27+
* @author Juan Esteban Castaño Holguin castanoesteban9@gmail.com 2022-02-16
28+
*/
29+
@RestController
30+
@RequiredArgsConstructor
31+
public class RecoverPasswordController {
32+
33+
@Autowired
34+
private final UserServiceImp serviceImp;
35+
36+
@GetMapping(value = "/recover-password")
37+
public ResponseEntity<Response> recoverPassword(HttpServletRequest request, HttpServletResponse response,
38+
@RequestParam(name = "email") String email) throws MessagingException {
39+
UserDTO user = serviceImp.findByEmail(email);
40+
if (user != null) {
41+
return ResponseEntity.ok(Response.builder().timeStamp(Instant.now())
42+
.data(Map.of("product",
43+
serviceImp.sendMail(request, response, email, user.getUsername(), user.getName())))
44+
.message("Mail sent").status(HttpStatus.OK).statusCode(HttpStatus.OK.value()).build());
45+
} else {
46+
return ResponseEntity.ok(Response.builder().timeStamp(Instant.now()).message("The email do not exist")
47+
.status(HttpStatus.BAD_REQUEST).statusCode(HttpStatus.BAD_REQUEST.value()).build());
48+
}
49+
}
50+
51+
@PostMapping("/reset-password")
52+
public ResponseEntity<Response> resetPassword(HttpServletRequest request,
53+
@RequestParam(name = "token") String token) {
54+
String newPassword = request.getParameter("newPassword");
55+
String repeatNewPassword = request.getParameter("repeatNewPassword");
56+
if (newPassword.equals(repeatNewPassword)) {
57+
String username = serviceImp.validationToken(token);
58+
if (username != null) {
59+
return ResponseEntity.ok(Response.builder().timeStamp(Instant.now())
60+
.data(Map.of("product", serviceImp.updatePasswordClient(username, newPassword)))
61+
.message("Create product").status(HttpStatus.OK).statusCode(HttpStatus.OK.value()).build());
62+
} else {
63+
return ResponseEntity.ok(
64+
Response.builder().timeStamp(Instant.now()).message("The Token's Signature resulted invalid!")
65+
.status(HttpStatus.UNAUTHORIZED).statusCode(HttpStatus.UNAUTHORIZED.value()).build());
66+
}
67+
} else {
68+
return ResponseEntity.ok(Response.builder().timeStamp(Instant.now()).message("Passwords must be the same")
69+
.status(HttpStatus.BAD_REQUEST).statusCode(HttpStatus.BAD_REQUEST.value()).build());
70+
}
71+
}
72+
}

src/main/java/JEstebanC/FastFoodApp/controller/RefreshTokenController.java

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
/**
2-
*
3-
*/
1+
42
package JEstebanC.FastFoodApp.controller;
53

64
import javax.servlet.http.HttpServletRequest;
@@ -60,14 +58,13 @@ public void refreshToken(HttpServletRequest request, HttpServletResponse respons
6058
User user = serviceImp.findByUsername(username);
6159

6260
String access_token = JWT.create().withSubject(user.getUsername())
63-
.withExpiresAt(new Date(System.currentTimeMillis() + 15 * 60 * 1000))
61+
.withExpiresAt(new Date(System.currentTimeMillis() + 30 * 60 * 1000))
6462
.withIssuer(request.getRequestURL().toString())
6563
.withClaim("roles",user.getUserRoles().getAuthority())
6664
.sign(algorithm);
6765

6866
Map<String, String> tokens = new HashMap<>();
6967
tokens.put("access_token", access_token);
70-
tokens.put("refresh_token", refresh_token);
7168
response.setContentType(MimeTypeUtils.APPLICATION_JSON_VALUE);
7269
new ObjectMapper().writeValue(response.getOutputStream(), tokens);
7370
} else {
@@ -77,10 +74,11 @@ public void refreshToken(HttpServletRequest request, HttpServletResponse respons
7774
} catch (Exception e) {
7875
log.error("Error logging in AuthorizationFilter: " + e.getMessage());
7976
response.setHeader("Error", e.getMessage());
80-
response.setStatus(403);
77+
response.setStatus(401);
8178
Map<String, String> error = new HashMap<>();
8279
error.put("error_message", e.getMessage());
8380
response.setContentType(MimeTypeUtils.APPLICATION_JSON_VALUE);
81+
8482
new ObjectMapper().writeValue(response.getOutputStream(), error);
8583
}
8684

@@ -89,4 +87,4 @@ public void refreshToken(HttpServletRequest request, HttpServletResponse respons
8987
}
9088
}
9189

92-
}
90+
}

src/main/java/JEstebanC/FastFoodApp/security/CustomAuthenticationFilter.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,10 @@
2525
import com.auth0.jwt.algorithms.Algorithm;
2626
import com.fasterxml.jackson.databind.ObjectMapper;
2727

28-
import lombok.extern.slf4j.Slf4j;
2928

3029
/**
3130
* @author Juan Esteban Castaño Holguin castanoesteban9@gmail.com 2022-02-02
3231
*/
33-
@Slf4j
3432
public class CustomAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
3533

3634
private final AuthenticationManager authenticationManager;
@@ -45,11 +43,9 @@ public Authentication attemptAuthentication(HttpServletRequest request, HttpServ
4543

4644
String username = request.getParameter("username");
4745
String password = request.getParameter("password");
48-
49-
log.info("Username is " + username + " Password is " + password);
5046
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username,
5147
password);
52-
48+
5349
return authenticationManager.authenticate(authenticationToken);
5450
}
5551

@@ -61,15 +57,15 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR
6157
Algorithm algorithm = Algorithm.HMAC256(OperationUtil.keyValue().getBytes());
6258
String access_token = JWT.create().withSubject(user.getUsername())
6359
//give 10 minutes for the token to expire
64-
.withExpiresAt(new Date(System.currentTimeMillis() + 30 * 60 * 1000))
60+
.withExpiresAt(new Date(System.currentTimeMillis() + 10 * 60 * 1000))
6561
.withIssuer(request.getRequestURL().toString())
6662
.withClaim("roles",
6763
user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
6864
.sign(algorithm);
6965

7066
String refresh_token = JWT.create().withSubject(user.getUsername())
7167
//give 30 minutes for the token to expire
72-
.withExpiresAt(new Date(System.currentTimeMillis() + 40 * 60 * 1000))
68+
.withExpiresAt(new Date(System.currentTimeMillis() + 30 * 60 * 1000))
7369
.withIssuer(request.getRequestURL().toString())
7470
.withClaim("roles",
7571
user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
@@ -80,6 +76,7 @@ protected void successfulAuthentication(HttpServletRequest request, HttpServletR
8076
tokens.put("refresh_token", refresh_token);
8177
response.setContentType(MimeTypeUtils.APPLICATION_JSON_VALUE);
8278
new ObjectMapper().writeValue(response.getOutputStream(), tokens);
79+
8380
}
8481

8582
}

src/main/java/JEstebanC/FastFoodApp/security/CustomAuthorizationFilter.java

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -35,46 +35,55 @@
3535
@Slf4j
3636
public class CustomAuthorizationFilter extends OncePerRequestFilter {
3737

38+
39+
3840
@Override
3941
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
4042
throws ServletException, IOException {
4143

42-
// here is where I start to check if the user has permission
43-
String authorizationHeader = request.getHeader(AUTHORIZATION);
44-
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
45-
try {
46-
// Remove the word Bearer, because we just want the token
47-
String token = authorizationHeader.substring("Bearer ".length());
48-
// Reference to the keyValue
49-
Algorithm algorithm = Algorithm.HMAC256(OperationUtil.keyValue().getBytes());
50-
JWTVerifier verifier = JWT.require(algorithm).build();
51-
DecodedJWT decodeJWT = verifier.verify(token);
52-
53-
String username = decodeJWT.getSubject();
54-
55-
String[] roles = decodeJWT.getClaim("roles").asArray(String.class);
56-
57-
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
58-
authorities.add(new SimpleGrantedAuthority(roles[0]));
59-
60-
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
61-
username, null,authorities);
62-
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
63-
filterChain.doFilter(request, response);
44+
if(request.getServletPath().equals("/api/v1/login/") || request.getServletPath().equals("/api/v1/token-refresh/")) {
45+
filterChain.doFilter(request, response);
46+
}else {
47+
// here is where I start to check if the user has permission
48+
String authorizationHeader = request.getHeader(AUTHORIZATION);
49+
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
50+
try {
51+
// Remove the word Bearer, because we just want the token
52+
String token = authorizationHeader.substring("Bearer ".length());
53+
// Reference to the keyValue
54+
Algorithm algorithm = Algorithm.HMAC256(OperationUtil.keyValue().getBytes());
55+
JWTVerifier verifier = JWT.require(algorithm).build();
56+
DecodedJWT decodeJWT = verifier.verify(token);
57+
58+
String username = decodeJWT.getSubject();
59+
60+
String[] roles = decodeJWT.getClaim("roles").asArray(String.class);
61+
62+
Collection<SimpleGrantedAuthority> authorities = new ArrayList<>();
63+
authorities.add(new SimpleGrantedAuthority(roles[0]));
64+
65+
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
66+
username, null,authorities);
67+
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
68+
filterChain.doFilter(request, response);
6469

65-
} catch (Exception e) {
66-
log.error("Error logging in AuthorizationFilter: " + e.getMessage());
67-
response.setHeader("Error", e.getMessage());
68-
response.setStatus(403);
69-
Map<String, String> error = new HashMap<>();
70-
error.put("error_message", e.getMessage());
71-
response.setContentType("application/json");
72-
new ObjectMapper().writeValue(response.getOutputStream(), error);
73-
}
70+
} catch (Exception e) {
71+
log.error("Error logging in AuthorizationFilter: " + e.getMessage());
72+
response.setHeader("Error", e.getMessage());
73+
response.setStatus(401);
74+
Map<String, String> error = new HashMap<>();
75+
error.put("error_message", e.getMessage());
76+
response.setContentType("application/json");
77+
new ObjectMapper().writeValue(response.getOutputStream(), error);
78+
79+
}
7480

75-
} else {
76-
filterChain.doFilter(request, response);
81+
} else {
82+
filterChain.doFilter(request, response);
83+
}
7784
}
85+
86+
7887

7988
}
8089

src/main/java/JEstebanC/FastFoodApp/security/SecurityConfig.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ protected void configure(HttpSecurity http) throws Exception {
4242
http.csrf().disable();
4343
// No session will be created or used by spring security
4444
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
45-
http.authorizeRequests().antMatchers("/api/v1/login/", "/api/v1/token-refresh/").permitAll();
45+
http.authorizeRequests().antMatchers("/api/v1/login/", "/api/v1/token-refresh/", "/api/v1/recover-password/", "/api/v1/reset-password/**").permitAll();
4646
http.addFilter(new CustomAuthenticationFilter(authenticationManagerBean()));
4747
http.addFilterBefore(new CustomAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class);
4848
}

src/main/java/JEstebanC/FastFoodApp/service/UserServiceImp.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,32 @@
55

66
import java.util.ArrayList;
77
import java.util.Collection;
8+
import java.util.Date;
89
import java.util.stream.Collectors;
910

11+
import javax.servlet.http.HttpServletRequest;
12+
import javax.servlet.http.HttpServletResponse;
1013
import javax.transaction.Transactional;
1114

1215
import org.springframework.beans.factory.annotation.Autowired;
16+
import org.springframework.mail.SimpleMailMessage;
17+
import org.springframework.mail.javamail.JavaMailSender;
1318
import org.springframework.security.core.authority.SimpleGrantedAuthority;
1419
import org.springframework.security.core.userdetails.UserDetails;
1520
import org.springframework.security.core.userdetails.UserDetailsService;
1621
import org.springframework.security.core.userdetails.UsernameNotFoundException;
1722
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
1823
import org.springframework.stereotype.Service;
1924

25+
import com.auth0.jwt.JWT;
26+
import com.auth0.jwt.JWTVerifier;
27+
import com.auth0.jwt.algorithms.Algorithm;
28+
import com.auth0.jwt.interfaces.DecodedJWT;
29+
2030
import JEstebanC.FastFoodApp.dto.UserDTO;
2131
import JEstebanC.FastFoodApp.model.User;
2232
import JEstebanC.FastFoodApp.repository.IUserRepository;
33+
import JEstebanC.FastFoodApp.security.OperationUtil;
2334
import lombok.RequiredArgsConstructor;
2435
import lombok.extern.slf4j.Slf4j;
2536

@@ -34,6 +45,8 @@ public class UserServiceImp implements IUserService, UserDetailsService {
3445
@Autowired
3546
private IUserRepository userRepository;
3647
private final BCryptPasswordEncoder bCryptPasswordEncoder;
48+
@Autowired
49+
private JavaMailSender javaMailSender;
3750

3851
@Override
3952
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
@@ -88,6 +101,27 @@ public User updateClient(User user, long id) {
88101
return userRepository.save(userOld);
89102
}
90103

104+
public String validationToken(String token) {
105+
try {
106+
Algorithm algorithm = Algorithm.HMAC256(OperationUtil.keyValue().getBytes());
107+
JWTVerifier verifier = JWT.require(algorithm).build();
108+
DecodedJWT decodeJWT = verifier.verify(token);
109+
String username = decodeJWT.getSubject();
110+
return username;
111+
} catch (Exception e) {
112+
log.error("Error logging in AuthorizationFilter: " + e.getMessage());
113+
}
114+
return null;
115+
}
116+
117+
public User updatePasswordClient(String username, String password) {
118+
log.info("Updating password username: " + username);
119+
User user = userRepository.findByUsername(username);
120+
121+
user.setPassword(bCryptPasswordEncoder.encode(password));
122+
return userRepository.save(user);
123+
}
124+
91125
@Override
92126
public Boolean delete(Long iduser) {
93127
log.info("Deleting the user with id: " + iduser);
@@ -153,4 +187,27 @@ public User findByUsername(String username) {
153187

154188
}
155189

190+
public Boolean sendMail(HttpServletRequest request, HttpServletResponse response, String email, String userName,
191+
String name) {
192+
193+
// Reference to the keyValue
194+
Algorithm algorithm = Algorithm.HMAC256(OperationUtil.keyValue().getBytes());
195+
String token = JWT.create().withSubject(userName)
196+
// give 10 minutes for the token to expire
197+
.withExpiresAt(new Date(System.currentTimeMillis() + 20 * 60 * 1000))
198+
.withIssuer(request.getRequestURL().toString()).sign(algorithm);
199+
200+
SimpleMailMessage message = new SimpleMailMessage();
201+
message.setTo(email);
202+
203+
message.setSubject("Burger App");
204+
String html = "Hola " + name + "! \n" + "¿olvidaste tu contraseña? \n"
205+
+ "Recibimos una petición para restablecer tu contraseña\n"
206+
+ "Para restablecer tu contraseña por favor presiona clic en el siguiente enlace \n"
207+
+ "http://localhost:8081/api/v1/reset-password?token=" + token;
208+
message.setText(html);
209+
javaMailSender.send(message);
210+
return true;
211+
}
212+
156213
}

0 commit comments

Comments
 (0)