mirror of
https://gitee.com/dromara/MaxKey.git
synced 2025-12-07 17:38:32 +08:00
PasswordPolicyValidator
PasswordPolicyValidator
This commit is contained in:
parent
7bbe1f472f
commit
4f67f93c28
@ -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
|
||||
|
||||
@ -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')
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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锛<EFBFBD>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锛<EFBFBD>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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 閲嶇疆閿欒瀵嗙爜娆℃暟鍜岃В閿佺敤鎴<EFBFBD>
|
||||
*
|
||||
* @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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -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 });
|
||||
}
|
||||
}
|
||||
@ -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锛<EFBFBD>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锛<EFBFBD>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 });
|
||||
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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
maxkey-core/src/test/resources/log4j2.xml
Normal file
37
maxkey-core/src/test/resources/log4j2.xml
Normal file
@ -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>
|
||||
@ -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;
|
||||
@ -49,6 +50,9 @@ public class UserInfoService extends JpaBaseService<UserInfo> {
|
||||
@Autowired
|
||||
private PasswordEncoder passwordEncoder;
|
||||
|
||||
@Autowired
|
||||
PasswordPolicyValidator passwordPolicyValidator;
|
||||
|
||||
@Autowired
|
||||
KafkaProvisioningService kafkaProvisioningService;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user