Pārlūkot izejas kodu

PasswordPolicyValidator

PasswordPolicyValidator
Crystal.Sea 4 gadi atpakaļ
vecāks
revīzija
4f67f93c28

+ 8 - 3
ReleaseNotes.txt

@@ -1,8 +1,13 @@
 MaxKey v 2.2.0 GA	2020/**/**
 	*(MAXKEY-200801)   官方网站内容调整,初步增加英文版支持
-	*(MAXKEY-200802) CAS协议增加自定义参数回传
-	*(MAXKEY-200803)  优化开发集成指南
-	*(MAXKEY-200804)  删除冗余的文件和文件夹
+	*(MAXKEY-200802)  密码策略优化
+	*(MAXKEY-200803) CAS协议增加自定义参数回传
+	*(MAXKEY-200804)  优化开发集成指南
+	*(MAXKEY-200805)  删除冗余的文件和文件夹
+	*(MAXKEY-200806)  CAS适配器支持
+	*(MAXKEY-200807)  Maven版本支持
+	*(MAXKEY-200808)  CAS spring boot demo
+	
 	
 	
 MaxKey v 2.1.0 GA	2020/08/01

+ 1 - 0
build.gradle

@@ -291,6 +291,7 @@ subprojects {
 		 compile group: 'org.apache.santuario', name: 'xmlsec', version: '1.5.8'
 		 compile group: 'org.ogce', name: 'xpp3', version: '1.1.6'
 		 compile group: 'com.thoughtworks.xstream', name: 'xstream', version: '1.4.10'
+		 compile group: 'org.passay', name: 'passay', version: '1.6.0'
 		
     	 //local jars
     	 compile fileTree(dir: "${rootDir}/maxkey-lib/", include: '*.jar')

+ 1 - 1
maxkey-core/src/main/java/org/maxkey/authn/RealmAuthenticationProvider.java

@@ -68,7 +68,7 @@ public class RealmAuthenticationProvider extends AbstractAuthenticationProvider
 
         tftcaptchaValid(auth.getOtpCaptcha(),auth.getAuthType(),userInfo);
 
-        authenticationRealm.passwordPolicyValid(userInfo);
+        authenticationRealm.getPasswordPolicyValidator().passwordPolicyValid(userInfo);
 
         authenticationRealm.passwordMatches(userInfo, auth.getPassword());
         authenticationRealm.grantAuthority(userInfo);

+ 39 - 220
maxkey-core/src/main/java/org/maxkey/authn/realm/AbstractAuthenticationRealm.java

@@ -17,27 +17,17 @@
 
 package org.maxkey.authn.realm;
 
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Types;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
 import javax.servlet.http.HttpServletResponse;
-import org.joda.time.DateTime;
-import org.joda.time.Duration;
-import org.joda.time.format.DateTimeFormat;
 import org.maxkey.authn.support.rememberme.AbstractRemeberMeService;
-import org.maxkey.constants.ConstantsLoginType;
-import org.maxkey.constants.ConstantsPasswordSetType;
-import org.maxkey.constants.ConstantsStatus;
 import org.maxkey.domain.Groups;
-import org.maxkey.domain.PasswordPolicy;
 import org.maxkey.domain.UserInfo;
-import org.maxkey.persistence.db.PasswordPolicyRowMapper;
-import org.maxkey.persistence.db.UserInfoRowMapper;
+import org.maxkey.persistence.db.LoginHistoryService;
+import org.maxkey.persistence.db.PasswordPolicyValidator;
+import org.maxkey.persistence.db.LoginService;
 import org.maxkey.util.DateUtils;
-import org.maxkey.util.StringUtils;
 import org.maxkey.web.WebConstants;
 import org.maxkey.web.WebContext;
 import org.slf4j.Logger;
@@ -45,10 +35,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Qualifier;
 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;
 
 /**
  * AbstractAuthenticationRealm.
@@ -58,35 +45,18 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority;
 public abstract class AbstractAuthenticationRealm {
     private static Logger _logger = LoggerFactory.getLogger(AbstractAuthenticationRealm.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 HISTORY_LOGIN_INSERT_STATEMENT = "INSERT INTO MXK_HISTORY_LOGIN (ID , SESSIONID , UID , USERNAME , DISPLAYNAME , LOGINTYPE , MESSAGE , CODE , PROVIDER , SOURCEIP , BROWSER , PLATFORM , APPLICATION , LOGINURL )VALUES( ? , ? , ? , ? , ?, ? , ? , ?, ? , ? , ?, ? , ? , ?)";
-
-    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 LOGOUT_USERINFO_UPDATE_STATEMENT = "UPDATE MXK_USERINFO SET LASTLOGOFFTIME = ? , ONLINE = "
-            + UserInfo.ONLINE.OFFLINE + "  WHERE ID = ?";
-
-    private static final String HISTORY_LOGOUT_UPDATE_STATEMENT = "UPDATE MXK_HISTORY_LOGIN SET LOGOUTTIME = ?  WHERE  SESSIONID = ?";
-
-    private static final String GROUPS_SELECT_STATEMENT = "SELECT DISTINCT G.ID,G.NAME 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 = ?";
-
-    private static final String PASSWORD_POLICY_SELECT_STATEMENT = "SELECT ID,MINLENGTH,MAXLENGTH,LOWERCASE,UPPERCASE,DIGITS,SPECIALCHAR,ATTEMPTS,DURATION,EXPIRATION,USERNAME,SIMPLEPASSWORDS FROM MXK_PASSWORD_POLICY ";
-
-    protected PasswordPolicy passwordPolicy;
-
     protected JdbcTemplate jdbcTemplate;
-
+    
     protected boolean provisioning;
+    
+    @Autowired
+    protected PasswordPolicyValidator passwordPolicyValidator;
+    
+    @Autowired
+    protected LoginService loginService;
+    
+    @Autowired
+    protected LoginHistoryService loginHistoryService;
 
     @Autowired
     @Qualifier("remeberMeService")
@@ -103,70 +73,16 @@ public abstract class AbstractAuthenticationRealm {
         this.jdbcTemplate = jdbcTemplate;
     }
 
-    public PasswordPolicy getPasswordPolicy() {
-        if (passwordPolicy == null) {
-            passwordPolicy = jdbcTemplate.queryForObject(PASSWORD_POLICY_SELECT_STATEMENT,
-                    new PasswordPolicyRowMapper());
-            _logger.debug("query PasswordPolicy : " + passwordPolicy);
-        }
-        return passwordPolicy;
+    public PasswordPolicyValidator getPasswordPolicyValidator() {
+        return passwordPolicyValidator;
     }
 
-    public boolean passwordPolicyValid(UserInfo userInfo) {
-        /*
-         * check login attempts fail times
-         */
-        if (userInfo.getBadPasswordCount() >= getPasswordPolicy().getAttempts()) {
-            _logger.debug("PasswordPolicy : " + passwordPolicy);
-            _logger.debug("login Attempts is " + userInfo.getBadPasswordCount());
-            lockUser(userInfo);
-
-            throw new BadCredentialsException(
-                    WebContext.getI18nValue("login.error.attempts") + " " + userInfo.getBadPasswordCount());
-        }
-
-        if (userInfo.getPasswordSetType() != ConstantsPasswordSetType.PASSWORD_NORMAL) {
-            WebContext.getSession().setAttribute(WebConstants.CURRENT_LOGIN_USER_PASSWORD_SET_TYPE,
-                    userInfo.getPasswordSetType());
-            return true;
-        } else {
-            WebContext.getSession().setAttribute(WebConstants.CURRENT_LOGIN_USER_PASSWORD_SET_TYPE,
-                    ConstantsPasswordSetType.PASSWORD_NORMAL);
-        }
-
-        /*
-         * check password is Expired,if Expiration equals 0,not need check
-         */
-        if (getPasswordPolicy().getExpiration() > 0) {
-
-            String passwordLastSetTimeString = userInfo.getPasswordLastSetTime().substring(0, 19);
-            _logger.info("last password set date " + passwordLastSetTimeString);
-
-            DateTime currentdateTime = new DateTime();
-            DateTime changePwdDateTime = DateTime.parse(passwordLastSetTimeString,
-                    DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
-            Duration duration = new Duration(changePwdDateTime, currentdateTime);
-            int intDuration = Integer.parseInt(duration.getStandardDays() + "");
-            _logger.debug("validate duration " + intDuration);
-            _logger.debug("validate result " + (intDuration <= getPasswordPolicy().getExpiration()));
-            if (intDuration > getPasswordPolicy().getExpiration()) {
-                WebContext.getSession().setAttribute(WebConstants.CURRENT_LOGIN_USER_PASSWORD_SET_TYPE,
-                        ConstantsPasswordSetType.PASSWORD_EXPIRED);
-            }
-        }
-
-        return true;
+    public LoginService getUserInfoLoginService() {
+        return loginService;
     }
 
     public UserInfo loadUserInfo(String username, String password) {
-        List<UserInfo> listUserInfo = jdbcTemplate.query(DEFAULT_USERINFO_SELECT_STATEMENT, new UserInfoRowMapper(),
-                username);
-        UserInfo userInfo = null;
-        if (listUserInfo != null && listUserInfo.size() > 0) {
-            userInfo = listUserInfo.get(0);
-        }
-        _logger.debug("load UserInfo : " + userInfo);
-        return userInfo;
+        return loginService.loadUserInfo(username, password);
     }
 
     public abstract boolean passwordMatches(UserInfo userInfo, String password);
@@ -179,90 +95,9 @@ public abstract class AbstractAuthenticationRealm {
         }
     }
 
-    /**
-     * 閿佸畾鐢ㄦ埛锛歩slock锛�1 鐢ㄦ埛瑙i攣 2 鐢ㄦ埛閿佸畾
-     * 
-     * @param userInfo
-     */
-    public void lockUser(UserInfo userInfo) {
-        try {
-            if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) {
-                jdbcTemplate.update(LOCK_USER_UPDATE_STATEMENT,
-                        new Object[] { ConstantsStatus.LOCK, new Date(), userInfo.getId() },
-                        new int[] { Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR });
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * 閿佸畾鐢ㄦ埛锛歩slock锛�1 鐢ㄦ埛瑙i攣 2 鐢ㄦ埛閿佸畾
-     * 
-     * @param userInfo
-     */
-    public void unlockUser(UserInfo userInfo) {
-        try {
-            if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) {
-                jdbcTemplate.update(UNLOCK_USER_UPDATE_STATEMENT,
-                        new Object[] { ConstantsStatus.ACTIVE, new Date(), userInfo.getId() },
-                        new int[] { Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR });
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * 閲嶇疆閿欒瀵嗙爜娆℃暟鍜岃В閿佺敤鎴�
-     * 
-     * @param userInfo
-     */
-    public void resetBadPasswordCountAndLockout(UserInfo userInfo) {
-        try {
-            if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) {
-                jdbcTemplate.update(BADPASSWORDCOUNT_RESET_UPDATE_STATEMENT,
-                        new Object[] { 0, ConstantsStatus.ACTIVE, new Date(), userInfo.getId() },
-                        new int[] { Types.INTEGER, Types.INTEGER, Types.TIMESTAMP, Types.VARCHAR });
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-            _logger.error(e.getMessage());
-        }
-    }
-
-    /**
-     * 鏇存柊閿欒瀵嗙爜娆℃暟
-     * 
-     * @param userInfo
-     */
-    public void setBadPasswordCount(UserInfo userInfo) {
-        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 });
-                insertLoginHistory(userInfo, ConstantsLoginType.LOCAL, "", "xe00000004", "password error");
-            }
-        } catch (Exception e) {
-            e.printStackTrace();
-            _logger.error(e.getMessage());
-        }
-    }
 
     public List<Groups> queryGroups(UserInfo userInfo) {
-        List<Groups> listGroups = jdbcTemplate.query(GROUPS_SELECT_STATEMENT, new RowMapper<Groups>() {
-            public Groups mapRow(ResultSet rs, int rowNum) throws SQLException {
-                Groups group = new Groups(rs.getString("ID"), rs.getString("NAME"), 0);
-
-                return group;
-            }
-        }, userInfo.getId());
-
-        _logger.debug("list Groups  " + listGroups);
-        return listGroups;
+       return loginService.queryGroups(userInfo);
     }
 
     /**
@@ -272,18 +107,7 @@ public abstract class AbstractAuthenticationRealm {
      * @return ArrayList<GrantedAuthority>
      */
     public ArrayList<GrantedAuthority> grantAuthority(UserInfo userInfo) {
-        // query roles for user
-        List<Groups> listGroups = queryGroups(userInfo);
-
-        // set role for spring security
-        ArrayList<GrantedAuthority> grantedAuthority = new ArrayList<GrantedAuthority>();
-        grantedAuthority.add(new SimpleGrantedAuthority("ROLE_USER"));
-        for (Groups group : listGroups) {
-            grantedAuthority.add(new SimpleGrantedAuthority(group.getId()));
-        }
-        _logger.debug("Authority : " + grantedAuthority);
-
-        return grantedAuthority;
+        return loginService.grantAuthority(userInfo);
     }
 
     /**
@@ -296,10 +120,10 @@ public abstract class AbstractAuthenticationRealm {
      * @param message
      */
     public boolean insertLoginHistory(UserInfo userInfo, String type, String provider, String code, String message) {
-        Date loginDate = new Date();
         String sessionId = WebContext.genId();
         WebContext.setAttribute(WebConstants.CURRENT_USER_SESSION_ID, sessionId);
-        String ipAddress = WebContext.getRequestIpAddress();
+        userInfo.setLastLoginTime(DateUtils.formatDateTime(new Date()));
+        userInfo.setLastLoginIp(WebContext.getRequestIpAddress());
         String platform = "";
         String browser = "";
         String userAgent = WebContext.getRequest().getHeader("User-Agent");
@@ -337,43 +161,38 @@ public abstract class AbstractAuthenticationRealm {
 
         }
 
-        jdbcTemplate.update(HISTORY_LOGIN_INSERT_STATEMENT,
-                new Object[] { WebContext.genId(), sessionId, userInfo.getId(), userInfo.getUsername(),
-                        userInfo.getDisplayName(), type, message, code, provider, ipAddress, browser, platform,
-                        "Browser", loginDate },
-                new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
-                        Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
-                        Types.VARCHAR, Types.TIMESTAMP });
-
-        userInfo.setLastLoginTime(DateUtils.formatDateTime(loginDate));
-
-        jdbcTemplate.update(LOGIN_USERINFO_UPDATE_STATEMENT,
-                new Object[] { loginDate, ipAddress, userInfo.getLoginCount() + 1, userInfo.getId() },
-                new int[] { Types.TIMESTAMP, Types.VARCHAR, Types.INTEGER, Types.VARCHAR });
+        loginHistoryService.login(userInfo,sessionId, type, message, code, provider, browser, platform);
+        
+        loginService.setLastLoginInfo(userInfo);
 
         return true;
     }
 
+    /**
+     * logout user and remove RemeberMe token 
+     * @param response
+     * @return
+     */
     public boolean logout(HttpServletResponse response) {
         if (isAuthenticated()) {
             Object sessionIdAttribute = WebContext.getAttribute(WebConstants.CURRENT_USER_SESSION_ID);
             UserInfo userInfo = WebContext.getUserInfo();
-            Date logoutDateTime = new Date();
+            userInfo.setLastLogoffTime(DateUtils.formatDateTime(new Date()));
+            
             if (sessionIdAttribute != null) {
                 remeberMeService.removeRemeberMe(response);
 
-                jdbcTemplate.update(HISTORY_LOGOUT_UPDATE_STATEMENT,
-                        new Object[] { logoutDateTime, sessionIdAttribute.toString() },
-                        new int[] { Types.TIMESTAMP, Types.VARCHAR });
+                loginHistoryService.logoff(userInfo.getLastLogoffTime(), sessionIdAttribute.toString());
             }
-
-            jdbcTemplate.update(LOGOUT_USERINFO_UPDATE_STATEMENT, new Object[] { logoutDateTime, userInfo.getId() },
-                    new int[] { Types.TIMESTAMP, Types.VARCHAR });
-
+            
+            loginService.setLastLogoffInfo(userInfo);
+            
             _logger.debug("Session " + WebContext.getAttribute(WebConstants.CURRENT_USER_SESSION_ID) + ", user "
-                    + userInfo.getUsername() + " Logout, datetime " + DateUtils.toUtc(logoutDateTime) + " .");
+                    + userInfo.getUsername() + " Logout, datetime " + userInfo.getLastLogoffTime() + " .");
         }
         return true;
 
     }
+    
+    
 }

+ 3 - 1
maxkey-core/src/main/java/org/maxkey/authn/realm/jdbc/DefaultJdbcAuthenticationRealm.java

@@ -18,6 +18,7 @@
 package org.maxkey.authn.realm.jdbc;
 
 import org.maxkey.authn.realm.AbstractAuthenticationRealm;
+import org.maxkey.constants.ConstantsLoginType;
 import org.maxkey.crypto.password.PasswordReciprocal;
 import org.maxkey.domain.UserInfo;
 import org.maxkey.web.WebContext;
@@ -58,7 +59,8 @@ public class DefaultJdbcAuthenticationRealm extends AbstractAuthenticationRealm
         passwordMatches = passwordEncoder.matches(password,userInfo.getPassword());
         _logger.debug("passwordvalid : " + passwordMatches);
         if (!passwordMatches) {
-            setBadPasswordCount(userInfo);
+            passwordPolicyValidator.setBadPasswordCount(userInfo);
+            insertLoginHistory(userInfo, ConstantsLoginType.LOCAL, "", "xe00000004", "password error");
             throw new BadCredentialsException(WebContext.getI18nValue("login.error.password"));
         }
         return passwordMatches;

+ 18 - 0
maxkey-core/src/main/java/org/maxkey/autoconfigure/ApplicationAutoConfiguration.java

@@ -34,6 +34,7 @@ import org.maxkey.crypto.keystore.KeyStoreLoader;
 import org.maxkey.crypto.password.PasswordReciprocal;
 import org.maxkey.crypto.password.SM3PasswordEncoder;
 import org.maxkey.crypto.password.StandardPasswordEncoder;
+import org.maxkey.persistence.db.PasswordPolicyValidator;
 import org.maxkey.persistence.redis.RedisConnectionFactory;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -58,6 +59,8 @@ import org.springframework.security.crypto.password.NoOpPasswordEncoder;
 import org.springframework.security.crypto.password.PasswordEncoder;
 import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
 import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
+import org.maxkey.persistence.db.LoginService;
+import org.maxkey.persistence.db.LoginHistoryService;
 
 
 @Configuration
@@ -126,6 +129,21 @@ public class ApplicationAutoConfiguration  implements InitializingBean {
         return new DataSourceTransactionManager(dataSource);
     }
     
+    @Bean(name = "passwordPolicyValidator")
+    public PasswordPolicyValidator passwordPolicyValidator(JdbcTemplate jdbcTemplate) {
+        return new PasswordPolicyValidator(jdbcTemplate);
+    }
+    
+    @Bean(name = "loginService")
+    public LoginService LoginService(JdbcTemplate jdbcTemplate) {
+        return new LoginService(jdbcTemplate);
+    }
+    @Bean(name = "loginHistoryService")
+    public LoginHistoryService loginHistoryService(JdbcTemplate jdbcTemplate) {
+        return new LoginHistoryService(jdbcTemplate);
+    }
+    
+    
     /**
      * Authentication Password Encoder .
      * @return

+ 2 - 0
maxkey-core/src/main/java/org/maxkey/constants/ConstantsStatus.java

@@ -43,5 +43,7 @@ public final class ConstantsStatus {
     public static final int STOP = 12;
 
     public static final int APPROVED = 13;
+    
+    public static final int QUITED = 14;
 
 }

+ 6 - 2
maxkey-core/src/main/java/org/maxkey/crypto/password/PasswordGen.java

@@ -34,16 +34,19 @@ public class PasswordGen {
     public static String CHAR_DEFAULT = CHAR_LOWERCASE + CHAR_NUMBERS + CHAR_UPPERCASE;
     private Random random = new Random();
     public static int DEFAULT_LENGTH = 8;
+    private int length;
 
     public PasswordGen() {
-
+        length = DEFAULT_LENGTH;
     }
 
     public String gen() {
-        return gen(DEFAULT_LENGTH);
+        this.length = DEFAULT_LENGTH;
+        return gen(length);
     }
 
     public String gen(int length) {
+        this.length = length;
         return gen(CHAR_DEFAULT, length);
     }
 
@@ -61,6 +64,7 @@ public class PasswordGen {
         password.append(gen(CHAR_NUMBERS, numbers));
         password.append(gen(CHAR_UPPERCASE, upperCase));
         password.append(gen(CHAR_SPECIAL, special));
+        password.append(gen(CHAR_DEFAULT, length - lowerCase - upperCase - numbers -special));
         // random generator String by sequence password
         return gen(password.toString(), password.length());
     }

+ 43 - 0
maxkey-core/src/main/java/org/maxkey/persistence/db/LoginHistoryService.java

@@ -0,0 +1,43 @@
+package org.maxkey.persistence.db;
+
+import java.sql.Types;
+
+import org.maxkey.domain.UserInfo;
+import org.maxkey.web.WebContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+public class LoginHistoryService {
+    private static Logger _logger = LoggerFactory.getLogger(LoginHistoryService.class);
+    
+    private static final String HISTORY_LOGIN_INSERT_STATEMENT = "INSERT INTO MXK_HISTORY_LOGIN (ID , SESSIONID , UID , USERNAME , DISPLAYNAME , LOGINTYPE , MESSAGE , CODE , PROVIDER , SOURCEIP , BROWSER , PLATFORM , APPLICATION , LOGINURL )VALUES( ? , ? , ? , ? , ?, ? , ? , ?, ? , ? , ?, ? , ? , ?)";
+
+    private static final String HISTORY_LOGOUT_UPDATE_STATEMENT = "UPDATE MXK_HISTORY_LOGIN SET LOGOUTTIME = ?  WHERE  SESSIONID = ?";
+
+    protected JdbcTemplate jdbcTemplate;
+    
+    public LoginHistoryService(JdbcTemplate jdbcTemplate) {
+        this.jdbcTemplate = jdbcTemplate;
+    }
+    
+    public void login(UserInfo userInfo,String sessionId,
+            String type, String message, String code, String provider,String browser, String platform) {
+        jdbcTemplate.update(HISTORY_LOGIN_INSERT_STATEMENT,
+                new Object[] { WebContext.genId(), sessionId, userInfo.getId(), userInfo.getUsername(),
+                        userInfo.getDisplayName(), type, message, code, provider, userInfo.getLastLoginIp(), browser, platform,
+                        "Browser", userInfo.getLastLoginTime() },
+                new int[] { Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
+                        Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
+                        Types.VARCHAR, Types.TIMESTAMP });
+        
+
+    }
+    
+    public void logoff(String lastLogoffTime,String sessionId) {
+        _logger.debug(" sessionId " +sessionId +" , lastlogofftime " + lastLogoffTime);
+        jdbcTemplate.update(HISTORY_LOGOUT_UPDATE_STATEMENT,
+                new Object[] { lastLogoffTime, sessionId },                           
+                new int[] { Types.TIMESTAMP, Types.VARCHAR });
+    }
+}

+ 184 - 0
maxkey-core/src/main/java/org/maxkey/persistence/db/LoginService.java

@@ -0,0 +1,184 @@
+package org.maxkey.persistence.db;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.maxkey.constants.ConstantsStatus;
+import org.maxkey.domain.Groups;
+import org.maxkey.domain.UserInfo;
+import org.maxkey.util.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.RowMapper;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+
+public class LoginService {
+    private static Logger _logger = LoggerFactory.getLogger(LoginService.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 LOGOUT_USERINFO_UPDATE_STATEMENT = "UPDATE MXK_USERINFO SET LASTLOGOFFTIME = ? , ONLINE = "
+            + UserInfo.ONLINE.OFFLINE + "  WHERE ID = ?";
+
+    private static final String GROUPS_SELECT_STATEMENT = "SELECT DISTINCT G.ID,G.NAME 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 = ?";
+    
+    protected JdbcTemplate jdbcTemplate;
+    
+    public LoginService(){
+        
+    }
+    
+    public LoginService(JdbcTemplate jdbcTemplate){
+        this.jdbcTemplate=jdbcTemplate;
+    }
+    
+    public UserInfo loadUserInfo(String username, String password) {
+        List<UserInfo> listUserInfo = jdbcTemplate.query(DEFAULT_USERINFO_SELECT_STATEMENT, new UserInfoRowMapper(),
+                username);
+        UserInfo userInfo = null;
+        if (listUserInfo != null && listUserInfo.size() > 0) {
+            userInfo = listUserInfo.get(0);
+        }
+        _logger.debug("load UserInfo : " + userInfo);
+        return userInfo;
+    }
+    
+    
+
+    /**
+     * 閿佸畾鐢ㄦ埛锛歩slock锛�1 鐢ㄦ埛瑙i攣 2 鐢ㄦ埛閿佸畾
+     * 
+     * @param userInfo
+     */
+    public void lockUser(UserInfo userInfo) {
+        try {
+            if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) {
+                jdbcTemplate.update(LOCK_USER_UPDATE_STATEMENT,
+                        new Object[] { ConstantsStatus.LOCK, new Date(), userInfo.getId() },
+                        new int[] { Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR });
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 閿佸畾鐢ㄦ埛锛歩slock锛�1 鐢ㄦ埛瑙i攣 2 鐢ㄦ埛閿佸畾
+     * 
+     * @param userInfo
+     */
+    public void unlockUser(UserInfo userInfo) {
+        try {
+            if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) {
+                jdbcTemplate.update(UNLOCK_USER_UPDATE_STATEMENT,
+                        new Object[] { ConstantsStatus.ACTIVE, new Date(), userInfo.getId() },
+                        new int[] { Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR });
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+    * reset BadPasswordCount And Lockout
+     * 
+     * @param userInfo
+     */
+    public void resetBadPasswordCountAndLockout(UserInfo userInfo) {
+        try {
+            if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) {
+                jdbcTemplate.update(BADPASSWORDCOUNT_RESET_UPDATE_STATEMENT,
+                        new Object[] { 0, ConstantsStatus.ACTIVE, new Date(), userInfo.getId() },
+                        new int[] { Types.INTEGER, Types.INTEGER, Types.TIMESTAMP, Types.VARCHAR });
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            _logger.error(e.getMessage());
+        }
+    }
+
+    /**
+     * if login password is error ,BadPasswordCount++ and set bad date
+     * 
+     * @param userInfo
+     */
+    public void setBadPasswordCount(UserInfo userInfo) {
+        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 });
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            _logger.error(e.getMessage());
+        }
+    }
+    
+    public List<Groups> queryGroups(UserInfo userInfo) {
+        List<Groups> listGroups = jdbcTemplate.query(GROUPS_SELECT_STATEMENT, new RowMapper<Groups>() {
+            public Groups mapRow(ResultSet rs, int rowNum) throws SQLException {
+                Groups group = new Groups(rs.getString("ID"), rs.getString("NAME"), 0);
+
+                return group;
+            }
+        }, userInfo.getId());
+
+        _logger.debug("list Groups  " + listGroups);
+        return listGroups;
+    }
+
+    /**
+     * grant Authority by userinfo
+     * 
+     * @param userInfo
+     * @return ArrayList<GrantedAuthority>
+     */
+    public ArrayList<GrantedAuthority> grantAuthority(UserInfo userInfo) {
+        // query roles for user
+        List<Groups> listGroups = queryGroups(userInfo);
+
+        // set role for spring security
+        ArrayList<GrantedAuthority> grantedAuthority = new ArrayList<GrantedAuthority>();
+        grantedAuthority.add(new SimpleGrantedAuthority("ROLE_USER"));
+        for (Groups group : listGroups) {
+            grantedAuthority.add(new SimpleGrantedAuthority(group.getId()));
+        }
+        _logger.debug("Authority : " + grantedAuthority);
+
+        return grantedAuthority;
+    }
+    
+    
+    public void setLastLoginInfo(UserInfo userInfo) {
+        jdbcTemplate.update(LOGIN_USERINFO_UPDATE_STATEMENT,
+                new Object[] { userInfo.getLastLoginTime(), userInfo.getLastLoginIp(), userInfo.getLoginCount() + 1, userInfo.getId() },
+                new int[] { Types.TIMESTAMP, Types.VARCHAR, Types.INTEGER, Types.VARCHAR });
+    }
+    
+    
+    public void setLastLogoffInfo(UserInfo userInfo) {
+        jdbcTemplate.update(LOGOUT_USERINFO_UPDATE_STATEMENT, new Object[] { userInfo.getLastLogoffTime(), userInfo.getId() },
+                new int[] { Types.TIMESTAMP, Types.VARCHAR });
+   
+    }
+}

+ 316 - 0
maxkey-core/src/main/java/org/maxkey/persistence/db/PasswordPolicyValidator.java

@@ -0,0 +1,316 @@
+package org.maxkey.persistence.db;
+
+import java.io.InputStreamReader;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.Date;
+
+import org.ehcache.UserManagedCache;
+import org.ehcache.config.builders.ExpiryPolicyBuilder;
+import org.ehcache.config.builders.UserManagedCacheBuilder;
+import org.joda.time.DateTime;
+import org.joda.time.Duration;
+import org.joda.time.format.DateTimeFormat;
+import org.maxkey.constants.ConstantsPasswordSetType;
+import org.maxkey.constants.ConstantsProperties;
+import org.maxkey.constants.ConstantsStatus;
+import org.maxkey.constants.ConstantsTimeInterval;
+import org.maxkey.domain.PasswordPolicy;
+import org.maxkey.domain.UserInfo;
+import org.maxkey.util.StringUtils;
+import org.maxkey.web.WebConstants;
+import org.maxkey.web.WebContext;
+import org.passay.CharacterRule;
+import org.passay.DictionaryRule;
+import org.passay.EnglishCharacterData;
+import org.passay.LengthRule;
+import org.passay.PasswordData;
+import org.passay.PasswordValidator;
+import org.passay.Rule;
+import org.passay.RuleResult;
+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.security.authentication.BadCredentialsException;
+
+public class PasswordPolicyValidator {
+    private static Logger _logger = LoggerFactory.getLogger(PasswordPolicyValidator.class);
+
+    public static final String topWeakPasswordPropertySource      = 
+            "classpath:/org/maxkey/persistence/db/top_weak_password.txt";
+    protected static final UserManagedCache<String, PasswordPolicy> passwordPolicyStore = 
+            UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, PasswordPolicy.class)
+                .withExpiry(
+                    ExpiryPolicyBuilder.timeToLiveExpiration(
+                            java.time.Duration.ofMinutes(ConstantsTimeInterval.ONE_HOUR)
+                    )
+                )
+                .build(true);
+    
+    protected PasswordPolicy passwordPolicy;
+    
+    ArrayList <Rule> passwordPolicyRuleList;
+    
+    protected JdbcTemplate jdbcTemplate;
+    
+    private static final String PASSWORD_POLICY_KEY = "PASSWORD_POLICY_KEY";
+    private static final String LOCK_USER_UPDATE_STATEMENT = "UPDATE MXK_USERINFO SET ISLOCKED = ?  , UNLOCKTIME = ? WHERE ID = ?";
+
+    private static final String PASSWORD_POLICY_SELECT_STATEMENT = "SELECT ID,MINLENGTH,MAXLENGTH,LOWERCASE,UPPERCASE,DIGITS,SPECIALCHAR,ATTEMPTS,DURATION,EXPIRATION,USERNAME,SIMPLEPASSWORDS FROM MXK_PASSWORD_POLICY ";
+
+    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) {
+        this.jdbcTemplate = jdbcTemplate;
+    }
+    
+    
+    public PasswordPolicy getPasswordPolicy() {
+        passwordPolicy = passwordPolicyStore.get(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);
+            
+            passwordPolicyRuleList = new ArrayList<Rule>();
+            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.getSimplePasswords().length()>0 ) {
+                try {
+                    ClassPathResource dictFile= 
+                            new ClassPathResource(
+                                    ConstantsProperties.classPathResource(topWeakPasswordPropertySource));
+                    
+                    Dictionary dictionary =new DictionaryBuilder().addReader(new InputStreamReader(dictFile.getInputStream())).build();
+                    passwordPolicyRuleList.add(new DictionaryRule(dictionary));
+                }catch(Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return passwordPolicy;
+    }
+    
+    /**
+     * validator .
+     * @param userInfo
+     * @return boolean
+     */
+   public boolean validator(UserInfo userInfo) {
+       
+       String password = userInfo.getPassword();
+       String username = userInfo.getUsername();
+       
+       if(password.equals("") || password==null){
+           _logger.debug("password  is Empty ");
+           return false;
+       }
+       
+       getPasswordPolicy();
+       
+       PasswordValidator validator = new PasswordValidator(passwordPolicyRuleList);
+       
+       RuleResult result = validator.validate(new PasswordData(username,password));
+       
+       if (result.isValid()) {
+           System.out.println("Password is valid");
+         } else {
+           System.out.println("Invalid password:");
+           for (String msg : validator.getMessages(result)) {
+             System.out.println(msg);
+           }
+         }
+       
+       return true;
+   }
+   
+   
+   /**
+    * passwordPolicyValid .
+    * @param userInfo
+    * @return boolean
+    */
+   public boolean passwordPolicyValid(UserInfo userInfo) {
+       
+       getPasswordPolicy();
+       
+        /*
+         * check login attempts fail times
+         */
+        if (userInfo.getBadPasswordCount() >= passwordPolicy.getAttempts()) {
+            _logger.debug("PasswordPolicy : " + passwordPolicy);
+            _logger.debug("login Attempts is " + userInfo.getBadPasswordCount());
+            lockUser(userInfo);
+
+            throw new BadCredentialsException(
+                                userInfo.getUsername() + " " +
+                                WebContext.getI18nValue("login.error.attempts") + " " +
+                                userInfo.getBadPasswordCount()
+                                );
+        }
+        
+        //locked
+        if(userInfo.getIsLocked()==ConstantsStatus.LOCK) {
+            throw new BadCredentialsException(
+                                userInfo.getUsername()+ " "+
+                                WebContext.getI18nValue("login.error.locked")
+                                );
+        }
+        // inactive
+        if(userInfo.getStatus()!=ConstantsStatus.ACTIVE) {
+            throw new BadCredentialsException(
+                                userInfo.getUsername()+ " status "+ 
+                                userInfo.getStatus() +
+                                WebContext.getI18nValue("login.error.inactive") 
+                                );
+        }
+
+        if (userInfo.getPasswordSetType() != ConstantsPasswordSetType.PASSWORD_NORMAL) {
+            WebContext.getSession().setAttribute(WebConstants.CURRENT_LOGIN_USER_PASSWORD_SET_TYPE,
+                    userInfo.getPasswordSetType());
+            return true;
+        } else {
+            WebContext.getSession().setAttribute(WebConstants.CURRENT_LOGIN_USER_PASSWORD_SET_TYPE,
+                    ConstantsPasswordSetType.PASSWORD_NORMAL);
+        }
+
+        /*
+         * check password is Expired,Expiration is Expired date ,if Expiration equals 0,not need check
+         *
+         */
+        if (passwordPolicy.getExpiration() > 0) {
+
+            String passwordLastSetTimeString = userInfo.getPasswordLastSetTime().substring(0, 19);
+            _logger.info("last password set date " + passwordLastSetTimeString);
+
+            DateTime currentdateTime = new DateTime();
+            DateTime changePwdDateTime = DateTime.parse(passwordLastSetTimeString,
+                    DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
+            Duration duration = new Duration(changePwdDateTime, currentdateTime);
+            int intDuration = Integer.parseInt(duration.getStandardDays() + "");
+            _logger.debug("validate duration " + intDuration);
+            _logger.debug("validate result " + (intDuration <= passwordPolicy.getExpiration()));
+            if (intDuration > passwordPolicy.getExpiration()) {
+                WebContext.getSession().setAttribute(WebConstants.CURRENT_LOGIN_USER_PASSWORD_SET_TYPE,
+                        ConstantsPasswordSetType.PASSWORD_EXPIRED);
+            }
+        }
+
+        return true;
+    }
+   
+   
+   /**
+    * lockUser
+    * 
+    * @param userInfo
+    */
+   public void lockUser(UserInfo userInfo) {
+       try {
+           if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) {
+               jdbcTemplate.update(LOCK_USER_UPDATE_STATEMENT,
+                       new Object[] { ConstantsStatus.LOCK, new Date(), userInfo.getId() },
+                       new int[] { Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR });
+           }
+       } catch (Exception e) {
+           e.printStackTrace();
+       }
+   }
+   
+
+   /**
+    * unlockUser
+    * 
+    * @param userInfo
+    */
+   public void unlockUser(UserInfo userInfo) {
+       try {
+           if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) {
+               jdbcTemplate.update(UNLOCK_USER_UPDATE_STATEMENT,
+                       new Object[] { ConstantsStatus.ACTIVE, new Date(), userInfo.getId() },
+                       new int[] { Types.VARCHAR, Types.TIMESTAMP, Types.VARCHAR });
+           }
+       } catch (Exception e) {
+           e.printStackTrace();
+       }
+   }
+
+   /**
+   * reset BadPasswordCount And Lockout
+    * 
+    * @param userInfo
+    */
+   public void resetBadPasswordCountAndLockout(UserInfo userInfo) {
+       try {
+           if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) {
+               jdbcTemplate.update(BADPASSWORDCOUNT_RESET_UPDATE_STATEMENT,
+                       new Object[] { 0, ConstantsStatus.ACTIVE, new Date(), userInfo.getId() },
+                       new int[] { Types.INTEGER, Types.INTEGER, Types.TIMESTAMP, Types.VARCHAR });
+           }
+       } catch (Exception e) {
+           e.printStackTrace();
+           _logger.error(e.getMessage());
+       }
+   }
+
+   /**
+    * if login password is error ,BadPasswordCount++ and set bad date
+    * 
+    * @param userInfo
+    */
+   public void setBadPasswordCount(UserInfo userInfo) {
+       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 });
+               
+           }
+       } catch (Exception e) {
+           e.printStackTrace();
+           _logger.error(e.getMessage());
+       }
+   }
+   
+   
+   
+   public void setPasswordPolicy(PasswordPolicy passwordPolicy) {
+    this.passwordPolicy = passwordPolicy;
+   }
+
+ 
+   
+}

+ 1100 - 0
maxkey-core/src/main/resources/org/maxkey/persistence/db/top_weak_password.txt

@@ -0,0 +1,1100 @@
+123456
+password
+12345678
+qwerty
+123456789
+12345
+1234
+111111
+1234567
+dragon
+123123
+baseball
+abc123
+football
+monkey
+letmein
+696969
+shadow
+master
+666666
+qwertyuiop
+123321
+mustang
+1234567890
+michael
+654321
+pussy
+superman
+1qaz2wsx
+7777777
+fuckyou
+121212
+000000
+qazwsx
+123qwe
+killer
+trustno1
+jordan
+jennifer
+zxcvbnm
+asdfgh
+hunter
+buster
+soccer
+harley
+batman
+andrew
+tigger
+sunshine
+iloveyou
+fuckme
+2000
+charlie
+robert
+thomas
+hockey
+ranger
+daniel
+starwars
+klaster
+112233
+george
+asshole
+computer
+michelle
+jessica
+pepper
+1111
+zxcvbn
+555555
+11111111
+131313
+freedom
+777777
+pass
+fuck
+maggie
+159753
+aaaaaa
+ginger
+princess
+joshua
+cheese
+amanda
+summer
+love
+ashley
+6969
+nicole
+chelsea
+biteme
+matthew
+access
+yankees
+987654321
+dallas
+austin
+thunder
+taylor
+matrix
+william
+corvette
+hello
+martin
+heather
+secret
+fucker
+merlin
+diamond
+1234qwer
+gfhjkm
+hammer
+silver
+222222
+88888888
+anthony
+justin
+test
+bailey
+q1w2e3r4t5
+patrick
+internet
+scooter
+orange
+11111
+golfer
+cookie
+richard
+samantha
+bigdog
+guitar
+jackson
+whatever
+mickey
+chicken
+sparky
+snoopy
+maverick
+phoenix
+camaro
+sexy
+peanut
+morgan
+welcome
+falcon
+cowboy
+ferrari
+samsung
+andrea
+smokey
+steelers
+joseph
+mercedes
+dakota
+arsenal
+eagles
+melissa
+boomer
+booboo
+spider
+nascar
+monster
+tigers
+yellow
+xxxxxx
+123123123
+gateway
+marina
+diablo
+bulldog
+qwer1234
+compaq
+purple
+hardcore
+banana
+junior
+hannah
+123654
+porsche
+lakers
+iceman
+money
+cowboys
+987654
+london
+tennis
+999999
+ncc1701
+coffee
+scooby
+0000
+miller
+boston
+q1w2e3r4
+fuckoff
+brandon
+yamaha
+chester
+mother
+forever
+johnny
+edward
+333333
+oliver
+redsox
+player
+nikita
+knight
+fender
+barney
+midnight
+please
+brandy
+chicago
+badboy
+iwantu
+slayer
+rangers
+charles
+angel
+flower
+bigdaddy
+rabbit
+wizard
+bigdick
+jasper
+enter
+rachel
+chris
+steven
+winner
+adidas
+victoria
+natasha
+1q2w3e4r
+jasmine
+winter
+prince
+panties
+marine
+ghbdtn
+fishing
+cocacola
+casper
+james
+232323
+raiders
+888888
+marlboro
+gandalf
+asdfasdf
+crystal
+87654321
+12344321
+sexsex
+golden
+blowme
+bigtits
+8675309
+panther
+lauren
+angela
+bitch
+spanky
+thx1138
+angels
+madison
+winston
+shannon
+mike
+toyota
+blowjob
+jordan23
+canada
+sophie
+Password
+apples
+dick
+tiger
+razz
+123abc
+pokemon
+qazxsw
+55555
+qwaszx
+muffin
+johnson
+murphy
+cooper
+jonathan
+liverpoo
+david
+danielle
+159357
+jackie
+1990
+123456a
+789456
+turtle
+horny
+abcd1234
+scorpion
+qazwsxedc
+101010
+butter
+carlos
+password1
+dennis
+slipknot
+qwerty123
+booger
+asdf
+1991
+black
+startrek
+12341234
+cameron
+newyork
+rainbow
+nathan
+john
+1992
+rocket
+viking
+redskins
+butthead
+asdfghjkl
+1212
+sierra
+peaches
+gemini
+doctor
+wilson
+sandra
+helpme
+qwertyui
+victor
+florida
+dolphin
+pookie
+captain
+tucker
+blue
+liverpool
+theman
+bandit
+dolphins
+maddog
+packers
+jaguar
+lovers
+nicholas
+united
+tiffany
+maxwell
+zzzzzz
+nirvana
+jeremy
+suckit
+stupid
+porn
+monica
+elephant
+giants
+jackass
+hotdog
+rosebud
+success
+debbie
+mountain
+444444
+xxxxxxxx
+warrior
+1q2w3e4r5t
+q1w2e3
+123456q
+albert
+metallic
+lucky
+azerty
+7777
+shithead
+alex
+bond007
+alexis
+1111111
+samson
+5150
+willie
+scorpio
+bonnie
+gators
+benjamin
+voodoo
+driver
+dexter
+2112
+jason
+calvin
+freddy
+212121
+creative
+12345a
+sydney
+rush2112
+1989
+asdfghjk
+red123
+bubba
+4815162342
+passw0rd
+trouble
+gunner
+happy
+fucking
+gordon
+legend
+jessie
+stella
+qwert
+eminem
+arthur
+apple
+nissan
+bullshit
+bear
+america
+1qazxsw2
+nothing
+parker
+4444
+rebecca
+qweqwe
+garfield
+01012011
+beavis
+69696969
+jack
+asdasd
+december
+2222
+102030
+252525
+11223344
+magic
+apollo
+skippy
+315475
+girls
+kitten
+golf
+copper
+braves
+shelby
+godzilla
+beaver
+fred
+tomcat
+august
+buddy
+airborne
+1993
+1988
+lifehack
+qqqqqq
+brooklyn
+animal
+platinum
+phantom
+online
+xavier
+darkness
+blink182
+power
+fish
+green
+789456123
+voyager
+police
+travis
+12qwaszx
+heaven
+snowball
+lover
+abcdef
+00000
+pakistan
+007007
+walter
+playboy
+blazer
+cricket
+sniper
+hooters
+donkey
+willow
+loveme
+saturn
+therock
+redwings
+bigboy
+pumpkin
+trinity
+williams
+tits
+nintendo
+digital
+destiny
+topgun
+runner
+marvin
+guinness
+chance
+bubbles
+testing
+fire
+november
+minecraft
+asdf1234
+lasvegas
+sergey
+broncos
+cartman
+private
+celtic
+birdie
+little
+cassie
+babygirl
+donald
+beatles
+1313
+dickhead
+family
+12121212
+school
+louise
+gabriel
+eclipse
+fluffy
+147258369
+lol123
+explorer
+beer
+nelson
+flyers
+spencer
+scott
+lovely
+gibson
+doggie
+cherry
+andrey
+snickers
+buffalo
+pantera
+metallica
+member
+carter
+qwertyu
+peter
+alexande
+steve
+bronco
+paradise
+goober
+5555
+samuel
+montana
+mexico
+dreams
+michigan
+cock
+carolina
+yankee
+friends
+magnum
+surfer
+poopoo
+maximus
+genius
+cool
+vampire
+lacrosse
+asd123
+aaaa
+christin
+kimberly
+speedy
+sharon
+carmen
+111222
+kristina
+sammy
+racing
+ou812
+sabrina
+horses
+0987654321
+qwerty1
+pimpin
+baby
+stalker
+enigma
+147147
+star
+poohbear
+boobies
+147258
+simple
+bollocks
+12345q
+marcus
+brian
+1987
+qweasdzxc
+drowssap
+hahaha
+caroline
+barbara
+dave
+viper
+drummer
+action
+einstein
+bitches
+genesis
+hello1
+scotty
+friend
+forest
+010203
+hotrod
+google
+vanessa
+spitfire
+badger
+maryjane
+friday
+alaska
+1232323q
+tester
+jester
+jake
+champion
+billy
+147852
+rock
+hawaii
+badass
+chevy
+420420
+walker
+stephen
+eagle1
+bill
+1986
+october
+gregory
+svetlana
+pamela
+1984
+music
+shorty
+westside
+stanley
+diesel
+courtney
+242424
+kevin
+porno
+hitman
+boobs
+mark
+12345qwert
+reddog
+frank
+qwe123
+popcorn
+patricia
+aaaaaaaa
+1969
+teresa
+mozart
+buddha
+anderson
+paul
+melanie
+abcdefg
+security
+lucky1
+lizard
+denise
+3333
+a12345
+123789
+ruslan
+stargate
+simpsons
+scarface
+eagle
+123456789a
+thumper
+olivia
+naruto
+1234554321
+general
+cherokee
+a123456
+vincent
+Usuckballz1
+spooky
+qweasd
+cumshot
+free
+frankie
+douglas
+death
+1980
+loveyou
+kitty
+kelly
+veronica
+suzuki
+semperfi
+penguin
+mercury
+liberty
+spirit
+scotland
+natalie
+marley
+vikings
+system
+sucker
+king
+allison
+marshall
+1979
+098765
+qwerty12
+hummer
+adrian
+1985
+vfhbyf
+sandman
+rocky
+leslie
+antonio
+98765432
+4321
+softball
+passion
+mnbvcxz
+bastard
+passport
+horney
+rascal
+howard
+franklin
+bigred
+assman
+alexander
+homer
+redrum
+jupiter
+claudia
+55555555
+141414
+zaq12wsx
+shit
+patches
+nigger
+cunt
+raider
+infinity
+andre
+54321
+galore
+college
+russia
+kawasaki
+bishop
+77777777
+vladimir
+money1
+freeuser
+wildcats
+francis
+disney
+budlight
+brittany
+1994
+00000000
+sweet
+oksana
+honda
+domino
+bulldogs
+brutus
+swordfis
+norman
+monday
+jimmy
+ironman
+ford
+fantasy
+9999
+7654321
+PASSWORD
+hentai
+duncan
+cougar
+1977
+jeffrey
+house
+dancer
+brooke
+timothy
+super
+marines
+justice
+digger
+connor
+patriots
+karina
+202020
+molly
+everton
+tinker
+alicia
+rasdzv3
+poop
+pearljam
+stinky
+naughty
+colorado
+123123a
+water
+test123
+ncc1701d
+motorola
+ireland
+asdfg
+slut
+matt
+houston
+boogie
+zombie
+accord
+vision
+bradley
+reggie
+kermit
+froggy
+ducati
+avalon
+6666
+9379992
+sarah
+saints
+logitech
+chopper
+852456
+simpson
+madonna
+juventus
+claire
+159951
+zachary
+yfnfif
+wolverin
+warcraft
+hello123
+extreme
+penis
+peekaboo
+fireman
+eugene
+brenda
+123654789
+russell
+panthers
+georgia
+smith
+skyline
+jesus
+elizabet
+spiderma
+smooth
+pirate
+empire
+bullet
+8888
+virginia
+valentin
+psycho
+predator
+arizona
+134679
+mitchell
+alyssa
+vegeta
+titanic
+christ
+goblue
+fylhtq
+wolf
+mmmmmm
+kirill
+indian
+hiphop
+baxter
+awesome
+people
+danger
+roland
+mookie
+741852963
+1111111111
+dreamer
+bambam
+arnold
+1981
+skipper
+serega
+rolltide
+elvis
+changeme
+simon
+1q2w3e
+lovelove
+fktrcfylh
+denver
+tommy
+mine
+loverboy
+hobbes
+happy1
+alison
+nemesis
+chevelle
+cardinal
+burton
+wanker
+picard
+151515
+tweety
+michael1
+147852369
+12312
+xxxx
+windows
+turkey
+456789
+1974
+vfrcbv
+sublime
+1975
+galina
+bobby
+newport
+manutd
+daddy
+american
+alexandr
+1966
+victory
+rooster
+qqq111
+madmax
+electric
+bigcock
+a1b2c3
+wolfpack
+spring
+phpbb
+lalala
+suckme
+spiderman
+eric
+darkside
+classic
+raptor
+123456789q
+hendrix
+1982
+wombat
+avatar
+alpha
+zxc123
+crazy
+hard
+england
+brazil
+1978
+01011980
+wildcat
+polina
+freepass
+123456789
+a123456
+123456
+a123456789
+1234567890
+woaini1314
+qq123456
+abc123456
+123456a
+123456789a
+147258369
+zxcvbnm
+987654321
+12345678910
+abc123
+qq123456789
+123456789.
+7708801314520
+woaini
+5201314520
+q123456
+123456abc
+1233211234567
+123123123
+123456.
+0123456789
+asd123456
+aa123456
+135792468
+q123456789
+abcd123456
+12345678900
+woaini520
+woaini123
+zxcvbnm123
+1111111111111111
+w123456
+aini1314
+abc123456789
+111111
+woaini521
+qwertyuiop
+1314520520
+1234567891
+qwe123456
+asd123
+000000
+1472583690
+1357924680
+789456123
+123456789abc
+z123456
+1234567899
+aaa123456
+abcd1234
+www123456
+123456789q
+123abc
+qwe123
+w123456789
+7894561230
+123456qq
+zxc123456
+123456789qq
+1111111111
+111111111
+0000000000000000
+1234567891234567
+qazwsxedc
+qwerty
+123456..
+zxc123
+asdfghjkl
+0000000000
+1234554321
+123456q
+123456aa
+9876543210
+110120119
+qaz123456
+qq5201314
+123698745
+5201314
+000000000
+as123456
+123123
+5841314520
+z123456789
+52013145201314
+a123123
+caonima
+a5201314
+wang123456
+abcd123
+123456789..
+woaini1314520
+123456asd
+aa123456789
+741852963
+a12345678

+ 4 - 3
maxkey-core/src/test/java/org/maxkey/crypto/PasswordGenTest.java

@@ -28,10 +28,11 @@ public class PasswordGenTest {
 	public static void main(String[] args) {
 		// TODO Auto-generated method stub
 		PasswordGen gen=new PasswordGen();
+		System.out.println(gen.gen(2,2,2,1));
 		for(int i=1;i<100;i++){
-			System.out.println(gen.gen());
-			System.out.println(gen.gen(6));
-			System.out.println(gen.gen(2,2,2,2));
+			//System.out.println(gen.gen());
+			//System.out.println(gen.gen(6));
+			//System.out.println(gen.gen(2,2,2,0));
 		}
 		
 	}

+ 31 - 0
maxkey-core/src/test/java/org/maxkey/crypto/password/PasswordPolicyValidatorTest.java

@@ -0,0 +1,31 @@
+package org.maxkey.crypto.password;
+
+import org.maxkey.domain.PasswordPolicy;
+import org.maxkey.domain.UserInfo;
+import org.maxkey.persistence.db.PasswordPolicyValidator;
+
+public class PasswordPolicyValidatorTest {
+
+    public static void main(String[] args) {
+        // TODO Auto-generated method stub
+         PasswordPolicy passwordPolicy =new PasswordPolicy();
+         passwordPolicy.setDigits(3);
+         passwordPolicy.setMaxLength(16);
+         passwordPolicy.setMinLength(6);
+         passwordPolicy.setLowerCase(2);
+         passwordPolicy.setUpperCase(2);
+         passwordPolicy.setSpecialChar(1);
+         passwordPolicy.setUsername(1);
+         passwordPolicy.setSimplePasswords("admin,1qaz,2wsx,123456,12345678,1234567890");
+        PasswordPolicyValidator passwordPolicyValidator =new PasswordPolicyValidator();
+        
+        passwordPolicyValidator.setPasswordPolicy(passwordPolicy);
+        
+        UserInfo u=new UserInfo();
+        u.setUsername("admin");
+        u.setPassword("admin无");
+        passwordPolicyValidator.validator(u);
+        
+    }
+
+}

+ 37 - 0
maxkey-core/src/test/resources/log4j2.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>  
+<!--DOCTYPE log4j:configuration SYSTEM "log4j.dtd" -->
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"
+	 status="INFO"  monitorInterval="300"
+>  
+    <appenders>  
+    	
+        <Console name="consolePrint" target="SYSTEM_OUT">  
+            <PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss,SSS} %-5level [%t] %logger{36}:%L - %msg%n" />  
+        </Console>
+   
+		<!-- 输出到文件,按天或者超过128MB分割  每天进行归档yyyy-MM-dd -->
+		<RollingFile name="RollingFile" fileName="logs/maxkey.log"    filePattern="logs/$${date:yyyyMMdd}/maxkey-%d{yyyy-MM-dd}-%i.log.gz">
+		    <!-- 需要记录的级别 -->
+		 	<!-- <ThresholdFilter level="info" onMatch="ACCEPT" onMismatch="DENY" /> -->
+		     <PatternLayout pattern="%d{YYYY-MM-dd HH:mm:ss,SSS} %-5level [%t] %logger{36}:%L - %msg%n" />
+		     <Policies>
+		          <OnStartupTriggeringPolicy />
+		          <TimeBasedTriggeringPolicy />
+		          <SizeBasedTriggeringPolicy size="128 MB" />
+		     </Policies>
+		     <DefaultRolloverStrategy max="100"/>
+		</RollingFile>
+	 </appenders>  
+	 
+    <loggers>  
+    	<Logger name="org.springframework" level="INFO"></Logger>
+    	<Logger name="org.apache.logging" level="INFO"></Logger>
+    	<Logger name="org.maxkey" level="DEBUG"></Logger>
+    	
+    	
+        <root level="INFO">  
+            <appender-ref ref="consolePrint" />
+            <appender-ref ref="RollingFile" /> 
+        </root>  
+    </loggers>  
+</log4j:configuration>

+ 13 - 0
maxkey-persistence/src/main/java/org/maxkey/persistence/service/UserInfoService.java

@@ -27,6 +27,7 @@ import org.maxkey.domain.UserInfo;
 import org.maxkey.identity.kafka.KafkaIdentityAction;
 import org.maxkey.identity.kafka.KafkaIdentityTopic;
 import org.maxkey.identity.kafka.KafkaProvisioningService;
+import org.maxkey.persistence.db.PasswordPolicyValidator;
 import org.maxkey.persistence.mapper.UserInfoMapper;
 import org.maxkey.util.DateUtils;
 import org.maxkey.util.StringUtils;
@@ -50,6 +51,9 @@ public class UserInfoService extends JpaBaseService<UserInfo> {
 	private PasswordEncoder passwordEncoder;
 	
 	@Autowired
+	PasswordPolicyValidator passwordPolicyValidator;
+	
+	@Autowired
 	KafkaProvisioningService kafkaProvisioningService;
 	
 	public UserInfoService() {
@@ -153,8 +157,13 @@ public class UserInfoService extends JpaBaseService<UserInfo> {
 	    }
         return userInfo;
 	}
+	
+	
 	public boolean changePassword(UserInfo userInfo) {
 		try {
+		    
+		    passwordPolicyValidator.validator(userInfo);
+		    
 			if(WebContext.getUserInfo() != null) {
 				userInfo.setModifiedBy(WebContext.getUserInfo().getId());
 				
@@ -277,4 +286,8 @@ public class UserInfoService extends JpaBaseService<UserInfo> {
         return getMapper().updateProfile(userInfo);
     }
 
+    public void setPasswordPolicyValidator(PasswordPolicyValidator passwordPolicyValidator) {
+        this.passwordPolicyValidator = passwordPolicyValidator;
+    }
+
 }

+ 1 - 1
maxkey-web-maxkey/src/main/java/org/maxkey/web/contorller/SafeController.java

@@ -118,7 +118,7 @@ public class SafeController {
 		_logger.debug("decipherable new : "+ReciprocalUtils.encode(PasswordReciprocal.getInstance().rawPassword(userInfo.getUsername(), newPassword)));
 		if(newPassword.equals(confirmPassword)){
 			if(oldPassword==null || 
-					passwordEncoder.matches(PasswordReciprocal.getInstance().rawPassword(userInfo.getUsername(),oldPassword), userInfo.getPassword())){
+					passwordEncoder.matches(oldPassword, userInfo.getPassword())){
 				userInfo.setPassword(newPassword);
 				userInfoService.changePassword(userInfo);
 				//TODO syncProvisioningService.changePassword(userInfo);