fix:密码摘要
This commit is contained in:
parent
a5c73c82b0
commit
06a76d5f39
@ -1,61 +0,0 @@
|
||||
package com.cisd.tms.modules.auth.service;
|
||||
|
||||
import com.cisd.tms.common.enums.ErrorCode;
|
||||
import com.cisd.tms.common.exception.BizException;
|
||||
|
||||
public final class PasswordComplexityValidator {
|
||||
|
||||
public static final String MESSAGE = "密码复杂度不符合要求:需由8到16位大小写字母、数字、符号组成,且三类均需包含";
|
||||
|
||||
private PasswordComplexityValidator() {
|
||||
}
|
||||
|
||||
public static void validate(String password) {
|
||||
String value = password == null ? "" : password;
|
||||
if (value.isBlank()
|
||||
|| value.length() < 8
|
||||
|| value.length() > 16
|
||||
|| !isAllowedCharacters(value)
|
||||
|| !containsUppercase(value)
|
||||
|| !containsLowercase(value)
|
||||
|| !containsDigit(value)
|
||||
|| !containsSymbol(value)) {
|
||||
throw new BizException(ErrorCode.VALIDATE_FAILED.getCode(), MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isAllowedCharacters(String value) {
|
||||
return value.codePoints().allMatch(codePoint ->
|
||||
isAsciiLetter(codePoint) || isAsciiDigit(codePoint) || isSymbol(codePoint));
|
||||
}
|
||||
|
||||
private static boolean containsUppercase(String value) {
|
||||
return value.codePoints().anyMatch(codePoint -> codePoint >= 'A' && codePoint <= 'Z');
|
||||
}
|
||||
|
||||
private static boolean containsLowercase(String value) {
|
||||
return value.codePoints().anyMatch(codePoint -> codePoint >= 'a' && codePoint <= 'z');
|
||||
}
|
||||
|
||||
private static boolean containsDigit(String value) {
|
||||
return value.codePoints().anyMatch(PasswordComplexityValidator::isAsciiDigit);
|
||||
}
|
||||
|
||||
private static boolean containsSymbol(String value) {
|
||||
return value.codePoints().anyMatch(PasswordComplexityValidator::isSymbol);
|
||||
}
|
||||
|
||||
private static boolean isAsciiLetter(int codePoint) {
|
||||
return (codePoint >= 'A' && codePoint <= 'Z') || (codePoint >= 'a' && codePoint <= 'z');
|
||||
}
|
||||
|
||||
private static boolean isAsciiDigit(int codePoint) {
|
||||
return codePoint >= '0' && codePoint <= '9';
|
||||
}
|
||||
|
||||
private static boolean isSymbol(int codePoint) {
|
||||
return codePoint >= 33 && codePoint <= 126
|
||||
&& !isAsciiDigit(codePoint)
|
||||
&& !isAsciiLetter(codePoint);
|
||||
}
|
||||
}
|
||||
@ -19,6 +19,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
@AutoConfigureMockMvc
|
||||
class TmsApplicationTests {
|
||||
|
||||
private static final String DEFAULT_PASSWORD_DIGEST =
|
||||
"fc216e5eea029a7b5c267ab13cc2e0927a3810e66a2a09b86f8fdbd8d4aa647b";
|
||||
|
||||
private static final Pattern AUTH_FULL_ACCOUNT_ROW = Pattern.compile(
|
||||
"\\(\\s*1210[1-5],.*?'([^']+)'\\s*,\\s*'([0-9a-f]{32})'",
|
||||
Pattern.DOTALL
|
||||
@ -115,7 +118,7 @@ class TmsApplicationTests {
|
||||
String hash = matcher.group(1);
|
||||
String salt = matcher.group(2);
|
||||
org.junit.jupiter.api.Assertions.assertTrue(salts.add(salt), "duplicate salt: " + salt);
|
||||
org.junit.jupiter.api.Assertions.assertTrue(hasher.matches("Sunyard@123", salt, hash), "hash mismatch for salt: " + salt);
|
||||
org.junit.jupiter.api.Assertions.assertTrue(hasher.matches(DEFAULT_PASSWORD_DIGEST, salt, hash), "hash mismatch for salt: " + salt);
|
||||
}
|
||||
org.junit.jupiter.api.Assertions.assertEquals(5, rows);
|
||||
}
|
||||
|
||||
@ -28,6 +28,11 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
||||
|
||||
class AuthControllerTest {
|
||||
|
||||
private static final String DIGEST_12345678 =
|
||||
"0fffff81e971fa3f09107abf77931463fc0710bfb8962efeae3d5654b073bb0c";
|
||||
private static final String DIGEST_ABC1234 =
|
||||
"6b66c27d356b7fef3e2c2a986043031a410bb564205f22525ba022591671a7e5";
|
||||
|
||||
@Test
|
||||
void shouldLoginWithPasswordPayload() throws Exception {
|
||||
AuthService authService = Mockito.mock(AuthService.class);
|
||||
@ -51,13 +56,13 @@ class AuthControllerTest {
|
||||
"accounts": [
|
||||
{
|
||||
"uid": 1,
|
||||
"password": "12345678"
|
||||
"password": "%s"
|
||||
}
|
||||
],
|
||||
"captchaCode": "ABCD",
|
||||
"captchaId": "captcha-001"
|
||||
}
|
||||
"""))
|
||||
""".formatted(DIGEST_12345678)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string(containsString("\"token\":\"token-password-001\"")))
|
||||
.andExpect(content().string(containsString("\"authLevel\":\"LIMITED\"")));
|
||||
@ -113,7 +118,7 @@ class AuthControllerTest {
|
||||
{
|
||||
"pubKey": "PUB-1",
|
||||
"uid": 1,
|
||||
"password": "11111111",
|
||||
"password": "%s",
|
||||
"serverRandom": "RB-1",
|
||||
"issueSignature": "ISSUE-1",
|
||||
"loginPayload": "LOGIN-DATA-1",
|
||||
@ -122,7 +127,7 @@ class AuthControllerTest {
|
||||
{
|
||||
"pubKey": "PUB-2",
|
||||
"uid": 2,
|
||||
"password": "22222222",
|
||||
"password": "%s",
|
||||
"serverRandom": "RB-2",
|
||||
"issueSignature": "ISSUE-2",
|
||||
"loginPayload": "LOGIN-DATA-2",
|
||||
@ -130,7 +135,7 @@ class AuthControllerTest {
|
||||
}
|
||||
]
|
||||
}
|
||||
"""))
|
||||
""".formatted(DIGEST_12345678, DIGEST_ABC1234)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string(containsString("\"token\":\"token-ukey-001\"")))
|
||||
.andExpect(content().string(containsString("\"authLevel\":\"FULL\"")));
|
||||
@ -215,14 +220,14 @@ class AuthControllerTest {
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("""
|
||||
{
|
||||
"oldPassword": "12345678",
|
||||
"newPassword": "Abc1234!"
|
||||
"oldPassword": "%s",
|
||||
"newPassword": "%s"
|
||||
}
|
||||
"""))
|
||||
""".formatted(DIGEST_12345678, DIGEST_ABC1234)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string(containsString("\"success\":true")));
|
||||
|
||||
Mockito.verify(authService).changeAccountPassword("token-change-001", 1, "12345678", "Abc1234!");
|
||||
Mockito.verify(authService).changeAccountPassword("token-change-001", 1, DIGEST_12345678, DIGEST_ABC1234);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -241,14 +246,14 @@ class AuthControllerTest {
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content("""
|
||||
{
|
||||
"oldPassword": "12345678",
|
||||
"newPassword": "Abc1234!"
|
||||
"oldPassword": "%s",
|
||||
"newPassword": "%s"
|
||||
}
|
||||
"""))
|
||||
""".formatted(DIGEST_12345678, DIGEST_ABC1234)))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(content().string(containsString("\"success\":true")));
|
||||
|
||||
Mockito.verify(authAdminService).changeAccountPassword("SUPER_ADMIN", "FULL", "KEY_ADMIN", 1, "12345678", "Abc1234!");
|
||||
Mockito.verify(authAdminService).changeAccountPassword("SUPER_ADMIN", "FULL", "KEY_ADMIN", 1, DIGEST_12345678, DIGEST_ABC1234);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -1,38 +0,0 @@
|
||||
package com.cisd.tms.modules.auth.service;
|
||||
|
||||
import com.cisd.tms.common.exception.BizException;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class PasswordComplexityValidatorTest {
|
||||
|
||||
@Test
|
||||
void shouldAcceptPasswordWithLettersDigitsAndSymbolInAllowedLength() {
|
||||
Assertions.assertDoesNotThrow(() -> PasswordComplexityValidator.validate("Abc1234!"));
|
||||
Assertions.assertDoesNotThrow(() -> PasswordComplexityValidator.validate("Aa123456789012!"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRejectPasswordOutsideNewComplexityPolicy() {
|
||||
assertInvalid(null);
|
||||
assertInvalid("");
|
||||
assertInvalid(" ");
|
||||
assertInvalid("Abc123!");
|
||||
assertInvalid("Abc1234567890123!");
|
||||
assertInvalid("abc1234!");
|
||||
assertInvalid("ABC1234!");
|
||||
assertInvalid("Abcdefg!");
|
||||
assertInvalid("Abc12345");
|
||||
assertInvalid("中Abc1234!");
|
||||
assertInvalid("Abc1234!");
|
||||
assertInvalid("Abc 123!");
|
||||
}
|
||||
|
||||
private void assertInvalid(String password) {
|
||||
BizException exception = Assertions.assertThrows(
|
||||
BizException.class,
|
||||
() -> PasswordComplexityValidator.validate(password)
|
||||
);
|
||||
Assertions.assertEquals(PasswordComplexityValidator.MESSAGE, exception.getMessage());
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user