Browse Source

Status '410 Gone' when token is expired

pull/11578/head
ViacheslavKlimov 2 years ago
parent
commit
478d20aec7
  1. 74
      application/src/main/java/org/thingsboard/server/controller/AuthController.java
  2. 6
      application/src/main/java/org/thingsboard/server/controller/BaseController.java
  3. 2
      application/src/main/java/org/thingsboard/server/controller/ImageController.java
  4. 3
      application/src/main/java/org/thingsboard/server/controller/MobileApplicationController.java
  5. 4
      application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java

74
application/src/main/java/org/thingsboard/server/controller/AuthController.java

@ -21,7 +21,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.access.prepost.PreAuthorize;
@ -132,28 +131,28 @@ public class AuthController extends BaseController {
@ApiOperation(value = "Check Activate User Token (checkActivateToken)", @ApiOperation(value = "Check Activate User Token (checkActivateToken)",
notes = "Checks the activation token and forwards user to 'Create Password' page. " + notes = "Checks the activation token and forwards user to 'Create Password' page. " +
"If token is valid, returns '303 See Other' (redirect) response code with the correct address of 'Create Password' page and same 'activateToken' specified in the URL parameters. " + "If token is valid, returns '303 See Other' (redirect) response code with the correct address of 'Create Password' page and same 'activateToken' specified in the URL parameters. " +
"If token is not valid, returns '409 Conflict'.") "If token is not valid, returns '409 Conflict'. " +
"If token is expired, returns '410 Gone'.")
@GetMapping(value = "/noauth/activate", params = {"activateToken"}) @GetMapping(value = "/noauth/activate", params = {"activateToken"})
public ResponseEntity<String> checkActivateToken( public ResponseEntity<?> checkActivateToken(
@Parameter(description = "The activate token string.") @Parameter(description = "The activate token string.")
@RequestParam(value = "activateToken") String activateToken) { @RequestParam(value = "activateToken") String activateToken) {
HttpHeaders headers = new HttpHeaders();
HttpStatus responseStatus;
UserCredentials userCredentials = userService.findUserCredentialsByActivateToken(TenantId.SYS_TENANT_ID, activateToken); UserCredentials userCredentials = userService.findUserCredentialsByActivateToken(TenantId.SYS_TENANT_ID, activateToken);
if (userCredentials != null && !userCredentials.isActivationTokenExpired()) { if (userCredentials == null) {
String createURI = "/login/createPassword"; return response(HttpStatus.CONFLICT);
try { } else if (userCredentials.isActivationTokenExpired()) {
URI location = new URI(createURI + "?activateToken=" + activateToken); return response(HttpStatus.GONE);
headers.setLocation(location); }
responseStatus = HttpStatus.SEE_OTHER;
} catch (URISyntaxException e) { String createURI = "/login/createPassword";
log.error("Unable to create URI with address [{}]", createURI); try {
responseStatus = HttpStatus.BAD_REQUEST; URI location = new URI(createURI + "?activateToken=" + activateToken);
} return ResponseEntity.status(HttpStatus.SEE_OTHER)
} else { .location(location).build();
responseStatus = HttpStatus.CONFLICT; } catch (URISyntaxException e) {
log.error("Unable to create URI with address [{}]", createURI);
return response(HttpStatus.BAD_REQUEST);
} }
return new ResponseEntity<>(headers, responseStatus);
} }
@ApiOperation(value = "Request reset password email (requestResetPasswordByEmail)", @ApiOperation(value = "Request reset password email (requestResetPasswordByEmail)",
@ -181,32 +180,31 @@ public class AuthController extends BaseController {
@ApiOperation(value = "Check password reset token (checkResetToken)", @ApiOperation(value = "Check password reset token (checkResetToken)",
notes = "Checks the password reset token and forwards user to 'Reset Password' page. " + notes = "Checks the password reset token and forwards user to 'Reset Password' page. " +
"If token is valid, returns '303 See Other' (redirect) response code with the correct address of 'Reset Password' page and same 'resetToken' specified in the URL parameters. " + "If token is valid, returns '303 See Other' (redirect) response code with the correct address of 'Reset Password' page and same 'resetToken' specified in the URL parameters. " +
"If token is not valid, returns '409 Conflict'.") "If token is not valid, returns '409 Conflict'. " +
"If token is expired, returns '410 Gone'.")
@GetMapping(value = "/noauth/resetPassword", params = {"resetToken"}) @GetMapping(value = "/noauth/resetPassword", params = {"resetToken"})
public ResponseEntity<String> checkResetToken( public ResponseEntity<?> checkResetToken(
@Parameter(description = "The reset token string.") @Parameter(description = "The reset token string.")
@RequestParam(value = "resetToken") String resetToken) { @RequestParam(value = "resetToken") String resetToken) {
HttpHeaders headers = new HttpHeaders();
HttpStatus responseStatus;
String resetURI = "/login/resetPassword";
UserCredentials userCredentials = userService.findUserCredentialsByResetToken(TenantId.SYS_TENANT_ID, resetToken); UserCredentials userCredentials = userService.findUserCredentialsByResetToken(TenantId.SYS_TENANT_ID, resetToken);
if (userCredentials == null) {
return response(HttpStatus.CONFLICT);
} else if (userCredentials.isResetTokenExpired()) {
return response(HttpStatus.GONE);
}
if (!rateLimitService.checkRateLimit(LimitedApi.PASSWORD_RESET, userCredentials.getUserId(), defaultLimitsConfiguration)) {
return response(HttpStatus.TOO_MANY_REQUESTS);
}
if (userCredentials != null && !userCredentials.isResetTokenExpired()) { String resetURI = "/login/resetPassword";
if (!rateLimitService.checkRateLimit(LimitedApi.PASSWORD_RESET, userCredentials.getUserId(), defaultLimitsConfiguration)) { try {
return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).build(); URI location = new URI(resetURI + "?resetToken=" + resetToken);
} return ResponseEntity.status(HttpStatus.SEE_OTHER)
try { .location(location).build();
URI location = new URI(resetURI + "?resetToken=" + resetToken); } catch (URISyntaxException e) {
headers.setLocation(location); log.error("Unable to create URI with address [{}]", resetURI);
responseStatus = HttpStatus.SEE_OTHER; return response(HttpStatus.BAD_REQUEST);
} catch (URISyntaxException e) {
log.error("Unable to create URI with address [{}]", resetURI);
responseStatus = HttpStatus.BAD_REQUEST;
}
} else {
responseStatus = HttpStatus.CONFLICT;
} }
return new ResponseEntity<>(headers, responseStatus);
} }
@ApiOperation(value = "Activate User", @ApiOperation(value = "Activate User",

6
application/src/main/java/org/thingsboard/server/controller/BaseController.java

@ -27,7 +27,9 @@ import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType; import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication; import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MethodArgumentNotValidException;
@ -867,4 +869,8 @@ public abstract class BaseController {
} }
} }
protected <T> ResponseEntity<T> response(HttpStatus status) {
return ResponseEntity.status(status).build();
}
} }

2
application/src/main/java/org/thingsboard/server/controller/ImageController.java

@ -290,7 +290,7 @@ public class ImageController extends BaseController {
if (StringUtils.isNotEmpty(etag)) { if (StringUtils.isNotEmpty(etag)) {
etag = StringUtils.remove(etag, '\"'); // etag is wrapped in double quotes due to HTTP specification etag = StringUtils.remove(etag, '\"'); // etag is wrapped in double quotes due to HTTP specification
if (etag.equals(tbImageService.getETag(cacheKey))) { if (etag.equals(tbImageService.getETag(cacheKey))) {
return ResponseEntity.status(HttpStatus.NOT_MODIFIED).build(); return response(HttpStatus.NOT_MODIFIED);
} }
} }

3
application/src/main/java/org/thingsboard/server/controller/MobileApplicationController.java

@ -183,8 +183,7 @@ public class MobileApplicationController extends BaseController {
.header("Location", appStoreLink) .header("Location", appStoreLink)
.build(); .build();
} else { } else {
return ResponseEntity.status(HttpStatus.NOT_FOUND) return response(HttpStatus.NOT_FOUND);
.build();
} }
} }

4
application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java

@ -193,7 +193,7 @@ public class AuthControllerTest extends AbstractControllerTest {
userCredentialsDao.save(tenantId, userCredentials); userCredentialsDao.save(tenantId, userCredentials);
doGet("/api/noauth/resetPassword?resetToken={resetToken}", this.currentResetPasswordToken) doGet("/api/noauth/resetPassword?resetToken={resetToken}", this.currentResetPasswordToken)
.andExpect(status().isConflict()); .andExpect(status().isGone());
JsonNode resetPasswordRequest = JacksonUtil.newObjectNode() JsonNode resetPasswordRequest = JacksonUtil.newObjectNode()
.put("resetToken", this.currentResetPasswordToken) .put("resetToken", this.currentResetPasswordToken)
.put("password", "wefwefe"); .put("password", "wefwefe");
@ -223,7 +223,7 @@ public class AuthControllerTest extends AbstractControllerTest {
userCredentials.setActivateTokenExpTime(System.currentTimeMillis() - 1); userCredentials.setActivateTokenExpTime(System.currentTimeMillis() - 1);
userCredentialsDao.save(tenantId, userCredentials); userCredentialsDao.save(tenantId, userCredentials);
doGet("/api/noauth/activate?activateToken={activateToken}", initialActivationToken) doGet("/api/noauth/activate?activateToken={activateToken}", initialActivationToken)
.andExpect(status().isConflict()); .andExpect(status().isGone());
doPost("/api/noauth/activate", JacksonUtil.newObjectNode() doPost("/api/noauth/activate", JacksonUtil.newObjectNode()
.put("activateToken", initialActivationToken) .put("activateToken", initialActivationToken)
.put("password", "wefewe")).andExpect(status().isBadRequest()) .put("password", "wefewe")).andExpect(status().isBadRequest())

Loading…
Cancel
Save