Skip to content

Commit 9fcdb93

Browse files
Create error handling mechanisms for token errors
1 parent 2d02fa1 commit 9fcdb93

File tree

9 files changed

+88
-15
lines changed

9 files changed

+88
-15
lines changed

src/main/java/com/springboilerplate/springboilerplate/controller/UserController.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public UserController(UserService userService, TokenAuthenticationService tokenA
4040
@PostMapping(path="/register")
4141
public ResponseEntity<?> registerUser(@Valid @RequestBody UserDto user) throws Exception {
4242
final User registeredUser = userService.saveUser(user, RoleType.USER);
43-
String token = tokenAuthenticationService.createUserToken(registeredUser);
43+
s
4444
HttpHeaders responseHeaders = new HttpHeaders();
4545
responseHeaders.set(TokenAuthenticationService.AUTH_HEADER_NAME, token);
4646
return new ResponseEntity<>("Registered and Logged in", responseHeaders, HttpStatus.CREATED);
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,56 @@
11
package com.springboilerplate.springboilerplate.exceptions;
22

33

4+
import org.springframework.http.HttpHeaders;
5+
import org.springframework.http.HttpStatus;
6+
import org.springframework.http.ResponseEntity;
7+
import org.springframework.validation.FieldError;
8+
import org.springframework.web.bind.MethodArgumentNotValidException;
9+
import org.springframework.web.bind.MissingServletRequestParameterException;
410
import org.springframework.web.bind.annotation.ControllerAdvice;
11+
import org.springframework.web.bind.annotation.ExceptionHandler;
12+
import org.springframework.web.context.request.WebRequest;
513
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
614

15+
import java.util.List;
16+
import java.util.stream.Collectors;
17+
718
@ControllerAdvice
819
public class CentralizedExceptionHandler extends ResponseEntityExceptionHandler {
920

21+
@Override
22+
protected ResponseEntity<Object> handleMissingServletRequestParameter(
23+
MissingServletRequestParameterException exception, HttpHeaders headers,
24+
HttpStatus status, WebRequest request){
25+
logger.error("Missing servlet request parameter exception.");
26+
String error = String.format("%s parameter is missing", exception.getParameterName());
27+
ApiError apiError = new ApiError(HttpStatus.BAD_REQUEST, exception.getLocalizedMessage(), error);
28+
return new ResponseEntity<>(apiError, new HttpHeaders(), apiError.getStatus());
29+
}
30+
31+
@Override
32+
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException exception, HttpHeaders headers,
33+
HttpStatus status, WebRequest request){
34+
logger.error("Method argument not valid.");
35+
List<FieldError> fieldErrors = exception.getBindingResult().getFieldErrors();
36+
String error = fieldErrors.stream()
37+
.map(fieldError -> fieldError.getField() + " : " + fieldError.getDefaultMessage())
38+
.collect(Collectors.joining());
39+
ApiError apiError = new ApiError(HttpStatus.BAD_REQUEST, exception.getMessage(), error);
40+
return new ResponseEntity<>(apiError, apiError.getStatus());
41+
}
42+
43+
@ExceptionHandler({ExpiredTokenException.class})
44+
public ResponseEntity<Object> handleExpiredTokenException(ExpiredTokenException ex, WebRequest webRequest){
45+
String error = ex.getMessage();
46+
ApiError apiError = new ApiError(HttpStatus.BAD_REQUEST, ex.getMessage(), error);
47+
return new ResponseEntity<>(apiError, apiError.getStatus());
48+
}
49+
50+
@ExceptionHandler({InvalidTokenException.class})
51+
public ResponseEntity<Object> handleInvalidTokenException(InvalidTokenException ex, WebRequest webRequest){
52+
String error = ex.getMessage();
53+
ApiError apiError = new ApiError(HttpStatus.BAD_REQUEST, ex.getMessage(), error);
54+
return new ResponseEntity<>(apiError, apiError.getStatus());
55+
}
1056
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.springboilerplate.springboilerplate.exceptions;
2+
3+
public class ExpiredTokenException extends RuntimeException {
4+
5+
public ExpiredTokenException(String message) {
6+
super(message);
7+
}
8+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.springboilerplate.springboilerplate.exceptions;
2+
3+
public class InvalidTokenException extends RuntimeException {
4+
5+
public InvalidTokenException(String message) {
6+
super(message);
7+
}
8+
}

src/main/java/com/springboilerplate/springboilerplate/model/PasswordResetToken.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class PasswordResetToken {
1717

1818
@Id
1919
@GeneratedValue(strategy= GenerationType.IDENTITY)
20+
@Column(name = "password_reset_token_id")
2021
public Long getId() {
2122
return id;
2223
}

src/main/java/com/springboilerplate/springboilerplate/security/StatelessAuthenticationFilter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public void doFilter(ServletRequest request, ServletResponse response, FilterCha
2626
chain.doFilter(request, response);
2727
}
2828

29-
private void setAuthenticationFromHeader(HttpServletRequest request) {
29+
private void setAuthenticationFromHeader(HttpServletRequest request){
3030
final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
3131
if (!(authentication instanceof UserAuthentication)) {
3232
final UserAuthentication userAuthentication = tokenAuthenticationService.

src/main/java/com/springboilerplate/springboilerplate/security/TokenHandler.java

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
import com.fasterxml.jackson.databind.ObjectMapper;
66
import com.fasterxml.jackson.databind.SerializationFeature;
77
import com.fasterxml.jackson.datatype.jsr310.JSR310Module;
8+
import com.springboilerplate.springboilerplate.exceptions.ExpiredTokenException;
9+
import com.springboilerplate.springboilerplate.exceptions.InvalidTokenException;
810
import com.springboilerplate.springboilerplate.model.User;
911
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
1012
import org.springframework.stereotype.Component;
@@ -38,25 +40,37 @@ public TokenHandler(byte[] secretKey) {
3840

3941
public User parseUserFromToken(String token) {
4042
final String[] parts = token.split(SEPARATOR_SPLITTER);
41-
if (parts.length == 2 && parts[0].length() > 0 && parts[1].length() > 0) {
43+
if (validToken(parts)) {
4244
try {
4345
final byte[] userBytes = fromBase64(parts[0]);
4446
final byte[] hash = fromBase64(parts[1]);
45-
4647
boolean validHash = Arrays.equals(createHmac(userBytes), hash);
47-
if (validHash) {
48-
final User user = fromJSON(userBytes);
49-
if (new Date().getTime() < user.getExpires()) {
50-
return user;
51-
}
52-
}
48+
final User user = getUser(userBytes, validHash);
49+
if (user != null) return user;
5350
} catch (IllegalArgumentException e) {
5451
//log tempering attempt here
5552
}
5653
}
5754
return null;
5855
}
5956

57+
private User getUser(byte[] userBytes, boolean validHash) {
58+
if (validHash) {
59+
final User user = fromJSON(userBytes);
60+
long currentTime = new Date().getTime();
61+
if (currentTime < user.getExpires()) {
62+
return user;
63+
}else {
64+
throw new ExpiredTokenException("User token has expired.");
65+
}
66+
}
67+
throw new InvalidTokenException("The token is not valid");
68+
}
69+
70+
private boolean validToken(String parts[]){
71+
return parts.length == 2 && parts[0].length() > 0 && parts[1].length() > 0;
72+
}
73+
6074
public String createTokenForUser(User user) {
6175
byte[] userBytes = toJSON(user);
6276
byte[] hash = createHmac(userBytes);

src/main/resources/application.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ server.port=8080
55

66
spring.jpa.database=POSTGRESQL
77
spring.datasource.platform=postgres
8-
spring.jpa.hibernate.ddl-auto=create-drop
8+
spring.jpa.hibernate.ddl-auto=validate
99
spring.database.driverClassName=org.postgresql.Driver
1010
spring.datasource.url=jdbc:postgresql://localhost:5432/boilerplate
1111
spring.datasource.username=postgres

src/main/resources/data-postgres.sql

Lines changed: 0 additions & 4 deletions
This file was deleted.

0 commit comments

Comments
 (0)