Merge pull request #9831 from dashevchenko/forcedPasswordPolicyCheck
Moved password policy check before user info rest calls
This commit is contained in:
commit
5946bde4c6
@ -170,7 +170,7 @@ public class AdminController extends BaseController {
|
|||||||
@ResponseBody
|
@ResponseBody
|
||||||
public SecuritySettings getSecuritySettings() throws ThingsboardException {
|
public SecuritySettings getSecuritySettings() throws ThingsboardException {
|
||||||
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
|
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.READ);
|
||||||
return checkNotNull(systemSecurityService.getSecuritySettings(TenantId.SYS_TENANT_ID));
|
return checkNotNull(systemSecurityService.getSecuritySettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiOperation(value = "Update Security Settings (saveSecuritySettings)",
|
@ApiOperation(value = "Update Security Settings (saveSecuritySettings)",
|
||||||
@ -182,7 +182,7 @@ public class AdminController extends BaseController {
|
|||||||
@ApiParam(value = "A JSON value representing the Security Settings.")
|
@ApiParam(value = "A JSON value representing the Security Settings.")
|
||||||
@RequestBody SecuritySettings securitySettings) throws ThingsboardException {
|
@RequestBody SecuritySettings securitySettings) throws ThingsboardException {
|
||||||
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE);
|
accessControlService.checkPermission(getCurrentUser(), Resource.ADMIN_SETTINGS, Operation.WRITE);
|
||||||
securitySettings = checkNotNull(systemSecurityService.saveSecuritySettings(TenantId.SYS_TENANT_ID, securitySettings));
|
securitySettings = checkNotNull(systemSecurityService.saveSecuritySettings(securitySettings));
|
||||||
return securitySettings;
|
return securitySettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -115,7 +115,7 @@ public class AuthController extends BaseController {
|
|||||||
if (!passwordEncoder.matches(currentPassword, userCredentials.getPassword())) {
|
if (!passwordEncoder.matches(currentPassword, userCredentials.getPassword())) {
|
||||||
throw new ThingsboardException("Current password doesn't match!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
|
throw new ThingsboardException("Current password doesn't match!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
|
||||||
}
|
}
|
||||||
systemSecurityService.validatePassword(securityUser.getTenantId(), newPassword, userCredentials);
|
systemSecurityService.validatePassword(newPassword, userCredentials);
|
||||||
if (passwordEncoder.matches(newPassword, userCredentials.getPassword())) {
|
if (passwordEncoder.matches(newPassword, userCredentials.getPassword())) {
|
||||||
throw new ThingsboardException("New password should be different from existing!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
|
throw new ThingsboardException("New password should be different from existing!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ public class AuthController extends BaseController {
|
|||||||
@ResponseBody
|
@ResponseBody
|
||||||
public UserPasswordPolicy getUserPasswordPolicy() throws ThingsboardException {
|
public UserPasswordPolicy getUserPasswordPolicy() throws ThingsboardException {
|
||||||
SecuritySettings securitySettings =
|
SecuritySettings securitySettings =
|
||||||
checkNotNull(systemSecurityService.getSecuritySettings(TenantId.SYS_TENANT_ID));
|
checkNotNull(systemSecurityService.getSecuritySettings());
|
||||||
return securitySettings.getPasswordPolicy();
|
return securitySettings.getPasswordPolicy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,7 +237,7 @@ public class AuthController extends BaseController {
|
|||||||
HttpServletRequest request) throws ThingsboardException {
|
HttpServletRequest request) throws ThingsboardException {
|
||||||
String activateToken = activateRequest.getActivateToken();
|
String activateToken = activateRequest.getActivateToken();
|
||||||
String password = activateRequest.getPassword();
|
String password = activateRequest.getPassword();
|
||||||
systemSecurityService.validatePassword(TenantId.SYS_TENANT_ID, password, null);
|
systemSecurityService.validatePassword(password, null);
|
||||||
String encodedPassword = passwordEncoder.encode(password);
|
String encodedPassword = passwordEncoder.encode(password);
|
||||||
UserCredentials credentials = userService.activateUserCredentials(TenantId.SYS_TENANT_ID, activateToken, encodedPassword);
|
UserCredentials credentials = userService.activateUserCredentials(TenantId.SYS_TENANT_ID, activateToken, encodedPassword);
|
||||||
User user = userService.findUserById(TenantId.SYS_TENANT_ID, credentials.getUserId());
|
User user = userService.findUserById(TenantId.SYS_TENANT_ID, credentials.getUserId());
|
||||||
@ -274,7 +274,7 @@ public class AuthController extends BaseController {
|
|||||||
String password = resetPasswordRequest.getPassword();
|
String password = resetPasswordRequest.getPassword();
|
||||||
UserCredentials userCredentials = userService.findUserCredentialsByResetToken(TenantId.SYS_TENANT_ID, resetToken);
|
UserCredentials userCredentials = userService.findUserCredentialsByResetToken(TenantId.SYS_TENANT_ID, resetToken);
|
||||||
if (userCredentials != null) {
|
if (userCredentials != null) {
|
||||||
systemSecurityService.validatePassword(TenantId.SYS_TENANT_ID, password, userCredentials);
|
systemSecurityService.validatePassword(password, userCredentials);
|
||||||
if (passwordEncoder.matches(password, userCredentials.getPassword())) {
|
if (passwordEncoder.matches(password, userCredentials.getPassword())) {
|
||||||
throw new ThingsboardException("New password should be different from existing!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
|
throw new ThingsboardException("New password should be different from existing!", ThingsboardErrorCode.BAD_REQUEST_PARAMS);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,11 +36,15 @@ import org.thingsboard.server.common.data.id.TenantId;
|
|||||||
import org.thingsboard.server.common.data.id.UserId;
|
import org.thingsboard.server.common.data.id.UserId;
|
||||||
import org.thingsboard.server.common.data.security.Authority;
|
import org.thingsboard.server.common.data.security.Authority;
|
||||||
import org.thingsboard.server.common.data.security.UserCredentials;
|
import org.thingsboard.server.common.data.security.UserCredentials;
|
||||||
|
import org.thingsboard.server.common.data.security.model.SecuritySettings;
|
||||||
|
import org.thingsboard.server.common.data.security.model.UserPasswordPolicy;
|
||||||
import org.thingsboard.server.dao.customer.CustomerService;
|
import org.thingsboard.server.dao.customer.CustomerService;
|
||||||
|
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||||
import org.thingsboard.server.dao.user.UserService;
|
import org.thingsboard.server.dao.user.UserService;
|
||||||
import org.thingsboard.server.queue.util.TbCoreComponent;
|
import org.thingsboard.server.queue.util.TbCoreComponent;
|
||||||
import org.thingsboard.server.service.security.auth.MfaAuthenticationToken;
|
import org.thingsboard.server.service.security.auth.MfaAuthenticationToken;
|
||||||
import org.thingsboard.server.service.security.auth.mfa.TwoFactorAuthService;
|
import org.thingsboard.server.service.security.auth.mfa.TwoFactorAuthService;
|
||||||
|
import org.thingsboard.server.service.security.exception.UserPasswordNotValidException;
|
||||||
import org.thingsboard.server.service.security.model.SecurityUser;
|
import org.thingsboard.server.service.security.model.SecurityUser;
|
||||||
import org.thingsboard.server.service.security.model.UserPrincipal;
|
import org.thingsboard.server.service.security.model.UserPrincipal;
|
||||||
import org.thingsboard.server.service.security.system.SystemSecurityService;
|
import org.thingsboard.server.service.security.system.SystemSecurityService;
|
||||||
@ -83,6 +87,17 @@ public class RestAuthenticationProvider implements AuthenticationProvider {
|
|||||||
if (userPrincipal.getType() == UserPrincipal.Type.USER_NAME) {
|
if (userPrincipal.getType() == UserPrincipal.Type.USER_NAME) {
|
||||||
String username = userPrincipal.getValue();
|
String username = userPrincipal.getValue();
|
||||||
String password = (String) authentication.getCredentials();
|
String password = (String) authentication.getCredentials();
|
||||||
|
|
||||||
|
SecuritySettings securitySettings = systemSecurityService.getSecuritySettings();
|
||||||
|
UserPasswordPolicy passwordPolicy = securitySettings.getPasswordPolicy();
|
||||||
|
if (Boolean.TRUE.equals(passwordPolicy.getForceUserToResetPasswordIfNotValid())) {
|
||||||
|
try {
|
||||||
|
systemSecurityService.validatePasswordByPolicy(password, passwordPolicy);
|
||||||
|
} catch (DataValidationException e) {
|
||||||
|
throw new UserPasswordNotValidException("The entered password violates our policies. If this is your real password, please reset it.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
securityUser = authenticateByUsernameAndPassword(authentication, userPrincipal, username, password);
|
securityUser = authenticateByUsernameAndPassword(authentication, userPrincipal, username, password);
|
||||||
if (twoFactorAuthService.isTwoFaEnabled(securityUser.getTenantId(), securityUser.getId())) {
|
if (twoFactorAuthService.isTwoFaEnabled(securityUser.getTenantId(), securityUser.getId())) {
|
||||||
return new MfaAuthenticationToken(securityUser);
|
return new MfaAuthenticationToken(securityUser);
|
||||||
|
|||||||
@ -15,9 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.thingsboard.server.service.security.exception;
|
package org.thingsboard.server.service.security.exception;
|
||||||
|
|
||||||
import org.springframework.security.core.AuthenticationException;
|
import org.springframework.security.authentication.AccountStatusException;
|
||||||
|
|
||||||
public class UserPasswordNotValidException extends AuthenticationException {
|
public class UserPasswordNotValidException extends AccountStatusException {
|
||||||
|
|
||||||
public UserPasswordNotValidException(String msg) {
|
public UserPasswordNotValidException(String msg) {
|
||||||
super(msg);
|
super(msg);
|
||||||
|
|||||||
@ -95,9 +95,9 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
|
|||||||
|
|
||||||
@Cacheable(cacheNames = SECURITY_SETTINGS_CACHE, key = "'securitySettings'")
|
@Cacheable(cacheNames = SECURITY_SETTINGS_CACHE, key = "'securitySettings'")
|
||||||
@Override
|
@Override
|
||||||
public SecuritySettings getSecuritySettings(TenantId tenantId) {
|
public SecuritySettings getSecuritySettings() {
|
||||||
SecuritySettings securitySettings = null;
|
SecuritySettings securitySettings = null;
|
||||||
AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(tenantId, "securitySettings");
|
AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "securitySettings");
|
||||||
if (adminSettings != null) {
|
if (adminSettings != null) {
|
||||||
try {
|
try {
|
||||||
securitySettings = JacksonUtil.convertValue(adminSettings.getJsonValue(), SecuritySettings.class);
|
securitySettings = JacksonUtil.convertValue(adminSettings.getJsonValue(), SecuritySettings.class);
|
||||||
@ -115,15 +115,15 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
|
|||||||
|
|
||||||
@CacheEvict(cacheNames = SECURITY_SETTINGS_CACHE, key = "'securitySettings'")
|
@CacheEvict(cacheNames = SECURITY_SETTINGS_CACHE, key = "'securitySettings'")
|
||||||
@Override
|
@Override
|
||||||
public SecuritySettings saveSecuritySettings(TenantId tenantId, SecuritySettings securitySettings) {
|
public SecuritySettings saveSecuritySettings(SecuritySettings securitySettings) {
|
||||||
AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(tenantId, "securitySettings");
|
AdminSettings adminSettings = adminSettingsService.findAdminSettingsByKey(TenantId.SYS_TENANT_ID, "securitySettings");
|
||||||
if (adminSettings == null) {
|
if (adminSettings == null) {
|
||||||
adminSettings = new AdminSettings();
|
adminSettings = new AdminSettings();
|
||||||
adminSettings.setTenantId(tenantId);
|
adminSettings.setTenantId(TenantId.SYS_TENANT_ID);
|
||||||
adminSettings.setKey("securitySettings");
|
adminSettings.setKey("securitySettings");
|
||||||
}
|
}
|
||||||
adminSettings.setJsonValue(JacksonUtil.valueToTree(securitySettings));
|
adminSettings.setJsonValue(JacksonUtil.valueToTree(securitySettings));
|
||||||
AdminSettings savedAdminSettings = adminSettingsService.saveAdminSettings(tenantId, adminSettings);
|
AdminSettings savedAdminSettings = adminSettingsService.saveAdminSettings(TenantId.SYS_TENANT_ID, adminSettings);
|
||||||
try {
|
try {
|
||||||
return JacksonUtil.convertValue(savedAdminSettings.getJsonValue(), SecuritySettings.class);
|
return JacksonUtil.convertValue(savedAdminSettings.getJsonValue(), SecuritySettings.class);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -133,19 +133,9 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validateUserCredentials(TenantId tenantId, UserCredentials userCredentials, String username, String password) throws AuthenticationException {
|
public void validateUserCredentials(TenantId tenantId, UserCredentials userCredentials, String username, String password) throws AuthenticationException {
|
||||||
SecuritySettings securitySettings = self.getSecuritySettings(tenantId);
|
|
||||||
UserPasswordPolicy passwordPolicy = securitySettings.getPasswordPolicy();
|
|
||||||
|
|
||||||
if (!tenantId.isSysTenantId() && Boolean.TRUE.equals(passwordPolicy.getForceUserToResetPasswordIfNotValid())) {
|
|
||||||
try {
|
|
||||||
validatePasswordByPolicy(password, passwordPolicy);
|
|
||||||
} catch (DataValidationException e) {
|
|
||||||
throw new UserPasswordNotValidException("The entered password violates our policies. If this is your real password, please reset it.");
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!encoder.matches(password, userCredentials.getPassword())) {
|
if (!encoder.matches(password, userCredentials.getPassword())) {
|
||||||
int failedLoginAttempts = userService.increaseFailedLoginAttempts(tenantId, userCredentials.getUserId());
|
int failedLoginAttempts = userService.increaseFailedLoginAttempts(tenantId, userCredentials.getUserId());
|
||||||
|
SecuritySettings securitySettings = self.getSecuritySettings();
|
||||||
if (securitySettings.getMaxFailedLoginAttempts() != null && securitySettings.getMaxFailedLoginAttempts() > 0) {
|
if (securitySettings.getMaxFailedLoginAttempts() != null && securitySettings.getMaxFailedLoginAttempts() > 0) {
|
||||||
if (failedLoginAttempts > securitySettings.getMaxFailedLoginAttempts() && userCredentials.isEnabled()) {
|
if (failedLoginAttempts > securitySettings.getMaxFailedLoginAttempts() && userCredentials.isEnabled()) {
|
||||||
lockAccount(userCredentials.getUserId(), username, securitySettings.getUserLockoutNotificationEmail(), securitySettings.getMaxFailedLoginAttempts());
|
lockAccount(userCredentials.getUserId(), username, securitySettings.getUserLockoutNotificationEmail(), securitySettings.getMaxFailedLoginAttempts());
|
||||||
@ -161,6 +151,7 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
|
|||||||
|
|
||||||
userService.resetFailedLoginAttempts(tenantId, userCredentials.getUserId());
|
userService.resetFailedLoginAttempts(tenantId, userCredentials.getUserId());
|
||||||
|
|
||||||
|
SecuritySettings securitySettings = self.getSecuritySettings();
|
||||||
if (isPositiveInteger(securitySettings.getPasswordPolicy().getPasswordExpirationPeriodDays())) {
|
if (isPositiveInteger(securitySettings.getPasswordPolicy().getPasswordExpirationPeriodDays())) {
|
||||||
if ((userCredentials.getCreatedTime()
|
if ((userCredentials.getCreatedTime()
|
||||||
+ TimeUnit.DAYS.toMillis(securitySettings.getPasswordPolicy().getPasswordExpirationPeriodDays()))
|
+ TimeUnit.DAYS.toMillis(securitySettings.getPasswordPolicy().getPasswordExpirationPeriodDays()))
|
||||||
@ -188,7 +179,7 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
|
|||||||
if (maxVerificationFailures != null && maxVerificationFailures > 0
|
if (maxVerificationFailures != null && maxVerificationFailures > 0
|
||||||
&& failedVerificationAttempts >= maxVerificationFailures) {
|
&& failedVerificationAttempts >= maxVerificationFailures) {
|
||||||
userService.setUserCredentialsEnabled(TenantId.SYS_TENANT_ID, userId, false);
|
userService.setUserCredentialsEnabled(TenantId.SYS_TENANT_ID, userId, false);
|
||||||
SecuritySettings securitySettings = self.getSecuritySettings(tenantId);
|
SecuritySettings securitySettings = self.getSecuritySettings();
|
||||||
lockAccount(userId, securityUser.getEmail(), securitySettings.getUserLockoutNotificationEmail(), maxVerificationFailures);
|
lockAccount(userId, securityUser.getEmail(), securitySettings.getUserLockoutNotificationEmail(), maxVerificationFailures);
|
||||||
throw new LockedException("User account was locked due to exceeded 2FA verification attempts");
|
throw new LockedException("User account was locked due to exceeded 2FA verification attempts");
|
||||||
}
|
}
|
||||||
@ -206,8 +197,8 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validatePassword(TenantId tenantId, String password, UserCredentials userCredentials) throws DataValidationException {
|
public void validatePassword(String password, UserCredentials userCredentials) throws DataValidationException {
|
||||||
SecuritySettings securitySettings = self.getSecuritySettings(tenantId);
|
SecuritySettings securitySettings = self.getSecuritySettings();
|
||||||
UserPasswordPolicy passwordPolicy = securitySettings.getPasswordPolicy();
|
UserPasswordPolicy passwordPolicy = securitySettings.getPasswordPolicy();
|
||||||
|
|
||||||
validatePasswordByPolicy(password, passwordPolicy);
|
validatePasswordByPolicy(password, passwordPolicy);
|
||||||
@ -227,7 +218,8 @@ public class DefaultSystemSecurityService implements SystemSecurityService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validatePasswordByPolicy(String password, UserPasswordPolicy passwordPolicy) {
|
@Override
|
||||||
|
public void validatePasswordByPolicy(String password, UserPasswordPolicy passwordPolicy) {
|
||||||
List<Rule> passwordRules = new ArrayList<>();
|
List<Rule> passwordRules = new ArrayList<>();
|
||||||
|
|
||||||
Integer maximumLength = passwordPolicy.getMaximumLength();
|
Integer maximumLength = passwordPolicy.getMaximumLength();
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import org.thingsboard.server.common.data.id.CustomerId;
|
|||||||
import org.thingsboard.server.common.data.id.TenantId;
|
import org.thingsboard.server.common.data.id.TenantId;
|
||||||
import org.thingsboard.server.common.data.security.UserCredentials;
|
import org.thingsboard.server.common.data.security.UserCredentials;
|
||||||
import org.thingsboard.server.common.data.security.model.SecuritySettings;
|
import org.thingsboard.server.common.data.security.model.SecuritySettings;
|
||||||
|
import org.thingsboard.server.common.data.security.model.UserPasswordPolicy;
|
||||||
import org.thingsboard.server.common.data.security.model.mfa.PlatformTwoFaSettings;
|
import org.thingsboard.server.common.data.security.model.mfa.PlatformTwoFaSettings;
|
||||||
import org.thingsboard.server.dao.exception.DataValidationException;
|
import org.thingsboard.server.dao.exception.DataValidationException;
|
||||||
import org.thingsboard.server.service.security.model.SecurityUser;
|
import org.thingsboard.server.service.security.model.SecurityUser;
|
||||||
@ -30,15 +31,17 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
|
|
||||||
public interface SystemSecurityService {
|
public interface SystemSecurityService {
|
||||||
|
|
||||||
SecuritySettings getSecuritySettings(TenantId tenantId);
|
SecuritySettings getSecuritySettings();
|
||||||
|
|
||||||
SecuritySettings saveSecuritySettings(TenantId tenantId, SecuritySettings securitySettings);
|
SecuritySettings saveSecuritySettings(SecuritySettings securitySettings);
|
||||||
|
|
||||||
|
void validatePasswordByPolicy(String password, UserPasswordPolicy passwordPolicy);
|
||||||
|
|
||||||
void validateUserCredentials(TenantId tenantId, UserCredentials userCredentials, String username, String password) throws AuthenticationException;
|
void validateUserCredentials(TenantId tenantId, UserCredentials userCredentials, String username, String password) throws AuthenticationException;
|
||||||
|
|
||||||
void validateTwoFaVerification(SecurityUser securityUser, boolean verificationSuccess, PlatformTwoFaSettings twoFaSettings);
|
void validateTwoFaVerification(SecurityUser securityUser, boolean verificationSuccess, PlatformTwoFaSettings twoFaSettings);
|
||||||
|
|
||||||
void validatePassword(TenantId tenantId, String password, UserCredentials userCredentials) throws DataValidationException;
|
void validatePassword(String password, UserCredentials userCredentials) throws DataValidationException;
|
||||||
|
|
||||||
String getBaseUrl(TenantId tenantId, CustomerId customerId, HttpServletRequest httpServletRequest);
|
String getBaseUrl(TenantId tenantId, CustomerId customerId, HttpServletRequest httpServletRequest);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user