/** * Copyright © 2016-2017 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.thingsboard.server.controller; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.web.bind.annotation.*; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.dao.user.UserService; import org.thingsboard.server.exception.ThingsboardErrorCode; import org.thingsboard.server.exception.ThingsboardException; import org.thingsboard.server.service.mail.MailService; import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRepository; import org.thingsboard.server.service.security.model.SecurityUser; import org.thingsboard.server.service.security.model.UserPrincipal; import org.thingsboard.server.service.security.model.token.JwtToken; import org.thingsboard.server.service.security.model.token.JwtTokenFactory; import javax.servlet.http.HttpServletRequest; import java.net.URI; import java.net.URISyntaxException; @RestController @RequestMapping("/api") @Slf4j public class AuthController extends BaseController { @Autowired private BCryptPasswordEncoder passwordEncoder; @Autowired private JwtTokenFactory tokenFactory; @Autowired private RefreshTokenRepository refreshTokenRepository; @Autowired private UserService userService; @Autowired private MailService mailService; @PreAuthorize("isAuthenticated()") @RequestMapping(value = "/auth/user", method = RequestMethod.GET) public @ResponseBody User getUser() throws ThingsboardException { try { SecurityUser securityUser = getCurrentUser(); return userService.findUserById(securityUser.getId()); } catch (Exception e) { throw handleException(e); } } @PreAuthorize("isAuthenticated()") @RequestMapping(value = "/auth/changePassword", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) public void changePassword ( @RequestParam(value = "currentPassword") String currentPassword, @RequestParam(value = "newPassword") String newPassword) throws ThingsboardException { try { SecurityUser securityUser = getCurrentUser(); UserCredentials userCredentials = userService.findUserCredentialsByUserId(securityUser.getId()); if (!passwordEncoder.matches(currentPassword, userCredentials.getPassword())) { throw new ThingsboardException("Current password doesn't match!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); } userCredentials.setPassword(passwordEncoder.encode(newPassword)); userService.saveUserCredentials(userCredentials); } catch (Exception e) { throw handleException(e); } } @RequestMapping(value = "/noauth/activate", params = { "activateToken" }, method = RequestMethod.GET) public ResponseEntity<String> checkActivateToken( @RequestParam(value = "activateToken") String activateToken) { HttpHeaders headers = new HttpHeaders(); HttpStatus responseStatus; UserCredentials userCredentials = userService.findUserCredentialsByActivateToken(activateToken); if (userCredentials != null) { String createPasswordURI = "/login/createPassword"; try { URI location = new URI(createPasswordURI + "?activateToken=" + activateToken); headers.setLocation(location); responseStatus = HttpStatus.PERMANENT_REDIRECT; } catch (URISyntaxException e) { log.error("Unable to create URI with address [{}]", createPasswordURI); responseStatus = HttpStatus.BAD_REQUEST; } } else { responseStatus = HttpStatus.CONFLICT; } return new ResponseEntity<>(headers, responseStatus); } @RequestMapping(value = "/noauth/resetPasswordByEmail", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) public void requestResetPasswordByEmail ( @RequestParam(value = "email") String email, HttpServletRequest request) throws ThingsboardException { try { UserCredentials userCredentials = userService.requestPasswordReset(email); String baseUrl = constructBaseUrl(request); String resetPasswordUrl = String.format("%s/api/noauth/resetPassword?resetToken=%s", baseUrl, userCredentials.getResetToken()); mailService.sendResetPasswordEmail(resetPasswordUrl, email); } catch (Exception e) { throw handleException(e); } } @RequestMapping(value = "/noauth/resetPassword", params = { "resetToken" }, method = RequestMethod.GET) public ResponseEntity<String> checkResetToken( @RequestParam(value = "resetToken") String resetToken) { HttpHeaders headers = new HttpHeaders(); HttpStatus responseStatus; String resetPasswordURI = "/login/resetPassword"; UserCredentials userCredentials = userService.findUserCredentialsByResetToken(resetToken); if (userCredentials != null) { try { URI location = new URI(resetPasswordURI + "?resetToken=" + resetToken); headers.setLocation(location); responseStatus = HttpStatus.PERMANENT_REDIRECT; } catch (URISyntaxException e) { log.error("Unable to create URI with address [{}]", resetPasswordURI); responseStatus = HttpStatus.BAD_REQUEST; } } else { responseStatus = HttpStatus.CONFLICT; } return new ResponseEntity<>(headers, responseStatus); } @RequestMapping(value = "/noauth/activate", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) @ResponseBody public JsonNode activateUser( @RequestParam(value = "activateToken") String activateToken, @RequestParam(value = "password") String password, HttpServletRequest request) throws ThingsboardException { try { String encodedPassword = passwordEncoder.encode(password); UserCredentials credentials = userService.activateUserCredentials(activateToken, encodedPassword); User user = userService.findUserById(credentials.getUserId()); UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail()); SecurityUser securityUser = new SecurityUser(user, credentials.isEnabled(), principal); String baseUrl = constructBaseUrl(request); String loginUrl = String.format("%s/login", baseUrl); String email = user.getEmail(); mailService.sendAccountActivatedEmail(loginUrl, email); JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); ObjectMapper objectMapper = new ObjectMapper(); ObjectNode tokenObject = objectMapper.createObjectNode(); tokenObject.put("token", accessToken.getToken()); tokenObject.put("refreshToken", refreshToken.getToken()); return tokenObject; } catch (Exception e) { throw handleException(e); } } @RequestMapping(value = "/noauth/resetPassword", method = RequestMethod.POST) @ResponseStatus(value = HttpStatus.OK) @ResponseBody public JsonNode resetPassword( @RequestParam(value = "resetToken") String resetToken, @RequestParam(value = "password") String password, HttpServletRequest request) throws ThingsboardException { try { UserCredentials userCredentials = userService.findUserCredentialsByResetToken(resetToken); if (userCredentials != null) { String encodedPassword = passwordEncoder.encode(password); userCredentials.setPassword(encodedPassword); userCredentials.setResetToken(null); userCredentials = userService.saveUserCredentials(userCredentials); User user = userService.findUserById(userCredentials.getUserId()); UserPrincipal principal = new UserPrincipal(UserPrincipal.Type.USER_NAME, user.getEmail()); SecurityUser securityUser = new SecurityUser(user, userCredentials.isEnabled(), principal); String baseUrl = constructBaseUrl(request); String loginUrl = String.format("%s/login", baseUrl); String email = user.getEmail(); mailService.sendPasswordWasResetEmail(loginUrl, email); JwtToken accessToken = tokenFactory.createAccessJwtToken(securityUser); JwtToken refreshToken = refreshTokenRepository.requestRefreshToken(securityUser); ObjectMapper objectMapper = new ObjectMapper(); ObjectNode tokenObject = objectMapper.createObjectNode(); tokenObject.put("token", accessToken.getToken()); tokenObject.put("refreshToken", refreshToken.getToken()); return tokenObject; } else { throw new ThingsboardException("Invalid reset token!", ThingsboardErrorCode.BAD_REQUEST_PARAMS); } } catch (Exception e) { throw handleException(e); } } }