From 6ddf42270f45c3ed240fa36adee41c2a5b774776 Mon Sep 17 00:00:00 2001 From: "Crystal.Sea" Date: Wed, 2 Sep 2020 23:51:49 +0800 Subject: [PATCH] PasswordPolicy --- .../src/main/java/org/maxkey/crypto/SM3.java | 17 +++++ .../org/maxkey/crypto/password/Digester.java | 17 +++++ .../crypto/password/SM3PasswordEncoder.java | 17 +++++ .../password/StandardPasswordEncoder.java | 17 +++++ .../main/java/org/maxkey/domain/UserInfo.java | 9 +++ .../persistence/db/LoginHistoryService.java | 17 +++++ .../maxkey/persistence/db/LoginService.java | 17 +++++ .../db/PasswordPolicyMessageResolver.java | 17 +++++ .../db/PasswordPolicyValidator.java | 71 ++++++++++++++----- .../persistence/db/UserInfoRowMapper.java | 1 + .../java/org/maxkey/pretty/PrettyFactory.java | 17 +++++ .../src/test/java/org/maxkey/Copyright.java | 2 +- .../password/PasswordPolicyValidatorTest.java | 17 +++++ .../password/SM3PasswordEncoderTest.java | 17 +++++ .../endpoint/CasBaseAuthorizeEndpoint.java | 17 +++++ 15 files changed, 253 insertions(+), 17 deletions(-) diff --git a/maxkey-core/src/main/java/org/maxkey/crypto/SM3.java b/maxkey-core/src/main/java/org/maxkey/crypto/SM3.java index e79e7276..852985e6 100644 --- a/maxkey-core/src/main/java/org/maxkey/crypto/SM3.java +++ b/maxkey-core/src/main/java/org/maxkey/crypto/SM3.java @@ -1,3 +1,20 @@ +/* + * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package org.maxkey.crypto; import java.util.Arrays; diff --git a/maxkey-core/src/main/java/org/maxkey/crypto/password/Digester.java b/maxkey-core/src/main/java/org/maxkey/crypto/password/Digester.java index d5980fd8..07cd7d6e 100644 --- a/maxkey-core/src/main/java/org/maxkey/crypto/password/Digester.java +++ b/maxkey-core/src/main/java/org/maxkey/crypto/password/Digester.java @@ -1,3 +1,20 @@ +/* + * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package org.maxkey.crypto.password; import java.security.MessageDigest; diff --git a/maxkey-core/src/main/java/org/maxkey/crypto/password/SM3PasswordEncoder.java b/maxkey-core/src/main/java/org/maxkey/crypto/password/SM3PasswordEncoder.java index 71cab69d..096f4cee 100644 --- a/maxkey-core/src/main/java/org/maxkey/crypto/password/SM3PasswordEncoder.java +++ b/maxkey-core/src/main/java/org/maxkey/crypto/password/SM3PasswordEncoder.java @@ -1,3 +1,20 @@ +/* + * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package org.maxkey.crypto.password; import org.springframework.security.crypto.codec.Hex; diff --git a/maxkey-core/src/main/java/org/maxkey/crypto/password/StandardPasswordEncoder.java b/maxkey-core/src/main/java/org/maxkey/crypto/password/StandardPasswordEncoder.java index a8ea87ab..b89a8e77 100644 --- a/maxkey-core/src/main/java/org/maxkey/crypto/password/StandardPasswordEncoder.java +++ b/maxkey-core/src/main/java/org/maxkey/crypto/password/StandardPasswordEncoder.java @@ -1,3 +1,20 @@ +/* + * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package org.maxkey.crypto.password; import static org.springframework.security.crypto.util.EncodingUtils.concatenate; diff --git a/maxkey-core/src/main/java/org/maxkey/domain/UserInfo.java b/maxkey-core/src/main/java/org/maxkey/domain/UserInfo.java index 8480aeac..167c57e4 100644 --- a/maxkey-core/src/main/java/org/maxkey/domain/UserInfo.java +++ b/maxkey-core/src/main/java/org/maxkey/domain/UserInfo.java @@ -128,6 +128,7 @@ public class UserInfo extends JpaBaseDomain { protected String passwordLastSetTime; protected int badPasswordCount; + protected String badPasswordTime; protected String unLockTime; protected int isLocked; protected String lastLoginTime; @@ -692,6 +693,14 @@ public class UserInfo extends JpaBaseDomain { this.badPasswordCount = badPasswordCount; } + public String getBadPasswordTime() { + return badPasswordTime; + } + + public void setBadPasswordTime(String badPasswordTime) { + this.badPasswordTime = badPasswordTime; + } + public String getUnLockTime() { return unLockTime; } diff --git a/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginHistoryService.java b/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginHistoryService.java index 12511d7f..caf31d2b 100644 --- a/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginHistoryService.java +++ b/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginHistoryService.java @@ -1,3 +1,20 @@ +/* + * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package org.maxkey.persistence.db; import java.sql.Types; diff --git a/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginService.java b/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginService.java index 62e2ce3b..0ecd8bf9 100644 --- a/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginService.java +++ b/maxkey-core/src/main/java/org/maxkey/persistence/db/LoginService.java @@ -1,3 +1,20 @@ +/* + * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package org.maxkey.persistence.db; import java.sql.ResultSet; diff --git a/maxkey-core/src/main/java/org/maxkey/persistence/db/PasswordPolicyMessageResolver.java b/maxkey-core/src/main/java/org/maxkey/persistence/db/PasswordPolicyMessageResolver.java index 2118ea69..2f6f24e9 100644 --- a/maxkey-core/src/main/java/org/maxkey/persistence/db/PasswordPolicyMessageResolver.java +++ b/maxkey-core/src/main/java/org/maxkey/persistence/db/PasswordPolicyMessageResolver.java @@ -1,3 +1,20 @@ +/* + * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package org.maxkey.persistence.db; import java.util.Locale; diff --git a/maxkey-core/src/main/java/org/maxkey/persistence/db/PasswordPolicyValidator.java b/maxkey-core/src/main/java/org/maxkey/persistence/db/PasswordPolicyValidator.java index c0c844f8..87f1da9d 100644 --- a/maxkey-core/src/main/java/org/maxkey/persistence/db/PasswordPolicyValidator.java +++ b/maxkey-core/src/main/java/org/maxkey/persistence/db/PasswordPolicyValidator.java @@ -1,3 +1,20 @@ +/* + * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package org.maxkey.persistence.db; import java.io.InputStreamReader; @@ -45,9 +62,12 @@ import org.springframework.security.authentication.BadCredentialsException; public class PasswordPolicyValidator { private static Logger _logger = LoggerFactory.getLogger(PasswordPolicyValidator.class); - + + //Dictionary topWeakPassword Source public static final String topWeakPasswordPropertySource = "classpath:/top_weak_password.txt"; + + //Cache PasswordPolicy in memory ONE_HOUR protected static final UserManagedCache passwordPolicyStore = UserManagedCacheBuilder.newUserManagedCacheBuilder(String.class, PasswordPolicy.class) .withExpiry( @@ -87,7 +107,10 @@ public class PasswordPolicyValidator { this.jdbcTemplate = jdbcTemplate; } - + /** + * init PasswordPolicy and load Rules + * @return + */ public PasswordPolicy getPasswordPolicy() { passwordPolicy = passwordPolicyStore.get(PASSWORD_POLICY_KEY); @@ -97,7 +120,7 @@ public class PasswordPolicyValidator { _logger.debug("query PasswordPolicy : " + passwordPolicy); passwordPolicyStore.put(PASSWORD_POLICY_KEY,passwordPolicy); - //init Password Policy + //RandomPasswordLength =(MaxLength +MinLength)/2 passwordPolicy.setRandomPasswordLength( Math.round( ( @@ -163,7 +186,7 @@ public class PasswordPolicyValidator { } /** - * validator . + * static validator . * @param userInfo * @return boolean */ @@ -202,7 +225,7 @@ public class PasswordPolicyValidator { /** - * passwordPolicyValid . + * dynamic passwordPolicy Valid for user login. * @param userInfo * @return boolean */ @@ -210,17 +233,34 @@ public class PasswordPolicyValidator { getPasswordPolicy(); + DateTime currentdateTime = new DateTime(); /* * 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( - WebContext.getI18nValue("login.error.attempts", - new Object[]{userInfo.getUsername(),userInfo.getBadPasswordCount()}) - ); + //duration + String badPasswordTimeString = userInfo.getBadPasswordTime().substring(0, 19); + _logger.trace("bad Password Time " + badPasswordTimeString); + + DateTime badPasswordTime = DateTime.parse(badPasswordTimeString, + DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")); + Duration duration = new Duration(badPasswordTime, currentdateTime); + int intDuration = Integer.parseInt(duration.getStandardHours() + ""); + _logger.debug("bad Password duration " + intDuration + + " , password policy Duration "+passwordPolicy.getDuration() + + " , validate result " + (intDuration > passwordPolicy.getDuration())); + //auto unlock attempts when intDuration > set Duration + if(intDuration > passwordPolicy.getDuration()) { + _logger.debug("resetAttempts ..."); + resetAttempts(userInfo); + }else { + lockUser(userInfo); + throw new BadCredentialsException( + WebContext.getI18nValue("login.error.attempts", + new Object[]{userInfo.getUsername(),userInfo.getBadPasswordCount()}) + ); + } } //locked @@ -258,17 +298,16 @@ public class PasswordPolicyValidator { * */ 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())); + _logger.debug("password Last Set duration day " + intDuration + + " , password policy Expiration " +passwordPolicy.getExpiration() + +" , validate result " + (intDuration <= passwordPolicy.getExpiration())); if (intDuration > passwordPolicy.getExpiration()) { WebContext.getSession().setAttribute(WebConstants.CURRENT_LOGIN_USER_PASSWORD_SET_TYPE, ConstantsPasswordSetType.PASSWORD_EXPIRED); @@ -319,7 +358,7 @@ public class PasswordPolicyValidator { * * @param userInfo */ - public void resetBadPasswordCountAndLockout(UserInfo userInfo) { + public void resetAttempts(UserInfo userInfo) { try { if (userInfo != null && StringUtils.isNotEmpty(userInfo.getId())) { jdbcTemplate.update(BADPASSWORDCOUNT_RESET_UPDATE_STATEMENT, diff --git a/maxkey-core/src/main/java/org/maxkey/persistence/db/UserInfoRowMapper.java b/maxkey-core/src/main/java/org/maxkey/persistence/db/UserInfoRowMapper.java index e48e9ea3..f6fcd563 100644 --- a/maxkey-core/src/main/java/org/maxkey/persistence/db/UserInfoRowMapper.java +++ b/maxkey-core/src/main/java/org/maxkey/persistence/db/UserInfoRowMapper.java @@ -71,6 +71,7 @@ public class UserInfoRowMapper implements RowMapper { userInfo.setPasswordLastSetTime(rs.getString("PASSWORDLASTSETTIME")); userInfo.setPasswordSetType(rs.getInt("PASSWORDSETTYPE")); userInfo.setBadPasswordCount(rs.getInt("BADPASSWORDCOUNT")); + userInfo.setBadPasswordTime(rs.getString("BADPASSWORDTIME")); userInfo.setUnLockTime(rs.getString("UNLOCKTIME")); userInfo.setIsLocked(rs.getInt("ISLOCKED")); userInfo.setLastLoginTime(rs.getString("LASTLOGINTIME")); diff --git a/maxkey-core/src/main/java/org/maxkey/pretty/PrettyFactory.java b/maxkey-core/src/main/java/org/maxkey/pretty/PrettyFactory.java index 8e45ee1d..ecfe5ead 100644 --- a/maxkey-core/src/main/java/org/maxkey/pretty/PrettyFactory.java +++ b/maxkey-core/src/main/java/org/maxkey/pretty/PrettyFactory.java @@ -1,3 +1,20 @@ +/* + * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package org.maxkey.pretty; import org.maxkey.pretty.impl.JsonPretty; diff --git a/maxkey-core/src/test/java/org/maxkey/Copyright.java b/maxkey-core/src/test/java/org/maxkey/Copyright.java index 1932b4a0..ef260dbb 100644 --- a/maxkey-core/src/test/java/org/maxkey/Copyright.java +++ b/maxkey-core/src/test/java/org/maxkey/Copyright.java @@ -31,7 +31,7 @@ import java.io.OutputStreamWriter; */ public class Copyright { // 存放java文件的文件夹,必须是文件夹 - private static String srcFolder = "D:\\JavaIDE\\Workspaces\\maxkey\\MaxKey"; + private static String srcFolder = "D:\\MaxKey\\Workspaces\\maxkey\\MaxKey"; //已添加标识 private static String copyRightText = "http://www.apache.org/licenses/LICENSE-2.0"; //扫描目录 diff --git a/maxkey-core/src/test/java/org/maxkey/crypto/password/PasswordPolicyValidatorTest.java b/maxkey-core/src/test/java/org/maxkey/crypto/password/PasswordPolicyValidatorTest.java index b0b4d613..4aca438a 100644 --- a/maxkey-core/src/test/java/org/maxkey/crypto/password/PasswordPolicyValidatorTest.java +++ b/maxkey-core/src/test/java/org/maxkey/crypto/password/PasswordPolicyValidatorTest.java @@ -1,3 +1,20 @@ +/* + * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package org.maxkey.crypto.password; import org.maxkey.domain.PasswordPolicy; diff --git a/maxkey-core/src/test/java/org/maxkey/crypto/password/SM3PasswordEncoderTest.java b/maxkey-core/src/test/java/org/maxkey/crypto/password/SM3PasswordEncoderTest.java index aeea4549..631f2720 100644 --- a/maxkey-core/src/test/java/org/maxkey/crypto/password/SM3PasswordEncoderTest.java +++ b/maxkey-core/src/test/java/org/maxkey/crypto/password/SM3PasswordEncoderTest.java @@ -1,3 +1,20 @@ +/* + * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package org.maxkey.crypto.password; public class SM3PasswordEncoderTest { diff --git a/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/maxkey/authz/cas/endpoint/CasBaseAuthorizeEndpoint.java b/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/maxkey/authz/cas/endpoint/CasBaseAuthorizeEndpoint.java index 53c1d7bc..60607d22 100644 --- a/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/maxkey/authz/cas/endpoint/CasBaseAuthorizeEndpoint.java +++ b/maxkey-protocols/maxkey-protocol-cas/src/main/java/org/maxkey/authz/cas/endpoint/CasBaseAuthorizeEndpoint.java @@ -1,3 +1,20 @@ +/* + * Copyright [2020] [MaxKey of copyright http://www.maxkey.top] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + package org.maxkey.authz.cas.endpoint; import javax.servlet.http.HttpServletRequest;