PasswordPolicy

上级 05a517a7
MaxKey v 2.2.0 GA 2020/**/**
*(MAXKEY-200801) 官方网站内容调整,初步增加英文版支持
*(MAXKEY-200802) 密码策略优化
*(MAXKEY-200803) CAS协议增加自定义参数回传
*(MAXKEY-200801) 官方网站内容调整,初步增加英文版支持,增加新闻、合作伙伴及与CAS等开源产品对比
*(MAXKEY-200802) 使用Passay增强密码策略,分离出静态密码策略和动态密码策略
*(MAXKEY-200803) CAS协议增加自定义参数回传
*(MAXKEY-200804) 优化开发集成指南
*(MAXKEY-200805) 删除冗余的文件和文件夹
*(MAXKEY-200806) CAS适配器支持
*(MAXKEY-200807) Maven版本支持
*(MAXKEY-200808) CAS spring boot demo
*(MAXKEY-200809) MGT管理访问找不到页面修复
*(MAXKEY-200810) MGT管理密码修改增加自动密码生成
......
......@@ -39,6 +39,10 @@ public class PasswordGen {
public PasswordGen() {
length = DEFAULT_LENGTH;
}
public PasswordGen(int length) {
this.length = length;
}
public String gen() {
this.length = DEFAULT_LENGTH;
......
......@@ -104,7 +104,23 @@ public class PasswordPolicy extends JpaBaseDomain implements java.io.Serializabl
* not include password list
*/
@Column
private String simplePasswords;
private int history;
@Column
private int dictionary;
@Column
private int alphabetical;
@Column
private int numerical;
@Column
private int qwerty;
@Column
private int occurances;
/**
* @return the minLength
......@@ -260,18 +276,57 @@ public class PasswordPolicy extends JpaBaseDomain implements java.io.Serializabl
this.username = username;
}
/**
* @return the simplePasswords
*/
public String getSimplePasswords() {
return simplePasswords;
public int getHistory() {
return history;
}
/**
* @param simplePasswords the simplePasswords to set
*/
public void setSimplePasswords(String simplePasswords) {
this.simplePasswords = simplePasswords;
public void setHistory(int history) {
this.history = history;
}
public int getDictionary() {
return dictionary;
}
public void setDictionary(int dictionary) {
this.dictionary = dictionary;
}
public int getAlphabetical() {
return alphabetical;
}
public void setAlphabetical(int alphabetical) {
this.alphabetical = alphabetical;
}
public int getNumerical() {
return numerical;
}
public void setNumerical(int numerical) {
this.numerical = numerical;
}
public int getQwerty() {
return qwerty;
}
public void setQwerty(int qwerty) {
this.qwerty = qwerty;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
public int getOccurances() {
return occurances;
}
public void setOccurances(int occurances) {
this.occurances = occurances;
}
public void check(String username, String newPassword, String oldPassword) throws PasswordPolicyException {
......@@ -319,17 +374,14 @@ public class PasswordPolicy extends JpaBaseDomain implements java.io.Serializabl
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "PasswordPolicy [minLength=" + minLength + ", maxLength=" + maxLength + ", lowerCase=" + lowerCase
+ ", upperCase=" + upperCase + ", digits=" + digits + ", specialChar=" + specialChar + ", attempts="
+ attempts + ", duration=" + duration + ", expiration=" + expiration + ", username=" + username
+ ", simplePasswords=" + simplePasswords + "]";
return "PasswordPolicy [id=" + id + ", minLength=" + minLength + ", maxLength=" + maxLength + ", lowerCase="
+ lowerCase + ", upperCase=" + upperCase + ", digits=" + digits + ", specialChar=" + specialChar
+ ", attempts=" + attempts + ", duration=" + duration + ", expiration=" + expiration + ", username="
+ username + ", history=" + history + ", dictionary=" + dictionary + ", alphabetical=" + alphabetical
+ ", numerical=" + numerical + ", qwerty=" + qwerty + "]";
}
}
......@@ -38,7 +38,12 @@ public class PasswordPolicyRowMapper implements RowMapper<PasswordPolicy> {
passwordPolicy.setDuration(rs.getInt("DURATION"));
passwordPolicy.setExpiration(rs.getInt("EXPIRATION"));
passwordPolicy.setUsername(rs.getInt("USERNAME"));
passwordPolicy.setSimplePasswords(rs.getString("SIMPLEPASSWORDS"));
passwordPolicy.setHistory(rs.getInt("HISTORY"));
passwordPolicy.setDictionary(rs.getInt("DICTIONARY"));
passwordPolicy.setAlphabetical(rs.getInt("ALPHABETICAL"));
passwordPolicy.setNumerical(rs.getInt("NUMERICAL"));
passwordPolicy.setQwerty(rs.getInt("QWERTY"));
passwordPolicy.setOccurances(rs.getInt("OCCURANCES"));
return passwordPolicy;
}
......
......@@ -15,11 +15,13 @@ import org.maxkey.constants.ConstantsPasswordSetType;
import org.maxkey.constants.ConstantsProperties;
import org.maxkey.constants.ConstantsStatus;
import org.maxkey.constants.ConstantsTimeInterval;
import org.maxkey.crypto.password.PasswordGen;
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.CharacterOccurrencesRule;
import org.passay.CharacterRule;
import org.passay.DictionaryRule;
import org.passay.EnglishCharacterData;
......@@ -64,7 +66,7 @@ public class PasswordPolicyValidator {
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 PASSWORD_POLICY_SELECT_STATEMENT = "SELECT * FROM MXK_PASSWORD_POLICY ";
private static final String UNLOCK_USER_UPDATE_STATEMENT = "UPDATE MXK_USERINFO SET ISLOCKED = ? , UNLOCKTIME = ? WHERE ID = ?";
......@@ -97,20 +99,28 @@ public class PasswordPolicyValidator {
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 ) {
if(passwordPolicy.getOccurances()>0) {
passwordPolicyRuleList.add(new CharacterOccurrencesRule(passwordPolicy.getOccurances()));
}
if(passwordPolicy.getDictionary()>0 ) {
try {
ClassPathResource dictFile=
new ClassPathResource(
......@@ -201,9 +211,15 @@ public class PasswordPolicyValidator {
);
}
//initial password need change
if(userInfo.getLoginCount()<=0) {
WebContext.getSession().setAttribute(WebConstants.CURRENT_LOGIN_USER_PASSWORD_SET_TYPE,
ConstantsPasswordSetType.INITIAL_PASSWORD);
}
if (userInfo.getPasswordSetType() != ConstantsPasswordSetType.PASSWORD_NORMAL) {
WebContext.getSession().setAttribute(WebConstants.CURRENT_LOGIN_USER_PASSWORD_SET_TYPE,
userInfo.getPasswordSetType());
userInfo.getPasswordSetType());
return true;
} else {
WebContext.getSession().setAttribute(WebConstants.CURRENT_LOGIN_USER_PASSWORD_SET_TYPE,
......@@ -232,12 +248,6 @@ public class PasswordPolicyValidator {
}
}
//initial password need change
if(userInfo.getLoginCount()<=0) {
WebContext.getSession().setAttribute(WebConstants.CURRENT_LOGIN_USER_PASSWORD_SET_TYPE,
ConstantsPasswordSetType.INITIAL_PASSWORD);
}
return true;
}
......@@ -316,7 +326,23 @@ public class PasswordPolicyValidator {
}
}
public String generateRandomPassword() {
getPasswordPolicy();
PasswordGen passwordGen = new PasswordGen(
Math.round(
(
passwordPolicy.getMaxLength() +
passwordPolicy.getMinLength()
)/2
)
);
return passwordGen.gen(
passwordPolicy.getLowerCase(),
passwordPolicy.getUpperCase(),
passwordPolicy.getDigits(),
passwordPolicy.getSpecialChar());
}
public void setPasswordPolicy(PasswordPolicy passwordPolicy) {
this.passwordPolicy = passwordPolicy;
......
......@@ -16,7 +16,7 @@ public class PasswordPolicyValidatorTest {
passwordPolicy.setUpperCase(2);
passwordPolicy.setSpecialChar(1);
passwordPolicy.setUsername(1);
passwordPolicy.setSimplePasswords("admin,1qaz,2wsx,123456,12345678,1234567890");
passwordPolicy.setDictionary(0);
PasswordPolicyValidator passwordPolicyValidator =new PasswordPolicyValidator();
passwordPolicyValidator.setPasswordPolicy(passwordPolicy);
......
......@@ -181,6 +181,10 @@ public class UserInfoService extends JpaBaseService<UserInfo> {
return false;
}
public String randomPassword() {
return passwordPolicyValidator.generateRandomPassword();
}
public void changePasswordProvisioning(UserInfo userInfo) {
if(userInfo.getPassword()!=null && !userInfo.getPassword().equals("")) {
ChangePassword changePassword=new ChangePassword();
......
......@@ -42,7 +42,6 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
......@@ -50,7 +49,6 @@ import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
......@@ -68,12 +66,8 @@ public class UserInfoController {
@Autowired
@Qualifier("userInfoService")
private UserInfoService userInfoService;
@Autowired
private PasswordEncoder passwordEncoder;
/**
* 查询用户列表
* @param user
......@@ -164,6 +158,13 @@ public class UserInfoController {
return userInfo;
}
@ResponseBody
@RequestMapping(value = "/randomPassword")
public String randomPassword() {
return userInfoService.randomPassword();
}
/**
* 修改用户
* @param userInfo
......
......@@ -99,7 +99,12 @@ login.passwordpolicy.attempts=\u767B\u5F55\u5C1D\u8BD5\u6B21\u6570
login.passwordpolicy.duration=\u81EA\u52A8\u89E3\u9664
login.passwordpolicy.expiration=\u8FC7\u671F\u65F6\u95F4
login.passwordpolicy.username=\u5305\u542B\u7528\u6237\u540D
login.passwordpolicy.simplepasswords=\u7B80\u5355\u5BC6\u7801
login.passwordpolicy.dictionary=\u7B80\u5355\u5BC6\u7801\u5B57\u5178
login.passwordpolicy.history=\u5386\u53F2\u5BC6\u7801\u6B21\u6570
login.passwordpolicy.alphabetical=\u5B57\u6BCD\u5E8F\u5217\u7B56\u7565
login.passwordpolicy.numerical=\u6570\u5B57\u5E8F\u5217\u7B56\u7565
login.passwordpolicy.qwerty=\u952E\u76D8\u7B56\u7565
login.passwordpolicy.occurances=\u5B57\u7B26\u91CD\u590D\u6B21\u6570
login.social.link=\u7ED1\u5B9A
......@@ -429,6 +434,8 @@ button.text.cancel=\u53D6\u6D88
button.text.add.member=\u65B0\u589E\u6210\u5458
button.text.delete.member=\u5220\u9664\u6210\u5458
button.text.generate=\u751F\u6210
button.text.view=\u67E5\u770B
button.text.hidden=\u9690\u85CF
log.loginhistory.id=\u7F16\u53F7
log.loginhistory.sessionId=\u4F1A\u8BDD
......
......@@ -101,7 +101,12 @@ login.passwordpolicy.attempts=attempts
login.passwordpolicy.duration=duration
login.passwordpolicy.expiration=expiration
login.passwordpolicy.username=username
login.passwordpolicy.simplepasswords=simplepasswords
login.passwordpolicy.dictionary=Dictionary
login.passwordpolicy.history=History
login.passwordpolicy.alphabetical=ALPHABETICAL sequences
login.passwordpolicy.numerical=NUMERICAL sequences
login.passwordpolicy.qwerty=QWERTY sequences
login.passwordpolicy.occurances=Occurances
login.social.link=Link
......@@ -428,6 +433,8 @@ button.text.cancel=Cancel
button.text.add.member=Ddd member
button.text.delete.member=Delete member
button.text.generate=Generate
button.text.view=View
button.text.hidden=Hidden
log.loginhistory.id=id
......
......@@ -99,7 +99,12 @@ login.passwordpolicy.attempts=\u767B\u5F55\u5C1D\u8BD5\u6B21\u6570
login.passwordpolicy.duration=\u81EA\u52A8\u89E3\u9664
login.passwordpolicy.expiration=\u8FC7\u671F\u65F6\u95F4
login.passwordpolicy.username=\u5305\u542B\u7528\u6237\u540D
login.passwordpolicy.simplepasswords=\u7B80\u5355\u5BC6\u7801
login.passwordpolicy.dictionary=\u7B80\u5355\u5BC6\u7801\u5B57\u5178
login.passwordpolicy.history=\u5386\u53F2\u5BC6\u7801\u6B21\u6570
login.passwordpolicy.alphabetical=\u5B57\u6BCD\u5E8F\u5217\u7B56\u7565
login.passwordpolicy.numerical=\u6570\u5B57\u5E8F\u5217\u7B56\u7565
login.passwordpolicy.qwerty=\u952E\u76D8\u7B56\u7565
login.passwordpolicy.occurances=\u5B57\u7B26\u91CD\u590D\u6B21\u6570
login.social.link=\u7ED1\u5B9A
......@@ -429,6 +434,8 @@ button.text.cancel=\u53D6\u6D88
button.text.add.member=\u65B0\u589E\u6210\u5458
button.text.delete.member=\u5220\u9664\u6210\u5458
button.text.generate=\u751F\u6210
button.text.view=\u67E5\u770B
button.text.hidden=\u9690\u85CF
log.loginhistory.id=\u7F16\u53F7
log.loginhistory.sessionId=\u4F1A\u8BDD
......
......@@ -119,6 +119,79 @@
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group row">
<label class="col-sm-3 col-form-label"><@locale code="login.passwordpolicy.occurances" /></label>
<div class="col-sm-9">
<input required="" class="form-control" type="text" id="occurances" name="occurances" value="${model.occurances}" />
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group row">
<label class="col-sm-3 col-form-label"><@locale code="login.passwordpolicy.username" /></label>
<div class="col-sm-9">
<select class="form-control" id="username" name="username" >
<option <#if 1==model.username>selected</#if> value="1"><@locale code="common.text.status.enabled"/></option>
<option <#if 0==model.username>selected</#if> value="0"><@locale code="common.text.status.disabled"/></option>
</select>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group row">
<label class="col-sm-3 col-form-label"><@locale code="login.passwordpolicy.alphabetical" /></label>
<div class="col-sm-9">
<select class="form-control" id="alphabetical" name="alphabetical" >
<option <#if 1==model.alphabetical>selected</#if> value="1"><@locale code="common.text.status.enabled"/></option>
<option <#if 0==model.alphabetical>selected</#if> value="0"><@locale code="common.text.status.disabled"/></option>
</select>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group row">
<label class="col-sm-3 col-form-label"><@locale code="login.passwordpolicy.numerical" /></label>
<div class="col-sm-9">
<select class="form-control" id="numerical" name="numerical" >
<option <#if 1==model.numerical>selected</#if> value="1"><@locale code="common.text.status.enabled"/></option>
<option <#if 0==model.numerical>selected</#if> value="0"><@locale code="common.text.status.disabled"/></option>
</select>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group row">
<label class="col-sm-3 col-form-label"><@locale code="login.passwordpolicy.qwerty" /></label>
<div class="col-sm-9">
<select class="form-control" id="qwerty" name="qwerty" >
<option <#if 1==model.qwerty>selected</#if> value="1"><@locale code="common.text.status.enabled"/></option>
<option <#if 0==model.qwerty>selected</#if> value="0"><@locale code="common.text.status.disabled"/></option>
</select>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group row">
<label class="col-sm-3 col-form-label"><@locale code="login.passwordpolicy.dictionary" /></label>
<div class="col-sm-9">
<select class="form-control" id="dictionary" name="dictionary" >
<option <#if 1==model.dictionary>selected</#if> value="1"><@locale code="common.text.status.enabled"/></option>
<option <#if 0==model.dictionary>selected</#if> value="0"><@locale code="common.text.status.disabled"/></option>
</select>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group row">
......@@ -148,29 +221,20 @@
</div>
<div class="col-md-6">
<div class="form-group row">
<label class="col-sm-3 col-form-label"><@locale code="login.passwordpolicy.username" /></label>
<label class="col-sm-3 col-form-label"><@locale code="login.passwordpolicy.history" /></label>
<div class="col-sm-9">
<select class="form-control" id="username" name="username" >
<option <#if 1==model.username>selected</#if> value="1"><@locale code="common.text.status.enabled"/></option>
<option <#if 0==model.username>selected</#if> value="0"><@locale code="common.text.status.disabled"/></option>
</select>
<input required="" class="form-control" type="text" id="history" name="history" value="${model.history!}" />
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group m-b-20">
<label style="float: left;" for="simplePasswords"><@locale code="login.passwordpolicy.simplepasswords" /></label>
<textarea required="" id="simplePasswords" name="simplePasswords" class="form-control" >${model.simplePasswords!}</textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-md-3">
<div class="col-md-4"></div>
<div class="col-md-4">
<button type="submit" class="button btn-primary btn btn-common btn-block mr-3" id="submitBtn" ><@locale code="button.text.save" /></button>
</div>
<div class="col-md-4"></div>
</div>
</form>
......
<!DOCTYPE HTML >
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
<title>MaxKey</title>
<base href="<@base />"/>
<link rel="shortcut icon" type="image/x-icon" href="<@base />/static/images/favicon.ico"/>
<link type="text/css" rel="stylesheet" href="<@base url="/style.css"/>" />
</head>
<body>
<script type="text/javascript">window.top.location.href="<@basePath />/main";</script>
</body>
</html>
\ No newline at end of file
......@@ -3,12 +3,33 @@
<head>
<#include "../layout/header.ftl"/>
<#include "../layout/common.cssjs.ftl"/>
<style type="text/css">
.table th, .table td {
padding: .2rem;
vertical-align: middle;
}
</style>
<style type="text/css">
.table th, .table td {
padding: .2rem;
vertical-align: middle;
}
</style>
<script type="text/javascript">
<!--
$(function(){
$("#generateSecret").on("click",function(){
$.post("<@base/>/userinfo/randomPassword/", {_method:"post",currTime:(new Date()).getTime()}, function(data) {
$("#password").val(data+"");
$("#confirmPassword").val(data+"");
});
});
$("#view").on("click",function(){
if($("#password").attr("type")=="text"){
$("#password").attr("type","password");
}else{
$("#password").attr("type","text");
}
});
});
//-->
</script>
</head>
<body>
......@@ -34,7 +55,8 @@
<tr>
<th><@locale code="login.password.newPassword" />:</th>
<td>
<input type="password" id="password" name="password" required="" class="form-control" title="" value=""/>
<input type="password" id="password" name="password" required="" class="form-control" title="" value="" width="80%"/>
</td>
</tr>
<tr>
......@@ -46,8 +68,10 @@
<tr>
<td colspan="2" class="center">
<input id="_method" type="hidden" name="_method" value="post"/>
<input id="generateSecret" type="button" class="button btn btn-warning mr-3" style="width:100px" value="<@locale code="button.text.generate"/>"/>
<input id="view" type="button" class="button btn btn-info mr-3" style="width:100px" value="<@locale code="button.text.view"/>"/>
<input class="button btn btn-primary mr-3" style="width:100px" type="submit" id="submitBtn" value="<@locale code="button.text.save" />"/>
</td>
</tr>
</tbody>
......
......@@ -69,11 +69,12 @@ public class IndexEndpoint {
UserInfo userInfo=WebContext.getUserInfo();
modelAndView.addObject("model", userInfo);
if(passwordSetType==ConstantsPasswordSetType.PASSWORD_EXPIRED){
if(passwordSetType==ConstantsPasswordSetType.PASSWORD_EXPIRED||
passwordSetType==ConstantsPasswordSetType.MANAGER_CHANGED_PASSWORD){
modelAndView.setViewName("passwordExpired");
return modelAndView;
}else if(passwordSetType==ConstantsPasswordSetType.INITIAL_PASSWORD||
passwordSetType==ConstantsPasswordSetType.MANAGER_CHANGED_PASSWORD){
}else if(passwordSetType==ConstantsPasswordSetType.INITIAL_PASSWORD){
modelAndView.setViewName("passwordInitial");
return modelAndView;
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册