diff --git a/application/src/main/java/org/thingsboard/server/controller/AuthController.java b/application/src/main/java/org/thingsboard/server/controller/AuthController.java index aa194d688e..a52a80f9f0 100644 --- a/application/src/main/java/org/thingsboard/server/controller/AuthController.java +++ b/application/src/main/java/org/thingsboard/server/controller/AuthController.java @@ -58,9 +58,6 @@ import org.thingsboard.server.service.security.model.UserPrincipal; import org.thingsboard.server.service.security.model.token.JwtTokenFactory; import org.thingsboard.server.service.security.system.SystemSecurityService; -import java.net.URI; -import java.net.URISyntaxException; - @RestController @TbCoreComponent @RequestMapping("/api") @@ -132,7 +129,7 @@ public class AuthController extends BaseController { 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 not valid, returns '409 Conflict'. " + - "If token is expired, returns '410 Gone'.") + "If token is expired, redirects to error page.") @GetMapping(value = "/noauth/activate", params = {"activateToken"}) public ResponseEntity checkActivateToken( @Parameter(description = "The activate token string.") @@ -141,18 +138,9 @@ public class AuthController extends BaseController { if (userCredentials == null) { return response(HttpStatus.CONFLICT); } else if (userCredentials.isActivationTokenExpired()) { - return response(HttpStatus.GONE); - } - - String createURI = "/login/createPassword"; - try { - URI location = new URI(createURI + "?activateToken=" + activateToken); - return ResponseEntity.status(HttpStatus.SEE_OTHER) - .location(location).build(); - } catch (URISyntaxException e) { - log.error("Unable to create URI with address [{}]", createURI); - return response(HttpStatus.BAD_REQUEST); + return redirectTo("/activationLinkExpired"); } + return redirectTo("/login/createPassword?activateToken=" + activateToken); } @ApiOperation(value = "Request reset password email (requestResetPasswordByEmail)", @@ -181,7 +169,7 @@ public class AuthController extends BaseController { 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 not valid, returns '409 Conflict'. " + - "If token is expired, returns '410 Gone'.") + "If token is expired, redirects to error page.") @GetMapping(value = "/noauth/resetPassword", params = {"resetToken"}) public ResponseEntity checkResetToken( @Parameter(description = "The reset token string.") @@ -190,21 +178,12 @@ public class AuthController extends BaseController { if (userCredentials == null) { return response(HttpStatus.CONFLICT); } else if (userCredentials.isResetTokenExpired()) { - return response(HttpStatus.GONE); + return redirectTo("/passwordResetLinkExpired"); } if (!rateLimitService.checkRateLimit(LimitedApi.PASSWORD_RESET, userCredentials.getUserId(), defaultLimitsConfiguration)) { return response(HttpStatus.TOO_MANY_REQUESTS); } - - String resetURI = "/login/resetPassword"; - try { - URI location = new URI(resetURI + "?resetToken=" + resetToken); - return ResponseEntity.status(HttpStatus.SEE_OTHER) - .location(location).build(); - } catch (URISyntaxException e) { - log.error("Unable to create URI with address [{}]", resetURI); - return response(HttpStatus.BAD_REQUEST); - } + return redirectTo("/login/resetPassword?resetToken=" + resetToken); } @ApiOperation(value = "Activate User", diff --git a/application/src/main/java/org/thingsboard/server/controller/BaseController.java b/application/src/main/java/org/thingsboard/server/controller/BaseController.java index 54d91b6cfb..d266c7e6cc 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -134,8 +134,8 @@ import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.IncorrectParameterException; import org.thingsboard.server.dao.mobile.MobileAppService; import org.thingsboard.server.dao.model.ModelConstants; -import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService; import org.thingsboard.server.dao.oauth2.OAuth2ClientService; +import org.thingsboard.server.dao.oauth2.OAuth2ConfigTemplateService; import org.thingsboard.server.dao.ota.OtaPackageService; import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.relation.RelationService; @@ -172,8 +172,8 @@ import org.thingsboard.server.service.sync.vc.EntitiesVersionControlService; import org.thingsboard.server.service.telemetry.AlarmSubscriptionService; import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; +import java.net.URI; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -918,6 +918,19 @@ public abstract class BaseController { return ResponseEntity.status(status).build(); } + protected ResponseEntity redirectTo(String location) { + URI uri; + try { + uri = URI.create(location); + } catch (IllegalArgumentException e) { + log.error("Failed to create URI from '{}'", location, e); + throw e; + } + return ResponseEntity.status(HttpStatus.SEE_OTHER) + .location(uri) + .build(); + } + protected List getOAuth2ClientIds(UUID[] ids) throws ThingsboardException { if (ids == null) { return Collections.emptyList(); diff --git a/application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java index e4010713d8..d2586b93e9 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AuthControllerTest.java @@ -195,7 +195,8 @@ public class AuthControllerTest extends AbstractControllerTest { userCredentialsDao.save(tenantId, userCredentials); doGet("/api/noauth/resetPassword?resetToken={resetToken}", this.currentResetPasswordToken) - .andExpect(status().isGone()); + .andExpect(status().isSeeOther()) + .andExpect(header().string(HttpHeaders.LOCATION, "/passwordResetLinkExpired")); JsonNode resetPasswordRequest = JacksonUtil.newObjectNode() .put("resetToken", this.currentResetPasswordToken) .put("password", "wefwefe"); @@ -229,7 +230,8 @@ public class AuthControllerTest extends AbstractControllerTest { userCredentials.setActivateTokenExpTime(System.currentTimeMillis() - 1); userCredentialsDao.save(tenantId, userCredentials); doGet("/api/noauth/activate?activateToken={activateToken}", initialActivationToken) - .andExpect(status().isGone()); + .andExpect(status().isSeeOther()) + .andExpect(header().string(HttpHeaders.LOCATION, "/activationLinkExpired")); doPost("/api/noauth/activate", JacksonUtil.newObjectNode() .put("activateToken", initialActivationToken) .put("password", "wefewe")).andExpect(status().isBadRequest())