diff --git a/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/provider/impl/MobileAuthenticationProvider.java b/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/provider/impl/MobileAuthenticationProvider.java index 40a1f4b4..85d29900 100644 --- a/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/provider/impl/MobileAuthenticationProvider.java +++ b/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/provider/impl/MobileAuthenticationProvider.java @@ -97,7 +97,7 @@ public class MobileAuthenticationProvider extends AbstractAuthenticationProvider mobileCaptchaValid(loginCredential.getPassword(),userInfo); //apply PasswordSetType and resetBadPasswordCount - authenticationRealm.getPasswordPolicyValidator().applyPasswordPolicy(userInfo); + authenticationRealm.getLoginRepository().applyPasswordPolicy(userInfo); authenticationToken = createOnlineTicket(loginCredential,userInfo); // user authenticated diff --git a/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/provider/impl/NormalAuthenticationProvider.java b/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/provider/impl/NormalAuthenticationProvider.java index 0bd55e1d..110b1a97 100644 --- a/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/provider/impl/NormalAuthenticationProvider.java +++ b/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/provider/impl/NormalAuthenticationProvider.java @@ -87,7 +87,7 @@ public class NormalAuthenticationProvider extends AbstractAuthenticationProvider isUserExist(loginCredential , userInfo); //Validate PasswordPolicy - authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(userInfo); + authenticationRealm.getLoginRepository().passwordPolicyValid(userInfo); statusValid(loginCredential , userInfo); @@ -95,7 +95,7 @@ public class NormalAuthenticationProvider extends AbstractAuthenticationProvider authenticationRealm.passwordMatches(userInfo, loginCredential.getPassword()); //apply PasswordSetType and resetBadPasswordCount - authenticationRealm.getPasswordPolicyValidator().applyPasswordPolicy(userInfo); + authenticationRealm.getLoginRepository().applyPasswordPolicy(userInfo); authenticationToken = createOnlineTicket(loginCredential,userInfo); // user authenticated diff --git a/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/provider/impl/TrustedAuthenticationProvider.java b/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/provider/impl/TrustedAuthenticationProvider.java index 7a70cfe6..7916d348 100644 --- a/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/provider/impl/TrustedAuthenticationProvider.java +++ b/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/provider/impl/TrustedAuthenticationProvider.java @@ -61,9 +61,9 @@ public class TrustedAuthenticationProvider extends AbstractAuthenticationProvide statusValid(loginCredential , loadeduserInfo); if (loadeduserInfo != null) { //Validate PasswordPolicy - authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(loadeduserInfo); + authenticationRealm.getLoginRepository().passwordPolicyValid(loadeduserInfo); //apply PasswordSetType and resetBadPasswordCount - authenticationRealm.getPasswordPolicyValidator().applyPasswordPolicy(loadeduserInfo); + authenticationRealm.getLoginRepository().applyPasswordPolicy(loadeduserInfo); Authentication authentication = createOnlineTicket(loginCredential,loadeduserInfo); authenticationRealm.insertLoginHistory( loadeduserInfo, diff --git a/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/realm/AbstractAuthenticationRealm.java b/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/realm/AbstractAuthenticationRealm.java index b55a530c..2cc2ff9a 100644 --- a/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/realm/AbstractAuthenticationRealm.java +++ b/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/realm/AbstractAuthenticationRealm.java @@ -29,8 +29,8 @@ import org.dromara.maxkey.entity.idm.UserInfo; import org.dromara.maxkey.ip2location.IpLocationParser; import org.dromara.maxkey.ip2location.Region; import org.dromara.maxkey.persistence.repository.LoginRepository; -import org.dromara.maxkey.persistence.repository.PasswordPolicyValidator; import org.dromara.maxkey.persistence.service.HistoryLoginService; +import org.dromara.maxkey.persistence.service.PasswordPolicyValidatorService; import org.dromara.maxkey.persistence.service.UserInfoService; import org.dromara.maxkey.web.WebConstants; import org.dromara.maxkey.web.WebContext; @@ -50,7 +50,7 @@ public abstract class AbstractAuthenticationRealm { protected JdbcTemplate jdbcTemplate; - protected PasswordPolicyValidator passwordPolicyValidator; + protected PasswordPolicyValidatorService passwordPolicyValidatorService; protected LoginRepository loginRepository; @@ -74,8 +74,8 @@ public abstract class AbstractAuthenticationRealm { this.jdbcTemplate = jdbcTemplate; } - public PasswordPolicyValidator getPasswordPolicyValidator() { - return passwordPolicyValidator; + public PasswordPolicyValidatorService getPasswordPolicyValidatorService() { + return passwordPolicyValidatorService; } public LoginRepository getLoginRepository() { diff --git a/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/realm/jdbc/JdbcAuthenticationRealm.java b/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/realm/jdbc/JdbcAuthenticationRealm.java index 2df4a9f0..b7859cae 100644 --- a/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/realm/jdbc/JdbcAuthenticationRealm.java +++ b/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/realm/jdbc/JdbcAuthenticationRealm.java @@ -27,8 +27,8 @@ import org.dromara.maxkey.entity.cnf.CnfPasswordPolicy; import org.dromara.maxkey.entity.idm.UserInfo; import org.dromara.maxkey.ip2location.IpLocationParser; import org.dromara.maxkey.persistence.repository.LoginRepository; -import org.dromara.maxkey.persistence.repository.PasswordPolicyValidator; import org.dromara.maxkey.persistence.service.HistoryLoginService; +import org.dromara.maxkey.persistence.service.PasswordPolicyValidatorService; import org.dromara.maxkey.persistence.service.UserInfoService; import org.dromara.maxkey.web.WebConstants; import org.dromara.maxkey.web.WebContext; @@ -58,7 +58,7 @@ public class JdbcAuthenticationRealm extends AbstractAuthenticationRealm { public JdbcAuthenticationRealm( PasswordEncoder passwordEncoder, - PasswordPolicyValidator passwordPolicyValidator, + PasswordPolicyValidatorService passwordPolicyValidatorService, LoginRepository loginRepository, HistoryLoginService historyLoginService, UserInfoService userInfoService, @@ -66,7 +66,7 @@ public class JdbcAuthenticationRealm extends AbstractAuthenticationRealm { JdbcTemplate jdbcTemplate) { this.passwordEncoder =passwordEncoder; - this.passwordPolicyValidator=passwordPolicyValidator; + this.passwordPolicyValidatorService=passwordPolicyValidatorService; this.loginRepository = loginRepository; this.historyLoginService = historyLoginService; this.userInfoService = userInfoService; @@ -76,7 +76,7 @@ public class JdbcAuthenticationRealm extends AbstractAuthenticationRealm { public JdbcAuthenticationRealm( PasswordEncoder passwordEncoder, - PasswordPolicyValidator passwordPolicyValidator, + PasswordPolicyValidatorService passwordPolicyValidatorService, LoginRepository loginRepository, HistoryLoginService historyLoginService, UserInfoService userInfoService, @@ -84,7 +84,7 @@ public class JdbcAuthenticationRealm extends AbstractAuthenticationRealm { JdbcTemplate jdbcTemplate, LdapAuthenticationRealmService ldapAuthenticationRealmService) { this.passwordEncoder = passwordEncoder; - this.passwordPolicyValidator = passwordPolicyValidator; + this.passwordPolicyValidatorService = passwordPolicyValidatorService; this.loginRepository = loginRepository; this.historyLoginService = historyLoginService; this.userInfoService = userInfoService; @@ -126,9 +126,9 @@ public class JdbcAuthenticationRealm extends AbstractAuthenticationRealm { } _logger.debug("passwordvalid : {}" , passwordMatches); if (!passwordMatches) { - passwordPolicyValidator.plusBadPasswordCount(userInfo); + loginRepository.plusBadPasswordCount(userInfo); insertLoginHistory(userInfo, ConstsLoginType.LOCAL, "", "xe00000004", WebConstants.LOGIN_RESULT.PASSWORD_ERROE); - CnfPasswordPolicy passwordPolicy = passwordPolicyValidator.getPasswordPolicyRepository().getPasswordPolicy(); + CnfPasswordPolicy passwordPolicy = passwordPolicyValidatorService.getPasswordPolicy(); if(userInfo.getBadPasswordCount()>=(passwordPolicy.getAttempts()/2)) { throw new BadCredentialsException( WebContext.getI18nValue("login.error.password.attempts", diff --git a/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/autoconfigure/AuthnProviderAutoConfiguration.java b/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/autoconfigure/AuthnProviderAutoConfiguration.java index 9afdc632..e3fe381a 100644 --- a/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/autoconfigure/AuthnProviderAutoConfiguration.java +++ b/maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/autoconfigure/AuthnProviderAutoConfiguration.java @@ -26,7 +26,10 @@ import org.dromara.maxkey.authn.session.SessionManager; import org.dromara.maxkey.configuration.ApplicationConfig; import org.dromara.maxkey.password.sms.SmsOtpAuthnService; import org.dromara.maxkey.persistence.repository.LoginRepository; -import org.dromara.maxkey.persistence.repository.PasswordPolicyValidator; +import org.dromara.maxkey.persistence.service.CnfPasswordPolicyService; +import org.dromara.maxkey.persistence.service.PasswordPolicyValidatorService; +import org.dromara.maxkey.persistence.service.UserInfoService; +import org.dromara.maxkey.persistence.service.impl.PasswordPolicyValidatorServiceImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.boot.autoconfigure.AutoConfiguration; @@ -99,13 +102,15 @@ public class AuthnProviderAutoConfiguration { } @Bean - PasswordPolicyValidator passwordPolicyValidator(JdbcTemplate jdbcTemplate,MessageSource messageSource) { - return new PasswordPolicyValidator(jdbcTemplate,messageSource); + PasswordPolicyValidatorService passwordPolicyValidatorService( + CnfPasswordPolicyService cnfPasswordPolicyService, + MessageSource messageSource) { + return new PasswordPolicyValidatorServiceImpl(cnfPasswordPolicyService,messageSource); } @Bean - LoginRepository loginRepository(JdbcTemplate jdbcTemplate) { - return new LoginRepository(jdbcTemplate); + LoginRepository loginRepository(UserInfoService userInfoService,CnfPasswordPolicyService cnfPasswordPolicyService,JdbcTemplate jdbcTemplate) { + return new LoginRepository(userInfoService,cnfPasswordPolicyService,jdbcTemplate); } } diff --git a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/AppAuthenticationProvider.java b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/AppAuthenticationProvider.java index 922def88..0347b6af 100644 --- a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/AppAuthenticationProvider.java +++ b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/AppAuthenticationProvider.java @@ -84,7 +84,7 @@ public class AppAuthenticationProvider extends AbstractAuthenticationProvider { UserInfo userInfo = loadUserInfo(loginCredential.getUsername(), loginCredential.getPassword()); //Validate PasswordPolicy - authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(userInfo); + authenticationRealm.getLoginRepository().passwordPolicyValid(userInfo); statusValid(loginCredential, userInfo); @@ -92,7 +92,7 @@ public class AppAuthenticationProvider extends AbstractAuthenticationProvider { authenticationRealm.passwordMatches(userInfo, loginCredential.getPassword()); //apply PasswordSetType and resetBadPasswordCount - authenticationRealm.getPasswordPolicyValidator().applyPasswordPolicy(userInfo); + authenticationRealm.getLoginRepository().applyPasswordPolicy(userInfo); authenticationToken = createOnlineTicket(loginCredential, userInfo); // user authenticated diff --git a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/MfaAuthenticationProvider.java b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/MfaAuthenticationProvider.java index 4fae8715..0f25ec0e 100644 --- a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/MfaAuthenticationProvider.java +++ b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/MfaAuthenticationProvider.java @@ -89,13 +89,13 @@ public class MfaAuthenticationProvider extends AbstractAuthenticationProvider { mfacaptchaValid(loginCredential.getOtpCaptcha(),userInfo); //Validate PasswordPolicy - authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(userInfo); + authenticationRealm.getLoginRepository().passwordPolicyValid(userInfo); //Match password authenticationRealm.passwordMatches(userInfo, loginCredential.getPassword()); //apply PasswordSetType and resetBadPasswordCount - authenticationRealm.getPasswordPolicyValidator().applyPasswordPolicy(userInfo); + authenticationRealm.getLoginRepository().applyPasswordPolicy(userInfo); authenticationToken = createOnlineTicket(loginCredential,userInfo); // user authenticated diff --git a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/MobileAuthenticationProvider.java b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/MobileAuthenticationProvider.java index 40a1f4b4..85d29900 100644 --- a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/MobileAuthenticationProvider.java +++ b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/MobileAuthenticationProvider.java @@ -97,7 +97,7 @@ public class MobileAuthenticationProvider extends AbstractAuthenticationProvider mobileCaptchaValid(loginCredential.getPassword(),userInfo); //apply PasswordSetType and resetBadPasswordCount - authenticationRealm.getPasswordPolicyValidator().applyPasswordPolicy(userInfo); + authenticationRealm.getLoginRepository().applyPasswordPolicy(userInfo); authenticationToken = createOnlineTicket(loginCredential,userInfo); // user authenticated diff --git a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/NormalAuthenticationProvider.java b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/NormalAuthenticationProvider.java index 0bd55e1d..110b1a97 100644 --- a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/NormalAuthenticationProvider.java +++ b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/NormalAuthenticationProvider.java @@ -87,7 +87,7 @@ public class NormalAuthenticationProvider extends AbstractAuthenticationProvider isUserExist(loginCredential , userInfo); //Validate PasswordPolicy - authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(userInfo); + authenticationRealm.getLoginRepository().passwordPolicyValid(userInfo); statusValid(loginCredential , userInfo); @@ -95,7 +95,7 @@ public class NormalAuthenticationProvider extends AbstractAuthenticationProvider authenticationRealm.passwordMatches(userInfo, loginCredential.getPassword()); //apply PasswordSetType and resetBadPasswordCount - authenticationRealm.getPasswordPolicyValidator().applyPasswordPolicy(userInfo); + authenticationRealm.getLoginRepository().applyPasswordPolicy(userInfo); authenticationToken = createOnlineTicket(loginCredential,userInfo); // user authenticated diff --git a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/TrustedAuthenticationProvider.java b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/TrustedAuthenticationProvider.java index 7a70cfe6..7916d348 100644 --- a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/TrustedAuthenticationProvider.java +++ b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/TrustedAuthenticationProvider.java @@ -61,9 +61,9 @@ public class TrustedAuthenticationProvider extends AbstractAuthenticationProvide statusValid(loginCredential , loadeduserInfo); if (loadeduserInfo != null) { //Validate PasswordPolicy - authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(loadeduserInfo); + authenticationRealm.getLoginRepository().passwordPolicyValid(loadeduserInfo); //apply PasswordSetType and resetBadPasswordCount - authenticationRealm.getPasswordPolicyValidator().applyPasswordPolicy(loadeduserInfo); + authenticationRealm.getLoginRepository().applyPasswordPolicy(loadeduserInfo); Authentication authentication = createOnlineTicket(loginCredential,loadeduserInfo); authenticationRealm.insertLoginHistory( loadeduserInfo, diff --git a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/realm/AbstractAuthenticationRealm.java b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/realm/AbstractAuthenticationRealm.java index 45990159..90327ed9 100644 --- a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/realm/AbstractAuthenticationRealm.java +++ b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/realm/AbstractAuthenticationRealm.java @@ -29,8 +29,8 @@ import org.dromara.maxkey.entity.idm.UserInfo; import org.dromara.maxkey.ip2location.IpLocationParser; import org.dromara.maxkey.ip2location.Region; import org.dromara.maxkey.persistence.repository.LoginRepository; -import org.dromara.maxkey.persistence.repository.PasswordPolicyValidator; import org.dromara.maxkey.persistence.service.HistoryLoginService; +import org.dromara.maxkey.persistence.service.PasswordPolicyValidatorService; import org.dromara.maxkey.persistence.service.UserInfoService; import org.dromara.maxkey.web.WebConstants; import org.dromara.maxkey.web.WebContext; @@ -50,7 +50,7 @@ public abstract class AbstractAuthenticationRealm { protected JdbcTemplate jdbcTemplate; - protected PasswordPolicyValidator passwordPolicyValidator; + protected PasswordPolicyValidatorService passwordPolicyValidatorService; protected LoginRepository loginRepository; @@ -74,8 +74,8 @@ public abstract class AbstractAuthenticationRealm { this.jdbcTemplate = jdbcTemplate; } - public PasswordPolicyValidator getPasswordPolicyValidator() { - return passwordPolicyValidator; + public PasswordPolicyValidatorService getPasswordPolicyValidatorService() { + return passwordPolicyValidatorService; } public LoginRepository getLoginRepository() { diff --git a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/realm/jdbc/JdbcAuthenticationRealm.java b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/realm/jdbc/JdbcAuthenticationRealm.java index 2df4a9f0..b7859cae 100644 --- a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/realm/jdbc/JdbcAuthenticationRealm.java +++ b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/realm/jdbc/JdbcAuthenticationRealm.java @@ -27,8 +27,8 @@ import org.dromara.maxkey.entity.cnf.CnfPasswordPolicy; import org.dromara.maxkey.entity.idm.UserInfo; import org.dromara.maxkey.ip2location.IpLocationParser; import org.dromara.maxkey.persistence.repository.LoginRepository; -import org.dromara.maxkey.persistence.repository.PasswordPolicyValidator; import org.dromara.maxkey.persistence.service.HistoryLoginService; +import org.dromara.maxkey.persistence.service.PasswordPolicyValidatorService; import org.dromara.maxkey.persistence.service.UserInfoService; import org.dromara.maxkey.web.WebConstants; import org.dromara.maxkey.web.WebContext; @@ -58,7 +58,7 @@ public class JdbcAuthenticationRealm extends AbstractAuthenticationRealm { public JdbcAuthenticationRealm( PasswordEncoder passwordEncoder, - PasswordPolicyValidator passwordPolicyValidator, + PasswordPolicyValidatorService passwordPolicyValidatorService, LoginRepository loginRepository, HistoryLoginService historyLoginService, UserInfoService userInfoService, @@ -66,7 +66,7 @@ public class JdbcAuthenticationRealm extends AbstractAuthenticationRealm { JdbcTemplate jdbcTemplate) { this.passwordEncoder =passwordEncoder; - this.passwordPolicyValidator=passwordPolicyValidator; + this.passwordPolicyValidatorService=passwordPolicyValidatorService; this.loginRepository = loginRepository; this.historyLoginService = historyLoginService; this.userInfoService = userInfoService; @@ -76,7 +76,7 @@ public class JdbcAuthenticationRealm extends AbstractAuthenticationRealm { public JdbcAuthenticationRealm( PasswordEncoder passwordEncoder, - PasswordPolicyValidator passwordPolicyValidator, + PasswordPolicyValidatorService passwordPolicyValidatorService, LoginRepository loginRepository, HistoryLoginService historyLoginService, UserInfoService userInfoService, @@ -84,7 +84,7 @@ public class JdbcAuthenticationRealm extends AbstractAuthenticationRealm { JdbcTemplate jdbcTemplate, LdapAuthenticationRealmService ldapAuthenticationRealmService) { this.passwordEncoder = passwordEncoder; - this.passwordPolicyValidator = passwordPolicyValidator; + this.passwordPolicyValidatorService = passwordPolicyValidatorService; this.loginRepository = loginRepository; this.historyLoginService = historyLoginService; this.userInfoService = userInfoService; @@ -126,9 +126,9 @@ public class JdbcAuthenticationRealm extends AbstractAuthenticationRealm { } _logger.debug("passwordvalid : {}" , passwordMatches); if (!passwordMatches) { - passwordPolicyValidator.plusBadPasswordCount(userInfo); + loginRepository.plusBadPasswordCount(userInfo); insertLoginHistory(userInfo, ConstsLoginType.LOCAL, "", "xe00000004", WebConstants.LOGIN_RESULT.PASSWORD_ERROE); - CnfPasswordPolicy passwordPolicy = passwordPolicyValidator.getPasswordPolicyRepository().getPasswordPolicy(); + CnfPasswordPolicy passwordPolicy = passwordPolicyValidatorService.getPasswordPolicy(); if(userInfo.getBadPasswordCount()>=(passwordPolicy.getAttempts()/2)) { throw new BadCredentialsException( WebContext.getI18nValue("login.error.password.attempts", diff --git a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/autoconfigure/AuthnProviderAutoConfiguration.java b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/autoconfigure/AuthnProviderAutoConfiguration.java index 6d03c42a..7770b7b3 100644 --- a/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/autoconfigure/AuthnProviderAutoConfiguration.java +++ b/maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/autoconfigure/AuthnProviderAutoConfiguration.java @@ -28,7 +28,10 @@ import org.dromara.maxkey.authn.support.rememberme.JdbcRemeberMeManager; import org.dromara.maxkey.configuration.ApplicationConfig; import org.dromara.maxkey.password.sms.SmsOtpAuthnService; import org.dromara.maxkey.persistence.repository.LoginRepository; -import org.dromara.maxkey.persistence.repository.PasswordPolicyValidator; +import org.dromara.maxkey.persistence.service.CnfPasswordPolicyService; +import org.dromara.maxkey.persistence.service.PasswordPolicyValidatorService; +import org.dromara.maxkey.persistence.service.UserInfoService; +import org.dromara.maxkey.persistence.service.impl.PasswordPolicyValidatorServiceImpl; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; @@ -133,13 +136,15 @@ public class AuthnProviderAutoConfiguration { } @Bean - PasswordPolicyValidator passwordPolicyValidator(JdbcTemplate jdbcTemplate,MessageSource messageSource) { - return new PasswordPolicyValidator(jdbcTemplate,messageSource); + PasswordPolicyValidatorService passwordPolicyValidatorService( + CnfPasswordPolicyService cnfPasswordPolicyService, + MessageSource messageSource) { + return new PasswordPolicyValidatorServiceImpl(cnfPasswordPolicyService,messageSource); } @Bean - LoginRepository loginRepository(JdbcTemplate jdbcTemplate) { - return new LoginRepository(jdbcTemplate); + LoginRepository loginRepository(UserInfoService userInfoService,CnfPasswordPolicyService cnfPasswordPolicyService,JdbcTemplate jdbcTemplate) { + return new LoginRepository(userInfoService,cnfPasswordPolicyService,jdbcTemplate); } /** diff --git a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/mapper/UserInfoMapper.java b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/mapper/UserInfoMapper.java index a1a5f6f7..6fbef06d 100644 --- a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/mapper/UserInfoMapper.java +++ b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/mapper/UserInfoMapper.java @@ -49,7 +49,9 @@ public interface UserInfoMapper extends IJpaMapper{ public void updateLockout(UserInfo userInfo); - public void updateBadPWDCount(UserInfo userInfo); + public void badPasswordCount(UserInfo userInfo); + + public void badPasswordCountReset(UserInfo userInfo); public int changePassword(ChangePassword changePassword); diff --git a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/LoginRepository.java b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/LoginRepository.java index 3194d319..52484395 100644 --- a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/LoginRepository.java +++ b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/LoginRepository.java @@ -26,33 +26,32 @@ import java.util.List; import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import org.dromara.maxkey.constants.ConstsPasswordSetType; import org.dromara.maxkey.constants.ConstsRoles; import org.dromara.maxkey.constants.ConstsStatus; +import org.dromara.maxkey.entity.cnf.CnfPasswordPolicy; import org.dromara.maxkey.entity.idm.Groups; import org.dromara.maxkey.entity.idm.UserInfo; +import org.dromara.maxkey.persistence.service.CnfPasswordPolicyService; +import org.dromara.maxkey.persistence.service.UserInfoService; +import org.dromara.maxkey.web.WebConstants; +import org.dromara.maxkey.web.WebContext; +import org.joda.time.DateTime; +import org.joda.time.Duration; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.jdbc.core.RowMapper; +import org.springframework.security.authentication.BadCredentialsException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; public class LoginRepository { private static final Logger _logger = LoggerFactory.getLogger(LoginRepository.class); - private static final String LOCK_USER_UPDATE_STATEMENT = "update mxk_userinfo set islocked = ? , unlocktime = ? where id = ?"; - - private static final String UNLOCK_USER_UPDATE_STATEMENT = "update mxk_userinfo set islocked = ? , unlocktime = ? where id = ?"; - - private static final String BADPASSWORDCOUNT_UPDATE_STATEMENT = "update mxk_userinfo set badpasswordcount = ? , badpasswordtime = ? where id = ?"; - - private static final String BADPASSWORDCOUNT_RESET_UPDATE_STATEMENT = "update mxk_userinfo set badpasswordcount = ? , islocked = ? ,unlocktime = ? where id = ?"; - private static final String LOGIN_USERINFO_UPDATE_STATEMENT = "update mxk_userinfo set lastlogintime = ? , lastloginip = ? , logincount = ?, online = " + UserInfo.ONLINE.ONLINE + " where id = ?"; - - private static final String GROUPS_SELECT_STATEMENT = "select distinct g.id,g.groupcode,g.groupname from mxk_userinfo u,mxk_groups g,mxk_group_member gm where u.id = ? and u.id=gm.memberid and gm.groupid=g.id "; private static final String DEFAULT_USERINFO_SELECT_STATEMENT = "select * from mxk_userinfo where username = ? "; @@ -64,6 +63,10 @@ public class LoginRepository { private static final String DEFAULT_MYAPPS_SELECT_STATEMENT = "select distinct app.id,app.appname from mxk_apps app,mxk_access gp,mxk_groups g where app.id=gp.appid and app.status = 1 and gp.groupid=g.id and g.id in(%s)"; protected JdbcTemplate jdbcTemplate; + + UserInfoService userInfoService; + + CnfPasswordPolicyService cnfPasswordPolicyService; /** * 1 (USERNAME) 2 (USERNAME | MOBILE) 3 (USERNAME | MOBILE | EMAIL) @@ -74,8 +77,10 @@ public class LoginRepository { } - public LoginRepository(JdbcTemplate jdbcTemplate){ + public LoginRepository(UserInfoService userInfoService,CnfPasswordPolicyService cnfPasswordPolicyService,JdbcTemplate jdbcTemplate){ this.jdbcTemplate=jdbcTemplate; + this.userInfoService = userInfoService; + this.cnfPasswordPolicyService = cnfPasswordPolicyService; } public UserInfo find(String username, String password) { @@ -116,36 +121,135 @@ public class LoginRepository { } + /** - * 閿佸畾鐢ㄦ埛锛歩slock锛�1 鐢ㄦ埛瑙i攣 2 鐢ㄦ埛閿佸畾 - * + * dynamic passwordPolicy Valid for user login. + * @param userInfo + * @return boolean + */ + public boolean passwordPolicyValid(UserInfo userInfo) { + + CnfPasswordPolicy passwordPolicy = cnfPasswordPolicyService.getPasswordPolicy(); + + DateTime currentdateTime = new DateTime(); + /* + * check login attempts fail times + */ + if (userInfo.getBadPasswordCount() >= passwordPolicy.getAttempts() && userInfo.getBadPasswordTime() != null) { + _logger.debug("login Attempts is {} , bad Password Time {}" , userInfo.getBadPasswordCount(),userInfo.getBadPasswordTime()); + + Duration duration = new Duration(new DateTime(userInfo.getBadPasswordTime()), currentdateTime); + int intDuration = Integer.parseInt(duration.getStandardMinutes() + ""); + _logger.debug("bad Password duration {} , " + + "password policy Duration {} , "+ + "validate result {}" , + intDuration, + passwordPolicy.getDuration(), + (intDuration > passwordPolicy.getDuration()) + ); + //auto unlock attempts when intDuration >= set Duration + if(intDuration >= passwordPolicy.getDuration()) { + _logger.debug("resetAttempts ..."); + resetAttempts(userInfo); + }else { + lockUser(userInfo); + throw new BadCredentialsException( + WebContext.getI18nValue("login.error.attempts", + new Object[]{userInfo.getBadPasswordCount(),passwordPolicy.getDuration()}) + ); + } + } + + //locked + if(userInfo.getIsLocked()==ConstsStatus.LOCK) { + throw new BadCredentialsException( + userInfo.getUsername()+ " "+ + WebContext.getI18nValue("login.error.locked") + ); + } + // inactive + if(userInfo.getStatus()!=ConstsStatus.ACTIVE) { + throw new BadCredentialsException( + userInfo.getUsername()+ + WebContext.getI18nValue("login.error.inactive") + ); + } + + return true; + } + + public void applyPasswordPolicy(UserInfo userInfo) { + CnfPasswordPolicy passwordPolicy = cnfPasswordPolicyService.getPasswordPolicy(); + + DateTime currentdateTime = new DateTime(); + //initial password need change + if(userInfo.getLoginCount()<=0) { + WebContext.getSession().setAttribute(WebConstants.CURRENT_USER_PASSWORD_SET_TYPE, + ConstsPasswordSetType.INITIAL_PASSWORD); + } + + if (userInfo.getPasswordSetType() != ConstsPasswordSetType.PASSWORD_NORMAL) { + WebContext.getSession().setAttribute(WebConstants.CURRENT_USER_PASSWORD_SET_TYPE, + userInfo.getPasswordSetType()); + return; + } else { + WebContext.getSession().setAttribute(WebConstants.CURRENT_USER_PASSWORD_SET_TYPE, + ConstsPasswordSetType.PASSWORD_NORMAL); + } + + /* + * check password is Expired,Expiration is Expired date ,if Expiration equals 0,not need check + * + */ + if (passwordPolicy.getExpiration() > 0 && userInfo.getPasswordLastSetTime() != null) { + _logger.info("last password set date {}" , userInfo.getPasswordLastSetTime()); + Duration duration = new Duration(new DateTime(userInfo.getPasswordLastSetTime()), currentdateTime); + int intDuration = Integer.parseInt(duration.getStandardDays() + ""); + _logger.debug("password Last Set duration day {} , " + + "password policy Expiration {} , " + + "validate result {}", + intDuration, + passwordPolicy.getExpiration(), + intDuration <= passwordPolicy.getExpiration() + ); + if (intDuration > passwordPolicy.getExpiration()) { + WebContext.getSession().setAttribute(WebConstants.CURRENT_USER_PASSWORD_SET_TYPE, + ConstsPasswordSetType.PASSWORD_EXPIRED); + } + } + + resetBadPasswordCount(userInfo); + } + + /** + * lockUser + * * @param userInfo */ - public void updateLock(UserInfo userInfo) { + public void lockUser(UserInfo userInfo) { try { - if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) { - jdbcTemplate.update(LOCK_USER_UPDATE_STATEMENT, - new Object[] { ConstsStatus.LOCK, new Date(), userInfo.getId() }, - new int[] { Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR }); + if (userInfo != null + && StringUtils.isNotEmpty(userInfo.getId()) + && userInfo.getIsLocked() == ConstsStatus.ACTIVE) { userInfo.setIsLocked(ConstsStatus.LOCK); + userInfoService.locked(userInfo); } } catch (Exception e) { _logger.error("lockUser Exception",e); } } + /** - * 閿佸畾鐢ㄦ埛锛歩slock锛�1 鐢ㄦ埛瑙i攣 2 鐢ㄦ埛閿佸畾 - * + * unlockUser + * * @param userInfo */ - public void updateUnlock(UserInfo userInfo) { + public void unlockUser(UserInfo userInfo) { try { if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) { - jdbcTemplate.update(UNLOCK_USER_UPDATE_STATEMENT, - new Object[] { ConstsStatus.ACTIVE, new Date(), userInfo.getId() }, - new int[] { Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR }); userInfo.setIsLocked(ConstsStatus.ACTIVE); + userInfoService.lockout(userInfo); } } catch (Exception e) { _logger.error("unlockUser Exception",e); @@ -154,39 +258,52 @@ public class LoginRepository { /** * reset BadPasswordCount And Lockout - * + * * @param userInfo */ - public void updateLockout(UserInfo userInfo) { + public void resetAttempts(UserInfo userInfo) { try { if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) { - jdbcTemplate.update(BADPASSWORDCOUNT_RESET_UPDATE_STATEMENT, - new Object[] { 0, ConstsStatus.ACTIVE, new Date(), userInfo.getId() }, - new int[] { Types.INTEGER, Types.INTEGER, Types.TIMESTAMP, Types.VARCHAR }); userInfo.setIsLocked(ConstsStatus.ACTIVE); + userInfo.setBadPasswordCount(0); + userInfoService.badPasswordCountReset(userInfo); } } catch (Exception e) { - _logger.error("resetBadPasswordCountAndLockout Exception",e); + _logger.error("resetAttempts Exception",e); } } /** * if login password is error ,BadPasswordCount++ and set bad date - * + * * @param userInfo */ - public void updateBadPasswordCount(UserInfo userInfo) { + private void setBadPasswordCount(String userId,int badPasswordCount) { try { - if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) { - int badPasswordCount = userInfo.getBadPasswordCount() + 1; - userInfo.setBadPasswordCount(badPasswordCount); - jdbcTemplate.update(BADPASSWORDCOUNT_UPDATE_STATEMENT, - new Object[] { badPasswordCount, new Date(), userInfo.getId() }, - new int[] { Types.INTEGER, Types.TIMESTAMP, Types.VARCHAR }); - } + UserInfo user = new UserInfo(); + user.setId(userId); + user.setBadPasswordCount(badPasswordCount); + userInfoService.badPasswordCount(user); } catch (Exception e) { - e.printStackTrace(); - _logger.error(e.getMessage()); + _logger.error("setBadPasswordCount Exception",e); + } + } + + public void plusBadPasswordCount(UserInfo userInfo) { + if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) { + setBadPasswordCount(userInfo.getId(),userInfo.getBadPasswordCount()); + CnfPasswordPolicy passwordPolicy = cnfPasswordPolicyService.getPasswordPolicy(); + if(userInfo.getBadPasswordCount() >= passwordPolicy.getAttempts()) { + _logger.debug("Bad Password Count {} , Max Attempts {}", + userInfo.getBadPasswordCount() + 1,passwordPolicy.getAttempts()); + this.lockUser(userInfo); + } + } + } + + public void resetBadPasswordCount(UserInfo userInfo) { + if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId()) && userInfo.getBadPasswordCount()>0) { + setBadPasswordCount(userInfo.getId(),0); } } diff --git a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/PasswordPolicyMessageResolver.java b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/PasswordPolicyMessageResolver.java deleted file mode 100644 index d464b635..00000000 --- a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/PasswordPolicyMessageResolver.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] - * - * 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.dromara.maxkey.persistence.repository; - -import java.util.Locale; - -import org.passay.MessageResolver; -import org.passay.PropertiesMessageResolver; -import org.passay.RuleResultDetail; -import org.springframework.context.MessageSource; -import org.springframework.context.NoSuchMessageException; -import org.springframework.context.support.MessageSourceAccessor; - - -public class PasswordPolicyMessageResolver implements MessageResolver{ - - /** A accessor for Spring's {@link MessageSource} */ - private final MessageSourceAccessor messageSourceAccessor; - - /** The {@link MessageResolver} for fallback */ - private final MessageResolver fallbackMessageResolver = new PropertiesMessageResolver(); - - /** - * Create a new instance with the locale associated with the current thread. - * @param messageSource a message source managed by spring - */ - public PasswordPolicyMessageResolver(final MessageSource messageSource) - { - this.messageSourceAccessor = new MessageSourceAccessor(messageSource); - } - - /** - * Create a new instance with the specified locale. - * @param messageSource a message source managed by spring - * @param locale the locale to use for message access - */ - public PasswordPolicyMessageResolver(final MessageSource messageSource, final Locale locale) - { - this.messageSourceAccessor = new MessageSourceAccessor(messageSource, locale); - } - - /** - * Resolves the message for the supplied rule result detail using Spring's {@link MessageSource}. - * (If the message can't retrieve from a {@link MessageSource}, return default message provided by passay) - * @param detail rule result detail - * @return message for the detail error code - */ - @Override - public String resolve(final RuleResultDetail detail) - { - try { - return this.messageSourceAccessor.getMessage("PasswordPolicy."+detail.getErrorCode(), detail.getValues()); - } catch (NoSuchMessageException e) { - return this.fallbackMessageResolver.resolve(detail); - } - } -} diff --git a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/PasswordPolicyRepository.java b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/PasswordPolicyRepository.java deleted file mode 100644 index 1bdcb950..00000000 --- a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/PasswordPolicyRepository.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright [2022] [MaxKey of copyright http://www.maxkey.top] - * - * 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.dromara.maxkey.persistence.repository; - -import java.io.InputStreamReader; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; - -import org.dromara.maxkey.constants.ConstsProperties; -import org.dromara.maxkey.entity.cnf.CnfPasswordPolicy; -import org.passay.CharacterOccurrencesRule; -import org.passay.CharacterRule; -import org.passay.DictionaryRule; -import org.passay.EnglishCharacterData; -import org.passay.EnglishSequenceData; -import org.passay.IllegalSequenceRule; -import org.passay.LengthRule; -import org.passay.Rule; -import org.passay.UsernameRule; -import org.passay.WhitespaceRule; -import org.passay.dictionary.Dictionary; -import org.passay.dictionary.DictionaryBuilder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.core.io.ClassPathResource; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; -import com.github.benmanes.caffeine.cache.Cache; -import com.github.benmanes.caffeine.cache.Caffeine; - -public class PasswordPolicyRepository { - static final Logger _logger = LoggerFactory.getLogger(PasswordPolicyRepository.class); - - //Dictionary topWeakPassword Source - public static final String TOPWEAKPASSWORD_PROPERTYSOURCE = "classpath:/top_weak_password.txt"; - - //Cache PasswordPolicy in memory ONE_HOUR - protected static final Cache passwordPolicyStore = - Caffeine.newBuilder() - .expireAfterWrite(60, TimeUnit.MINUTES) - .build(); - - protected CnfPasswordPolicy passwordPolicy; - - protected JdbcTemplate jdbcTemplate; - - ArrayList passwordPolicyRuleList; - - private static final String PASSWORD_POLICY_KEY = "PASSWORD_POLICY_KEY"; - - private static final String PASSWORD_POLICY_SELECT_STATEMENT = "select * from mxk_cnf_password_policy "; - - public PasswordPolicyRepository(JdbcTemplate jdbcTemplate) { - this.jdbcTemplate = jdbcTemplate; - } - - /** - * init PasswordPolicy and load Rules - * @return - */ - public CnfPasswordPolicy getPasswordPolicy() { - passwordPolicy = passwordPolicyStore.getIfPresent(PASSWORD_POLICY_KEY); - - if (passwordPolicy == null) { - passwordPolicy = jdbcTemplate.queryForObject(PASSWORD_POLICY_SELECT_STATEMENT, - new PasswordPolicyRowMapper()); - _logger.debug("query PasswordPolicy : {}" , passwordPolicy); - passwordPolicyStore.put(PASSWORD_POLICY_KEY,passwordPolicy); - - //RandomPasswordLength =(MaxLength +MinLength)/2 - passwordPolicy.setRandomPasswordLength( - Math.round( - ( - passwordPolicy.getMaxLength() + - passwordPolicy.getMinLength() - )/2 - ) - ); - - passwordPolicyRuleList = new ArrayList<>(); - passwordPolicyRuleList.add(new WhitespaceRule()); - passwordPolicyRuleList.add(new LengthRule(passwordPolicy.getMinLength(), passwordPolicy.getMaxLength())); - - if(passwordPolicy.getUpperCase()>0) { - passwordPolicyRuleList.add(new CharacterRule(EnglishCharacterData.UpperCase, passwordPolicy.getUpperCase())); - } - - if(passwordPolicy.getLowerCase()>0) { - passwordPolicyRuleList.add(new CharacterRule(EnglishCharacterData.LowerCase, passwordPolicy.getLowerCase())); - } - - if(passwordPolicy.getDigits()>0) { - passwordPolicyRuleList.add(new CharacterRule(EnglishCharacterData.Digit, passwordPolicy.getDigits())); - } - - if(passwordPolicy.getSpecialChar()>0) { - passwordPolicyRuleList.add(new CharacterRule(EnglishCharacterData.Special, passwordPolicy.getSpecialChar())); - } - - if(passwordPolicy.getUsername()>0) { - passwordPolicyRuleList.add(new UsernameRule()); - } - - if(passwordPolicy.getOccurances()>0) { - passwordPolicyRuleList.add(new CharacterOccurrencesRule(passwordPolicy.getOccurances())); - } - - if(passwordPolicy.getAlphabetical()>0) { - passwordPolicyRuleList.add(new IllegalSequenceRule(EnglishSequenceData.Alphabetical, 4, false)); - } - - if(passwordPolicy.getNumerical()>0) { - passwordPolicyRuleList.add(new IllegalSequenceRule(EnglishSequenceData.Numerical, 4, false)); - } - - if(passwordPolicy.getQwerty()>0) { - passwordPolicyRuleList.add(new IllegalSequenceRule(EnglishSequenceData.USQwerty, 4, false)); - } - - if(passwordPolicy.getDictionary()>0 ) { - try { - ClassPathResource dictFile= - new ClassPathResource( - ConstsProperties.classPathResource(TOPWEAKPASSWORD_PROPERTYSOURCE)); - Dictionary dictionary =new DictionaryBuilder().addReader(new InputStreamReader(dictFile.getInputStream())).build(); - passwordPolicyRuleList.add(new DictionaryRule(dictionary)); - }catch(Exception e) { - e.printStackTrace(); - } - } - } - return passwordPolicy; - } - - - public List getPasswordPolicyRuleList() { - getPasswordPolicy(); - return passwordPolicyRuleList; - } - - -public class PasswordPolicyRowMapper implements RowMapper { - - @Override - public CnfPasswordPolicy mapRow(ResultSet rs, int rowNum) throws SQLException { - CnfPasswordPolicy newPasswordPolicy = new CnfPasswordPolicy(); - newPasswordPolicy.setId(rs.getString("id")); - newPasswordPolicy.setMinLength(rs.getInt("minlength")); - newPasswordPolicy.setMaxLength(rs.getInt("maxlength")); - newPasswordPolicy.setLowerCase(rs.getInt("lowercase")); - newPasswordPolicy.setUpperCase(rs.getInt("uppercase")); - newPasswordPolicy.setDigits(rs.getInt("digits")); - newPasswordPolicy.setSpecialChar(rs.getInt("specialchar")); - newPasswordPolicy.setAttempts(rs.getInt("attempts")); - newPasswordPolicy.setDuration(rs.getInt("duration")); - newPasswordPolicy.setExpiration(rs.getInt("expiration")); - newPasswordPolicy.setUsername(rs.getInt("username")); - newPasswordPolicy.setHistory(rs.getInt("history")); - newPasswordPolicy.setDictionary(rs.getInt("dictionary")); - newPasswordPolicy.setAlphabetical(rs.getInt("alphabetical")); - newPasswordPolicy.setNumerical(rs.getInt("numerical")); - newPasswordPolicy.setQwerty(rs.getInt("qwerty")); - newPasswordPolicy.setOccurances(rs.getInt("occurances")); - return newPasswordPolicy; - } - - } -} diff --git a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/PasswordPolicyValidator.java b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/PasswordPolicyValidator.java deleted file mode 100644 index 2da9f422..00000000 --- a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/PasswordPolicyValidator.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] - * - * 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.dromara.maxkey.persistence.repository; - -import java.sql.Types; -import java.util.Date; - -import org.apache.commons.lang3.StringUtils; -import org.dromara.maxkey.constants.ConstsPasswordSetType; -import org.dromara.maxkey.constants.ConstsStatus; -import org.dromara.maxkey.crypto.password.PasswordGen; -import org.dromara.maxkey.entity.ChangePassword; -import org.dromara.maxkey.entity.cnf.CnfPasswordPolicy; -import org.dromara.maxkey.entity.idm.UserInfo; -import org.dromara.maxkey.web.WebConstants; -import org.dromara.maxkey.web.WebContext; -import org.joda.time.DateTime; -import org.joda.time.Duration; -import org.passay.PasswordData; -import org.passay.PasswordValidator; -import org.passay.RuleResult; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.context.MessageSource; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.security.authentication.BadCredentialsException; - -public class PasswordPolicyValidator { - static final Logger _logger = LoggerFactory.getLogger(PasswordPolicyValidator.class); - - PasswordPolicyRepository passwordPolicyRepository; - - protected JdbcTemplate jdbcTemplate; - - MessageSource messageSource; - - public static final String PASSWORD_POLICY_VALIDATE_RESULT = "PASSWORD_POLICY_SESSION_VALIDATE_RESULT_KEY"; - - private static final String LOCK_USER_UPDATE_STATEMENT = "update mxk_userinfo set islocked = ? , unlocktime = ? where id = ?"; - - private static final String UNLOCK_USER_UPDATE_STATEMENT = "update mxk_userinfo set islocked = ? , unlocktime = ? where id = ?"; - - private static final String BADPASSWORDCOUNT_UPDATE_STATEMENT = "update mxk_userinfo set badpasswordcount = ? , badpasswordtime = ? where id = ?"; - - private static final String BADPASSWORDCOUNT_RESET_UPDATE_STATEMENT = "update mxk_userinfo set badpasswordcount = ? , islocked = ? ,unlocktime = ? where id = ?"; - - public PasswordPolicyValidator() { - } - - public PasswordPolicyValidator(JdbcTemplate jdbcTemplate,MessageSource messageSource) { - this.messageSource=messageSource; - this.jdbcTemplate = jdbcTemplate; - this.passwordPolicyRepository = new PasswordPolicyRepository(jdbcTemplate); - - } - - /** - * static validator . - * @param userInfo - * @return boolean - */ - public boolean validator(ChangePassword changePassword) { - - - String password = changePassword.getPassword(); - String username = changePassword.getUsername(); - - if(StringUtils.isBlank(username)){ - _logger.debug("username is Empty "); - return false; - } - - if(StringUtils.isBlank(password)){ - _logger.debug("password is Empty "); - return false; - } - - PasswordValidator validator = new PasswordValidator( - new PasswordPolicyMessageResolver(messageSource),passwordPolicyRepository.getPasswordPolicyRuleList()); - - RuleResult result = validator.validate(new PasswordData(username,password)); - - if (result.isValid()) { - _logger.debug("Password is valid"); - return true; - } else { - _logger.debug("Invalid password:"); - String passwordPolicyMessage = ""; - for (String msg : validator.getMessages(result)) { - passwordPolicyMessage = passwordPolicyMessage + msg + "
"; - _logger.debug("Rule Message {}" , msg); - } - WebContext.setAttribute(PasswordPolicyValidator.PASSWORD_POLICY_VALIDATE_RESULT, passwordPolicyMessage); - return false; - } - } - - - /** - * dynamic passwordPolicy Valid for user login. - * @param userInfo - * @return boolean - */ - public boolean passwordPolicyValid(UserInfo userInfo) { - - CnfPasswordPolicy passwordPolicy = passwordPolicyRepository.getPasswordPolicy(); - - DateTime currentdateTime = new DateTime(); - /* - * check login attempts fail times - */ - if (userInfo.getBadPasswordCount() >= passwordPolicy.getAttempts() && userInfo.getBadPasswordTime() != null) { - _logger.debug("login Attempts is {} , bad Password Time {}" , userInfo.getBadPasswordCount(),userInfo.getBadPasswordTime()); - - Duration duration = new Duration(new DateTime(userInfo.getBadPasswordTime()), currentdateTime); - int intDuration = Integer.parseInt(duration.getStandardMinutes() + ""); - _logger.debug("bad Password duration {} , " + - "password policy Duration {} , "+ - "validate result {}" , - intDuration, - passwordPolicy.getDuration(), - (intDuration > passwordPolicy.getDuration()) - ); - //auto unlock attempts when intDuration >= set Duration - if(intDuration >= passwordPolicy.getDuration()) { - _logger.debug("resetAttempts ..."); - resetAttempts(userInfo); - }else { - lockUser(userInfo); - throw new BadCredentialsException( - WebContext.getI18nValue("login.error.attempts", - new Object[]{userInfo.getBadPasswordCount(),passwordPolicy.getDuration()}) - ); - } - } - - //locked - if(userInfo.getIsLocked()==ConstsStatus.LOCK) { - throw new BadCredentialsException( - userInfo.getUsername()+ " "+ - WebContext.getI18nValue("login.error.locked") - ); - } - // inactive - if(userInfo.getStatus()!=ConstsStatus.ACTIVE) { - throw new BadCredentialsException( - userInfo.getUsername()+ - WebContext.getI18nValue("login.error.inactive") - ); - } - - return true; - } - - public void applyPasswordPolicy(UserInfo userInfo) { - CnfPasswordPolicy passwordPolicy = passwordPolicyRepository.getPasswordPolicy(); - - DateTime currentdateTime = new DateTime(); - //initial password need change - if(userInfo.getLoginCount()<=0) { - WebContext.getSession().setAttribute(WebConstants.CURRENT_USER_PASSWORD_SET_TYPE, - ConstsPasswordSetType.INITIAL_PASSWORD); - } - - if (userInfo.getPasswordSetType() != ConstsPasswordSetType.PASSWORD_NORMAL) { - WebContext.getSession().setAttribute(WebConstants.CURRENT_USER_PASSWORD_SET_TYPE, - userInfo.getPasswordSetType()); - return; - } else { - WebContext.getSession().setAttribute(WebConstants.CURRENT_USER_PASSWORD_SET_TYPE, - ConstsPasswordSetType.PASSWORD_NORMAL); - } - - /* - * check password is Expired,Expiration is Expired date ,if Expiration equals 0,not need check - * - */ - if (passwordPolicy.getExpiration() > 0 && userInfo.getPasswordLastSetTime() != null) { - _logger.info("last password set date {}" , userInfo.getPasswordLastSetTime()); - Duration duration = new Duration(new DateTime(userInfo.getPasswordLastSetTime()), currentdateTime); - int intDuration = Integer.parseInt(duration.getStandardDays() + ""); - _logger.debug("password Last Set duration day {} , " + - "password policy Expiration {} , " + - "validate result {}", - intDuration, - passwordPolicy.getExpiration(), - intDuration <= passwordPolicy.getExpiration() - ); - if (intDuration > passwordPolicy.getExpiration()) { - WebContext.getSession().setAttribute(WebConstants.CURRENT_USER_PASSWORD_SET_TYPE, - ConstsPasswordSetType.PASSWORD_EXPIRED); - } - } - - resetBadPasswordCount(userInfo); - } - - /** - * lockUser - * - * @param userInfo - */ - public void lockUser(UserInfo userInfo) { - try { - if (userInfo != null - && StringUtils.isNotEmpty(userInfo.getId()) - && userInfo.getIsLocked() == ConstsStatus.ACTIVE) { - jdbcTemplate.update(LOCK_USER_UPDATE_STATEMENT, - new Object[] { ConstsStatus.LOCK, new Date(), userInfo.getId() }, - new int[] { Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR }); - userInfo.setIsLocked(ConstsStatus.LOCK); - } - } catch (Exception e) { - _logger.error("lockUser Exception",e); - } - } - - - /** - * unlockUser - * - * @param userInfo - */ - public void unlockUser(UserInfo userInfo) { - try { - if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) { - jdbcTemplate.update(UNLOCK_USER_UPDATE_STATEMENT, - new Object[] { ConstsStatus.ACTIVE, new Date(), userInfo.getId() }, - new int[] { Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR }); - userInfo.setIsLocked(ConstsStatus.ACTIVE); - } - } catch (Exception e) { - _logger.error("unlockUser Exception",e); - } - } - - /** - * reset BadPasswordCount And Lockout - * - * @param userInfo - */ - public void resetAttempts(UserInfo userInfo) { - try { - if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) { - jdbcTemplate.update(BADPASSWORDCOUNT_RESET_UPDATE_STATEMENT, - new Object[] { 0, ConstsStatus.ACTIVE, new Date(), userInfo.getId() }, - new int[] { Types.INTEGER, Types.INTEGER, Types.TIMESTAMP, Types.VARCHAR }); - userInfo.setIsLocked(ConstsStatus.ACTIVE); - userInfo.setBadPasswordCount(0); - } - } catch (Exception e) { - _logger.error("resetAttempts Exception",e); - } - } - - /** - * if login password is error ,BadPasswordCount++ and set bad date - * - * @param userInfo - */ - private void setBadPasswordCount(String userId,int badPasswordCount) { - try { - jdbcTemplate.update(BADPASSWORDCOUNT_UPDATE_STATEMENT, - new Object[] { badPasswordCount, new Date(), userId }, - new int[] { Types.INTEGER, Types.TIMESTAMP, Types.VARCHAR }); - } catch (Exception e) { - _logger.error("setBadPasswordCount Exception",e); - } - } - - public void plusBadPasswordCount(UserInfo userInfo) { - if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) { - userInfo.setBadPasswordCount(userInfo.getBadPasswordCount() + 1); - setBadPasswordCount(userInfo.getId(),userInfo.getBadPasswordCount()); - CnfPasswordPolicy passwordPolicy = passwordPolicyRepository.getPasswordPolicy(); - if(userInfo.getBadPasswordCount() >= passwordPolicy.getAttempts()) { - _logger.debug("Bad Password Count {} , Max Attempts {}", - userInfo.getBadPasswordCount() + 1,passwordPolicy.getAttempts()); - this.lockUser(userInfo); - } - } - } - - public void resetBadPasswordCount(UserInfo userInfo) { - if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId()) && userInfo.getBadPasswordCount()>0) { - setBadPasswordCount(userInfo.getId(),0); - } - } - - public String generateRandomPassword() { - CnfPasswordPolicy passwordPolicy = passwordPolicyRepository.getPasswordPolicy(); - - PasswordGen passwordGen = new PasswordGen( - passwordPolicy.getRandomPasswordLength() - ); - - return passwordGen.gen( - passwordPolicy.getLowerCase(), - passwordPolicy.getUpperCase(), - passwordPolicy.getDigits(), - passwordPolicy.getSpecialChar()); - } - - public PasswordPolicyRepository getPasswordPolicyRepository() { - return passwordPolicyRepository; - } - -} diff --git a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/CnfPasswordPolicyService.java b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/CnfPasswordPolicyService.java index 756108dc..1c79d8de 100644 --- a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/CnfPasswordPolicyService.java +++ b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/CnfPasswordPolicyService.java @@ -17,9 +17,15 @@ package org.dromara.maxkey.persistence.service; +import java.util.List; + import org.dromara.maxkey.entity.cnf.CnfPasswordPolicy; import org.dromara.mybatis.jpa.IJpaService; +import org.passay.Rule; public interface CnfPasswordPolicyService extends IJpaService{ + public CnfPasswordPolicy getPasswordPolicy(); + + public List getPasswordPolicyRuleList(); } diff --git a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/PasswordPolicyValidatorService.java b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/PasswordPolicyValidatorService.java new file mode 100644 index 00000000..a5fc1aee --- /dev/null +++ b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/PasswordPolicyValidatorService.java @@ -0,0 +1,13 @@ +package org.dromara.maxkey.persistence.service; + +import org.dromara.maxkey.entity.ChangePassword; +import org.dromara.maxkey.entity.cnf.CnfPasswordPolicy; + +public interface PasswordPolicyValidatorService { + + public CnfPasswordPolicy getPasswordPolicy(); + + public boolean validator(ChangePassword changePassword); + + public String generateRandomPassword() ; +} diff --git a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/UserInfoService.java b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/UserInfoService.java index 3440de4d..650dadc4 100644 --- a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/UserInfoService.java +++ b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/UserInfoService.java @@ -20,7 +20,6 @@ package org.dromara.maxkey.persistence.service; import org.dromara.maxkey.entity.ChangePassword; import org.dromara.maxkey.entity.idm.UserInfo; -import org.dromara.maxkey.persistence.repository.PasswordPolicyValidator; import org.dromara.mybatis.jpa.IJpaService; /** @@ -84,19 +83,21 @@ public interface UserInfoService extends IJpaService { * 锁定用户:islock:1 用户解锁 2 用户锁定 * @param userInfo */ - public void updateLocked(UserInfo userInfo) ; + public void locked(UserInfo userInfo) ; /** * 用户登录成功后,重置错误密码次数和解锁用户 * @param userInfo */ - public void updateLockout(UserInfo userInfo) ; + public void lockout(UserInfo userInfo) ; /** * 更新错误密码次数 * @param userInfo */ - public void updateBadPasswordCount(UserInfo userInfo) ; + public void badPasswordCount(UserInfo userInfo) ; + + public void badPasswordCountReset(UserInfo userInfo); public boolean updateSharedSecret(UserInfo userInfo); @@ -112,6 +113,4 @@ public interface UserInfoService extends IJpaService { public boolean updateStatus(UserInfo userInfo); - public void setPasswordPolicyValidator(PasswordPolicyValidator passwordPolicyValidator); - } diff --git a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/impl/CnfPasswordPolicyServiceImpl.java b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/impl/CnfPasswordPolicyServiceImpl.java index 9de9b4f7..c8683acc 100644 --- a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/impl/CnfPasswordPolicyServiceImpl.java +++ b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/impl/CnfPasswordPolicyServiceImpl.java @@ -17,13 +17,139 @@ package org.dromara.maxkey.persistence.service.impl; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.dromara.maxkey.constants.ConstsProperties; import org.dromara.maxkey.entity.cnf.CnfPasswordPolicy; import org.dromara.maxkey.persistence.mapper.CnfPasswordPolicyMapper; import org.dromara.maxkey.persistence.service.CnfPasswordPolicyService; +import org.dromara.mybatis.jpa.query.LambdaQuery; import org.dromara.mybatis.jpa.service.impl.JpaServiceImpl; +import org.passay.CharacterOccurrencesRule; +import org.passay.CharacterRule; +import org.passay.DictionaryRule; +import org.passay.EnglishCharacterData; +import org.passay.EnglishSequenceData; +import org.passay.IllegalSequenceRule; +import org.passay.LengthRule; +import org.passay.Rule; +import org.passay.UsernameRule; +import org.passay.WhitespaceRule; +import org.passay.dictionary.Dictionary; +import org.passay.dictionary.DictionaryBuilder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Repository; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; + @Repository public class CnfPasswordPolicyServiceImpl extends JpaServiceImpl implements CnfPasswordPolicyService{ + static final Logger _logger = LoggerFactory.getLogger(CnfPasswordPolicyServiceImpl.class); + + //Dictionary topWeakPassword Source + public static final String TOPWEAKPASSWORD_PROPERTYSOURCE = "classpath:/top_weak_password.txt"; + + //Cache PasswordPolicy in memory ONE_HOUR + protected static final Cache passwordPolicyStore = + Caffeine.newBuilder() + .expireAfterWrite(60, TimeUnit.MINUTES) + .build(); + + protected CnfPasswordPolicy passwordPolicy; + + ArrayList passwordPolicyRuleList; + + private static final String PASSWORD_POLICY_KEY = "PASSWORD_POLICY_KEY"; + + /** + * init PasswordPolicy and load Rules + * @return + */ + public CnfPasswordPolicy getPasswordPolicy() { + passwordPolicy = passwordPolicyStore.getIfPresent(PASSWORD_POLICY_KEY); + + if (passwordPolicy == null) { + LambdaQueryquery = new LambdaQuery<>(); + query.notNull(CnfPasswordPolicy::getId); + passwordPolicy = this.get(query); + _logger.debug("query PasswordPolicy : {}" , passwordPolicy); + passwordPolicyStore.put(PASSWORD_POLICY_KEY,passwordPolicy); + + //RandomPasswordLength =(MaxLength +MinLength)/2 + passwordPolicy.setRandomPasswordLength( + Math.round( + ( + passwordPolicy.getMaxLength() + + passwordPolicy.getMinLength() + )/2 + ) + ); + + passwordPolicyRuleList = new ArrayList<>(); + passwordPolicyRuleList.add(new WhitespaceRule()); + passwordPolicyRuleList.add(new LengthRule(passwordPolicy.getMinLength(), passwordPolicy.getMaxLength())); + + if(passwordPolicy.getUpperCase()>0) { + passwordPolicyRuleList.add(new CharacterRule(EnglishCharacterData.UpperCase, passwordPolicy.getUpperCase())); + } + + if(passwordPolicy.getLowerCase()>0) { + passwordPolicyRuleList.add(new CharacterRule(EnglishCharacterData.LowerCase, passwordPolicy.getLowerCase())); + } + + if(passwordPolicy.getDigits()>0) { + passwordPolicyRuleList.add(new CharacterRule(EnglishCharacterData.Digit, passwordPolicy.getDigits())); + } + + if(passwordPolicy.getSpecialChar()>0) { + passwordPolicyRuleList.add(new CharacterRule(EnglishCharacterData.Special, passwordPolicy.getSpecialChar())); + } + + if(passwordPolicy.getUsername()>0) { + passwordPolicyRuleList.add(new UsernameRule()); + } + + if(passwordPolicy.getOccurances()>0) { + passwordPolicyRuleList.add(new CharacterOccurrencesRule(passwordPolicy.getOccurances())); + } + + if(passwordPolicy.getAlphabetical()>0) { + passwordPolicyRuleList.add(new IllegalSequenceRule(EnglishSequenceData.Alphabetical, 4, false)); + } + + if(passwordPolicy.getNumerical()>0) { + passwordPolicyRuleList.add(new IllegalSequenceRule(EnglishSequenceData.Numerical, 4, false)); + } + + if(passwordPolicy.getQwerty()>0) { + passwordPolicyRuleList.add(new IllegalSequenceRule(EnglishSequenceData.USQwerty, 4, false)); + } + + if(passwordPolicy.getDictionary()>0 ) { + try { + ClassPathResource dictFile= + new ClassPathResource( + ConstsProperties.classPathResource(TOPWEAKPASSWORD_PROPERTYSOURCE)); + Dictionary dictionary =new DictionaryBuilder().addReader(new InputStreamReader(dictFile.getInputStream())).build(); + passwordPolicyRuleList.add(new DictionaryRule(dictionary)); + }catch(Exception e) { + e.printStackTrace(); + } + } + } + return passwordPolicy; + } + + + public List getPasswordPolicyRuleList() { + getPasswordPolicy(); + return passwordPolicyRuleList; + } } diff --git a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/impl/PasswordPolicyValidatorServiceImpl.java b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/impl/PasswordPolicyValidatorServiceImpl.java new file mode 100644 index 00000000..5a6f30f5 --- /dev/null +++ b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/impl/PasswordPolicyValidatorServiceImpl.java @@ -0,0 +1,167 @@ +/* + * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] + * + * 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.dromara.maxkey.persistence.service.impl; + +import java.util.Locale; + +import org.apache.commons.lang3.StringUtils; +import org.dromara.maxkey.crypto.password.PasswordGen; +import org.dromara.maxkey.entity.ChangePassword; +import org.dromara.maxkey.entity.cnf.CnfPasswordPolicy; +import org.dromara.maxkey.persistence.service.CnfPasswordPolicyService; +import org.dromara.maxkey.persistence.service.PasswordPolicyValidatorService; +import org.dromara.maxkey.web.WebContext; +import org.passay.MessageResolver; +import org.passay.PasswordData; +import org.passay.PasswordValidator; +import org.passay.PropertiesMessageResolver; +import org.passay.RuleResult; +import org.passay.RuleResultDetail; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.context.MessageSource; +import org.springframework.context.NoSuchMessageException; +import org.springframework.context.support.MessageSourceAccessor; + +public class PasswordPolicyValidatorServiceImpl implements PasswordPolicyValidatorService{ + static final Logger _logger = LoggerFactory.getLogger(PasswordPolicyValidatorServiceImpl.class); + + CnfPasswordPolicyService cnfPasswordPolicyService; + + MessageSource messageSource; + + public static final String PASSWORD_POLICY_VALIDATE_RESULT = "PASSWORD_POLICY_SESSION_VALIDATE_RESULT_KEY"; + + public PasswordPolicyValidatorServiceImpl() { + } + + public PasswordPolicyValidatorServiceImpl(CnfPasswordPolicyService cnfPasswordPolicyService,MessageSource messageSource) { + this.messageSource=messageSource; + this.cnfPasswordPolicyService = cnfPasswordPolicyService; + + } + + public CnfPasswordPolicy getPasswordPolicy(){ + return cnfPasswordPolicyService.getPasswordPolicy(); + } + + + /** + * static validator . + * @param userInfo + * @return boolean + */ + public boolean validator(ChangePassword changePassword) { + + + String password = changePassword.getPassword(); + String username = changePassword.getUsername(); + + if(StringUtils.isBlank(username)){ + _logger.debug("username is Empty "); + return false; + } + + if(StringUtils.isBlank(password)){ + _logger.debug("password is Empty "); + return false; + } + + PasswordValidator validator = new PasswordValidator( + new PasswordPolicyMessageResolver(messageSource),cnfPasswordPolicyService.getPasswordPolicyRuleList()); + + RuleResult result = validator.validate(new PasswordData(username,password)); + + if (result.isValid()) { + _logger.debug("Password is valid"); + return true; + } else { + _logger.debug("Invalid password:"); + String passwordPolicyMessage = ""; + for (String msg : validator.getMessages(result)) { + passwordPolicyMessage = passwordPolicyMessage + msg + "
"; + _logger.debug("Rule Message {}" , msg); + } + WebContext.setAttribute(PasswordPolicyValidatorServiceImpl.PASSWORD_POLICY_VALIDATE_RESULT, passwordPolicyMessage); + return false; + } + } + + + + public String generateRandomPassword() { + CnfPasswordPolicy passwordPolicy = cnfPasswordPolicyService.getPasswordPolicy(); + + PasswordGen passwordGen = new PasswordGen( + passwordPolicy.getRandomPasswordLength() + ); + + return passwordGen.gen( + passwordPolicy.getLowerCase(), + passwordPolicy.getUpperCase(), + passwordPolicy.getDigits(), + passwordPolicy.getSpecialChar()); + } + + public class PasswordPolicyMessageResolver implements MessageResolver{ + + /** A accessor for Spring's {@link MessageSource} */ + private final MessageSourceAccessor messageSourceAccessor; + + /** The {@link MessageResolver} for fallback */ + private final MessageResolver fallbackMessageResolver = new PropertiesMessageResolver(); + + /** + * Create a new instance with the locale associated with the current thread. + * @param messageSource a message source managed by spring + */ + public PasswordPolicyMessageResolver(final MessageSource messageSource) + { + this.messageSourceAccessor = new MessageSourceAccessor(messageSource); + } + + /** + * Create a new instance with the specified locale. + * @param messageSource a message source managed by spring + * @param locale the locale to use for message access + */ + public PasswordPolicyMessageResolver(final MessageSource messageSource, final Locale locale) + { + this.messageSourceAccessor = new MessageSourceAccessor(messageSource, locale); + } + + /** + * Resolves the message for the supplied rule result detail using Spring's {@link MessageSource}. + * (If the message can't retrieve from a {@link MessageSource}, return default message provided by passay) + * @param detail rule result detail + * @return message for the detail error code + */ + @Override + public String resolve(final RuleResultDetail detail) + { + try { + return this.messageSourceAccessor.getMessage("PasswordPolicy."+detail.getErrorCode(), detail.getValues()); + } catch (NoSuchMessageException e) { + return this.fallbackMessageResolver.resolve(detail); + } + } + } + +} + + diff --git a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/impl/UserInfoServiceImpl.java b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/impl/UserInfoServiceImpl.java index 7764d803..f74b7849 100644 --- a/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/impl/UserInfoServiceImpl.java +++ b/maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/impl/UserInfoServiceImpl.java @@ -28,8 +28,8 @@ import org.dromara.maxkey.entity.Accounts; import org.dromara.maxkey.entity.ChangePassword; import org.dromara.maxkey.entity.idm.UserInfo; import org.dromara.maxkey.persistence.mapper.UserInfoMapper; -import org.dromara.maxkey.persistence.repository.PasswordPolicyValidator; import org.dromara.maxkey.persistence.service.AccountsService; +import org.dromara.maxkey.persistence.service.PasswordPolicyValidatorService; import org.dromara.maxkey.persistence.service.UserInfoService; import org.dromara.maxkey.provision.ProvisionAct; import org.dromara.maxkey.provision.ProvisionService; @@ -55,7 +55,7 @@ public class UserInfoServiceImpl extends JpaServiceImpl private PasswordEncoder passwordEncoder; @Autowired - PasswordPolicyValidator passwordPolicyValidator; + PasswordPolicyValidatorService passwordPolicyValidatorService; @Autowired ProvisionService provisionService; @@ -256,7 +256,7 @@ public class UserInfoServiceImpl extends JpaServiceImpl */ public boolean changePassword( ChangePassword changePassword) { try { - WebContext.setAttribute(PasswordPolicyValidator.PASSWORD_POLICY_VALIDATE_RESULT, ""); + WebContext.setAttribute(PasswordPolicyValidatorServiceImpl.PASSWORD_POLICY_VALIDATE_RESULT, ""); UserInfo userInfo = this.findByUsername(changePassword.getUsername()); if(changePassword.getPassword().equals(changePassword.getConfirmPassword())){ if(StringUtils.isNotBlank(changePassword.getOldPassword()) && @@ -268,15 +268,15 @@ public class UserInfoServiceImpl extends JpaServiceImpl }else { if(StringUtils.isNotBlank(changePassword.getOldPassword())&& passwordEncoder.matches(changePassword.getPassword(), userInfo.getPassword())) { - WebContext.setAttribute(PasswordPolicyValidator.PASSWORD_POLICY_VALIDATE_RESULT, + WebContext.setAttribute(PasswordPolicyValidatorServiceImpl.PASSWORD_POLICY_VALIDATE_RESULT, WebContext.getI18nValue("PasswordPolicy.OLD_PASSWORD_MATCH")); }else { - WebContext.setAttribute(PasswordPolicyValidator.PASSWORD_POLICY_VALIDATE_RESULT, + WebContext.setAttribute(PasswordPolicyValidatorServiceImpl.PASSWORD_POLICY_VALIDATE_RESULT, WebContext.getI18nValue("PasswordPolicy.OLD_PASSWORD_NOT_MATCH")); } } }else { - WebContext.setAttribute(PasswordPolicyValidator.PASSWORD_POLICY_VALIDATE_RESULT, + WebContext.setAttribute(PasswordPolicyValidatorServiceImpl.PASSWORD_POLICY_VALIDATE_RESULT, WebContext.getI18nValue("PasswordPolicy.CONFIRMPASSWORD_NOT_MATCH")); } } catch (Exception e) { @@ -297,7 +297,7 @@ public class UserInfoServiceImpl extends JpaServiceImpl _logger.debug("decipherable old : {}" , changePassword.getDecipherable()); _logger.debug("decipherable new : {}" , PasswordReciprocal.getInstance().encode(changePassword.getDecipherable())); - if (passwordPolicy && !passwordPolicyValidator.validator(changePassword)) { + if (passwordPolicy && !passwordPolicyValidatorService.validator(changePassword)) { return false; } @@ -317,7 +317,7 @@ public class UserInfoServiceImpl extends JpaServiceImpl } public String randomPassword() { - return passwordPolicyValidator.generateRandomPassword(); + return passwordPolicyValidatorService.generateRandomPassword(); } public void changePasswordProvisioning(ChangePassword changePassworded) { @@ -340,10 +340,10 @@ public class UserInfoServiceImpl extends JpaServiceImpl /** - * 锁定用户:islock:1 用户解锁 2 用户锁定 + * 锁定用户:islock:1 解锁 5 锁定 * @param userInfo */ - public void updateLocked(UserInfo userInfo) { + public void locked(UserInfo userInfo) { try { if(userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) { userInfo.setIsLocked(ConstsStatus.LOCK); @@ -358,10 +358,10 @@ public class UserInfoServiceImpl extends JpaServiceImpl * 用户登录成功后,重置错误密码次数和解锁用户 * @param userInfo */ - public void updateLockout(UserInfo userInfo) { + public void lockout(UserInfo userInfo) { try { if(userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) { - userInfo.setIsLocked(ConstsStatus.START); + userInfo.setIsLocked(ConstsStatus.ACTIVE); userInfo.setBadPasswordCount(0); getMapper().updateLockout(userInfo); } @@ -374,12 +374,26 @@ public class UserInfoServiceImpl extends JpaServiceImpl * 更新错误密码次数 * @param userInfo */ - public void updateBadPasswordCount(UserInfo userInfo) { + public void badPasswordCount(UserInfo userInfo) { try { if(userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) { int updateBadPWDCount = userInfo.getBadPasswordCount() + 1; userInfo.setBadPasswordCount(updateBadPWDCount); - getMapper().updateBadPWDCount(userInfo); + getMapper().badPasswordCount(userInfo); + } + } catch(Exception e) { + e.printStackTrace(); + } + } + + /** + * 重置错误密码次数 + * @param userInfo + */ + public void badPasswordCountReset(UserInfo userInfo) { + try { + if(userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) { + getMapper().badPasswordCountReset(userInfo); } } catch(Exception e) { e.printStackTrace(); @@ -414,8 +428,4 @@ public class UserInfoServiceImpl extends JpaServiceImpl return getMapper().updateStatus(userInfo) > 0; } - public void setPasswordPolicyValidator(PasswordPolicyValidator passwordPolicyValidator) { - this.passwordPolicyValidator = passwordPolicyValidator; - } - } diff --git a/maxkey-persistence/src/main/resources/org/dromara/maxkey/persistence/mapper/xml/mysql/UserInfoMapper.xml b/maxkey-persistence/src/main/resources/org/dromara/maxkey/persistence/mapper/xml/mysql/UserInfoMapper.xml index e4493f6c..1ed0213d 100644 --- a/maxkey-persistence/src/main/resources/org/dromara/maxkey/persistence/mapper/xml/mysql/UserInfoMapper.xml +++ b/maxkey-persistence/src/main/resources/org/dromara/maxkey/persistence/mapper/xml/mysql/UserInfoMapper.xml @@ -65,8 +65,9 @@ update mxk_userinfo set - islocked = #{isLocked}, + islocked = #{isLocked}, + unlockdate = current_timestamp modifieddate = current_timestamp where id = #{id} @@ -75,14 +76,29 @@ update mxk_userinfo set - islocked = #{isLocked}, - badpwdcount = 0, + islocked = #{isLocked}, + badpasswordcount = 0, unlockdate = current_timestamp, modifieddate = current_timestamp where id = #{id} + + + update mxk_userinfo set + badpasswordcount = badpasswordcount + 1 , + badpasswordtime = current_timestamp + where id = #{id} + + + + update mxk_userinfo set + badpasswordcount = 0 , + islocked = 1 , + unlocktime = current_timestamp + where id = #{id} + update mxk_userinfo set diff --git a/maxkey-webs/maxkey-web-maxkey/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyConfig.java b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyConfig.java index 044777f3..6be9af1f 100644 --- a/maxkey-webs/maxkey-web-maxkey/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyConfig.java +++ b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyConfig.java @@ -43,9 +43,9 @@ import org.dromara.maxkey.password.onetimepwd.impl.TimeBasedOtpAuthn; import org.dromara.maxkey.password.onetimepwd.token.RedisOtpTokenStore; import org.dromara.maxkey.persistence.redis.RedisConnectionFactory; import org.dromara.maxkey.persistence.repository.LoginRepository; -import org.dromara.maxkey.persistence.repository.PasswordPolicyValidator; import org.dromara.maxkey.persistence.service.CnfLdapContextService; import org.dromara.maxkey.persistence.service.HistoryLoginService; +import org.dromara.maxkey.persistence.service.PasswordPolicyValidatorService; import org.dromara.maxkey.persistence.service.UserInfoService; import org.dromara.maxkey.schedule.ScheduleAdapterBuilder; import org.quartz.Scheduler; @@ -88,7 +88,7 @@ public class MaxKeyConfig { @Bean JdbcAuthenticationRealm authenticationRealm( @Qualifier("passwordEncoder") PasswordEncoder passwordEncoder, - PasswordPolicyValidator passwordPolicyValidator, + PasswordPolicyValidatorService passwordPolicyValidatorService, LoginRepository loginService, HistoryLoginService historyLoginService, UserInfoService userInfoService, @@ -99,7 +99,7 @@ public class MaxKeyConfig { LdapAuthenticationRealmService ldapRealmService = new LdapAuthenticationRealmService(ldapContextService); return new JdbcAuthenticationRealm( passwordEncoder, - passwordPolicyValidator, + passwordPolicyValidatorService, loginService, historyLoginService, userInfoService, diff --git a/maxkey-webs/maxkey-web-maxkey/src/main/java/org/dromara/maxkey/web/contorller/ChangePasswodController.java b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/dromara/maxkey/web/contorller/ChangePasswodController.java index 7c05eff1..67ffa142 100644 --- a/maxkey-webs/maxkey-web-maxkey/src/main/java/org/dromara/maxkey/web/contorller/ChangePasswodController.java +++ b/maxkey-webs/maxkey-web-maxkey/src/main/java/org/dromara/maxkey/web/contorller/ChangePasswodController.java @@ -26,10 +26,10 @@ import org.dromara.maxkey.entity.ChangePassword; import org.dromara.maxkey.entity.Message; import org.dromara.maxkey.entity.cnf.CnfPasswordPolicy; import org.dromara.maxkey.entity.idm.UserInfo; -import org.dromara.maxkey.persistence.repository.PasswordPolicyValidator; import org.dromara.maxkey.persistence.service.HistorySystemLogsService; import org.dromara.maxkey.persistence.service.CnfPasswordPolicyService; import org.dromara.maxkey.persistence.service.UserInfoService; +import org.dromara.maxkey.persistence.service.impl.PasswordPolicyValidatorServiceImpl; import org.dromara.maxkey.web.WebContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -78,7 +78,7 @@ public class ChangePasswodController { currentUser); return new Message<>(); }else { - String message = (String) WebContext.getAttribute(PasswordPolicyValidator.PASSWORD_POLICY_VALIDATE_RESULT); + String message = (String) WebContext.getAttribute(PasswordPolicyValidatorServiceImpl.PASSWORD_POLICY_VALIDATE_RESULT); logger.info("-message: {}",message); return new Message<>(Message.ERROR,message); } diff --git a/maxkey-webs/maxkey-web-mgt/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyMgtConfig.java b/maxkey-webs/maxkey-web-mgt/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyMgtConfig.java index db49d048..995c6ea1 100644 --- a/maxkey-webs/maxkey-web-mgt/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyMgtConfig.java +++ b/maxkey-webs/maxkey-web-mgt/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyMgtConfig.java @@ -22,8 +22,8 @@ import org.dromara.maxkey.ip2location.IpLocationParser; import org.dromara.maxkey.password.onetimepwd.AbstractOtpAuthn; import org.dromara.maxkey.password.onetimepwd.impl.TimeBasedOtpAuthn; import org.dromara.maxkey.persistence.repository.LoginRepository; -import org.dromara.maxkey.persistence.repository.PasswordPolicyValidator; import org.dromara.maxkey.persistence.service.HistoryLoginService; +import org.dromara.maxkey.persistence.service.PasswordPolicyValidatorService; import org.dromara.maxkey.persistence.service.UserInfoService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,7 +42,7 @@ public class MaxKeyMgtConfig { JdbcAuthenticationRealm authenticationRealm( @Qualifier("passwordEncoder") PasswordEncoder passwordEncoder, - PasswordPolicyValidator passwordPolicyValidator, + PasswordPolicyValidatorService passwordPolicyValidatorService, LoginRepository loginRepository, HistoryLoginService historyLoginService, UserInfoService userInfoService, @@ -51,7 +51,7 @@ public class MaxKeyMgtConfig { JdbcAuthenticationRealm authenticationRealm = new JdbcAuthenticationRealm( passwordEncoder, - passwordPolicyValidator, + passwordPolicyValidatorService, loginRepository, historyLoginService, userInfoService, diff --git a/maxkey-webs/maxkey-web-openapi/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyOpenApiConfig.java b/maxkey-webs/maxkey-web-openapi/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyOpenApiConfig.java index 3f401da8..296dd062 100644 --- a/maxkey-webs/maxkey-web-openapi/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyOpenApiConfig.java +++ b/maxkey-webs/maxkey-web-openapi/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyOpenApiConfig.java @@ -22,8 +22,8 @@ import org.dromara.maxkey.ip2location.IpLocationParser; import org.dromara.maxkey.password.onetimepwd.AbstractOtpAuthn; import org.dromara.maxkey.password.onetimepwd.impl.TimeBasedOtpAuthn; import org.dromara.maxkey.persistence.repository.LoginRepository; -import org.dromara.maxkey.persistence.repository.PasswordPolicyValidator; import org.dromara.maxkey.persistence.service.HistoryLoginService; +import org.dromara.maxkey.persistence.service.PasswordPolicyValidatorService; import org.dromara.maxkey.persistence.service.UserInfoService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -42,7 +42,7 @@ public class MaxKeyOpenApiConfig{ JdbcAuthenticationRealm authenticationRealm( @Qualifier("passwordEncoder") PasswordEncoder passwordEncoder, - PasswordPolicyValidator passwordPolicyValidator, + PasswordPolicyValidatorService passwordPolicyValidatorService, LoginRepository loginRepository, HistoryLoginService historyLoginService, UserInfoService userInfoService, @@ -51,7 +51,7 @@ public class MaxKeyOpenApiConfig{ JdbcAuthenticationRealm authenticationRealm = new JdbcAuthenticationRealm( passwordEncoder, - passwordPolicyValidator, + passwordPolicyValidatorService, loginRepository, historyLoginService, userInfoService,