Bläddra i källkod

代码整合优化

shimingxy 1 år sedan
förälder
incheckning
7844fc25bf
30 ändrade filer med 592 tillägg och 707 borttagningar
  1. 1 1
      maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/provider/impl/MobileAuthenticationProvider.java
  2. 2 2
      maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/provider/impl/NormalAuthenticationProvider.java
  3. 2 2
      maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/provider/impl/TrustedAuthenticationProvider.java
  4. 4 4
      maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/realm/AbstractAuthenticationRealm.java
  5. 7 7
      maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/authn/realm/jdbc/JdbcAuthenticationRealm.java
  6. 10 5
      maxkey-authentications/maxkey-authentication-provider-mgt/src/main/java/org/dromara/maxkey/autoconfigure/AuthnProviderAutoConfiguration.java
  7. 2 2
      maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/AppAuthenticationProvider.java
  8. 2 2
      maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/MfaAuthenticationProvider.java
  9. 1 1
      maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/MobileAuthenticationProvider.java
  10. 2 2
      maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/NormalAuthenticationProvider.java
  11. 2 2
      maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/provider/impl/TrustedAuthenticationProvider.java
  12. 4 4
      maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/realm/AbstractAuthenticationRealm.java
  13. 7 7
      maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/authn/realm/jdbc/JdbcAuthenticationRealm.java
  14. 10 5
      maxkey-authentications/maxkey-authentication-provider/src/main/java/org/dromara/maxkey/autoconfigure/AuthnProviderAutoConfiguration.java
  15. 3 1
      maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/mapper/UserInfoMapper.java
  16. 158 41
      maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/LoginRepository.java
  17. 0 72
      maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/PasswordPolicyMessageResolver.java
  18. 0 186
      maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/PasswordPolicyRepository.java
  19. 0 323
      maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/PasswordPolicyValidator.java
  20. 6 0
      maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/CnfPasswordPolicyService.java
  21. 13 0
      maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/PasswordPolicyValidatorService.java
  22. 5 6
      maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/UserInfoService.java
  23. 126 0
      maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/impl/CnfPasswordPolicyServiceImpl.java
  24. 167 0
      maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/impl/PasswordPolicyValidatorServiceImpl.java
  25. 28 18
      maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/service/impl/UserInfoServiceImpl.java
  26. 19 3
      maxkey-persistence/src/main/resources/org/dromara/maxkey/persistence/mapper/xml/mysql/UserInfoMapper.xml
  27. 3 3
      maxkey-webs/maxkey-web-maxkey/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyConfig.java
  28. 2 2
      maxkey-webs/maxkey-web-maxkey/src/main/java/org/dromara/maxkey/web/contorller/ChangePasswodController.java
  29. 3 3
      maxkey-webs/maxkey-web-mgt/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyMgtConfig.java
  30. 3 3
      maxkey-webs/maxkey-web-openapi/src/main/java/org/dromara/maxkey/autoconfigure/MaxKeyOpenApiConfig.java

+ 1 - 1
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

+ 2 - 2
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

+ 2 - 2
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, 

+ 4 - 4
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() {

+ 7 - 7
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",

+ 10 - 5
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);
     }
 
 }

+ 2 - 2
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

+ 2 - 2
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

+ 1 - 1
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

+ 2 - 2
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

+ 2 - 2
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, 

+ 4 - 4
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() {

+ 7 - 7
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",

+ 10 - 5
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);
     }
 
     /**

+ 3 - 1
maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/mapper/UserInfoMapper.java

@@ -49,7 +49,9 @@ public interface UserInfoMapper  extends IJpaMapper<UserInfo>{
 
 	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);
 	

+ 158 - 41
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 void updateLock(UserInfo userInfo) {
+    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 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);
         }
     }
 

+ 0 - 72
maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/PasswordPolicyMessageResolver.java

@@ -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);
-      }
-    }
-}

+ 0 - 186
maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/PasswordPolicyRepository.java

@@ -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<String, CnfPasswordPolicy> passwordPolicyStore = 
-            Caffeine.newBuilder()
-                .expireAfterWrite(60, TimeUnit.MINUTES)
-                .build();
-    
-    protected CnfPasswordPolicy passwordPolicy;
-    
-    protected JdbcTemplate jdbcTemplate;
-    
-    ArrayList <Rule> 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<Rule> getPasswordPolicyRuleList() {
-	   getPasswordPolicy();
-		return passwordPolicyRuleList;
-	}
-
-
-public class PasswordPolicyRowMapper implements RowMapper<CnfPasswordPolicy> {
-
-       @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;
-       }
-
-   }
-}

+ 0 - 323
maxkey-persistence/src/main/java/org/dromara/maxkey/persistence/repository/PasswordPolicyValidator.java

@@ -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 + "<br>";
-               _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;
-	}
-
-}

+ 6 - 0
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<CnfPasswordPolicy>{
 	
+	public CnfPasswordPolicy getPasswordPolicy();
+	
+	public List<Rule> getPasswordPolicyRuleList();
 }

+ 13 - 0
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() ;
+}

+ 5 - 6
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<UserInfo> {
 	 * 锁定用户: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<UserInfo> {
     
     public boolean 	updateStatus(UserInfo userInfo);
 
-    public void setPasswordPolicyValidator(PasswordPolicyValidator passwordPolicyValidator);
-
 }

+ 126 - 0
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<CnfPasswordPolicyMapper,CnfPasswordPolicy> 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<String, CnfPasswordPolicy> passwordPolicyStore = 
+            Caffeine.newBuilder()
+                .expireAfterWrite(60, TimeUnit.MINUTES)
+                .build();
+    
+    protected CnfPasswordPolicy passwordPolicy;
+    
+    ArrayList <Rule> 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) {
+        	LambdaQuery<CnfPasswordPolicy>query = 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<Rule> getPasswordPolicyRuleList() {
+	   getPasswordPolicy();
+		return passwordPolicyRuleList;
+	}
 
 }

+ 167 - 0
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 + "<br>";
+               _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);
+	      }
+	    }
+	}
+
+}
+
+

+ 28 - 18
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<UserInfoMapper,UserInfo>
 	private PasswordEncoder passwordEncoder;
 	
 	@Autowired
-	PasswordPolicyValidator passwordPolicyValidator;
+	PasswordPolicyValidatorService passwordPolicyValidatorService;
 	
 	@Autowired
 	ProvisionService provisionService;
@@ -256,7 +256,7 @@ public class UserInfoServiceImpl extends JpaServiceImpl<UserInfoMapper,UserInfo>
 	 */
 	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<UserInfoMapper,UserInfo>
 	            }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<UserInfoMapper,UserInfo>
             _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<UserInfoMapper,UserInfo>
     }
 	
 	public String randomPassword() {
-	    return passwordPolicyValidator.generateRandomPassword();
+	    return passwordPolicyValidatorService.generateRandomPassword();
 	}
 	
 	public void changePasswordProvisioning(ChangePassword changePassworded) {
@@ -340,10 +340,10 @@ public class UserInfoServiceImpl extends JpaServiceImpl<UserInfoMapper,UserInfo>
 	
 	
 	/**
-	 * 锁定用户: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<UserInfoMapper,UserInfo>
 	 * 用户登录成功后,重置错误密码次数和解锁用户
 	 * @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<UserInfoMapper,UserInfo>
 	 * 更新错误密码次数
 	 * @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<UserInfoMapper,UserInfo>
     	return getMapper().updateStatus(userInfo) > 0;
     }
 
-    public void setPasswordPolicyValidator(PasswordPolicyValidator passwordPolicyValidator) {
-        this.passwordPolicyValidator = passwordPolicyValidator;
-    }
-
 }

+ 19 - 3
maxkey-persistence/src/main/resources/org/dromara/maxkey/persistence/mapper/xml/mysql/UserInfoMapper.xml

@@ -65,8 +65,9 @@
     <update id="updateLocked" parameterType="UserInfo" >
     	update mxk_userinfo set
     		<if test="isLocked != null">
-    		islocked		=	#{isLocked},
+    		islocked			=	#{isLocked},
 			</if>
+			unlockdate			=	current_timestamp
 			modifieddate		=	current_timestamp
 		where 
 			id	=	#{id}
@@ -75,14 +76,29 @@
     <update id="updateLockout" parameterType="UserInfo" >
     	update mxk_userinfo set
     		<if test="isLocked != null">
-    		islocked		=	#{isLocked},
-    		badpwdcount		=	0,
+    		islocked			=	#{isLocked},
+    		badpasswordcount	=	0,
 			</if>
 			unlockdate			=	current_timestamp,
 			modifieddate		=	current_timestamp
 		where 
 			id	=	#{id}
     </update>
+    
+    <update id="badPasswordCount" parameterType="UserInfo" >
+    	update mxk_userinfo set 
+	    	badpasswordcount = badpasswordcount + 1 , 
+	    	badpasswordtime = current_timestamp  
+    	where id = #{id}
+    </update>
+    
+    <update id="badPasswordCountReset" parameterType="UserInfo" >
+    	update mxk_userinfo set 
+	    	badpasswordcount = 0 , 
+	    	islocked = 1  ,
+	    	unlocktime = current_timestamp  
+    	where id = #{id}
+    </update>	
     	
 	<update id="changePassword" parameterType="ChangePassword" >
     	update mxk_userinfo set

+ 3 - 3
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,

+ 2 - 2
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);
 		}

+ 3 - 3
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,

+ 3 - 3
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,