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
|
@AutoConfigureMockMvc
|
||||||
class TmsApplicationTests {
|
class TmsApplicationTests {
|
||||||
|
|
||||||
|
private static final String DEFAULT_PASSWORD_DIGEST =
|
||||||
|
"fc216e5eea029a7b5c267ab13cc2e0927a3810e66a2a09b86f8fdbd8d4aa647b";
|
||||||
|
|
||||||
private static final Pattern AUTH_FULL_ACCOUNT_ROW = Pattern.compile(
|
private static final Pattern AUTH_FULL_ACCOUNT_ROW = Pattern.compile(
|
||||||
"\\(\\s*1210[1-5],.*?'([^']+)'\\s*,\\s*'([0-9a-f]{32})'",
|
"\\(\\s*1210[1-5],.*?'([^']+)'\\s*,\\s*'([0-9a-f]{32})'",
|
||||||
Pattern.DOTALL
|
Pattern.DOTALL
|
||||||
@ -115,7 +118,7 @@ class TmsApplicationTests {
|
|||||||
String hash = matcher.group(1);
|
String hash = matcher.group(1);
|
||||||
String salt = matcher.group(2);
|
String salt = matcher.group(2);
|
||||||
org.junit.jupiter.api.Assertions.assertTrue(salts.add(salt), "duplicate salt: " + salt);
|
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);
|
org.junit.jupiter.api.Assertions.assertEquals(5, rows);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,6 +28,11 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||||||
|
|
||||||
class AuthControllerTest {
|
class AuthControllerTest {
|
||||||
|
|
||||||
|
private static final String DIGEST_12345678 =
|
||||||
|
"0fffff81e971fa3f09107abf77931463fc0710bfb8962efeae3d5654b073bb0c";
|
||||||
|
private static final String DIGEST_ABC1234 =
|
||||||
|
"6b66c27d356b7fef3e2c2a986043031a410bb564205f22525ba022591671a7e5";
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldLoginWithPasswordPayload() throws Exception {
|
void shouldLoginWithPasswordPayload() throws Exception {
|
||||||
AuthService authService = Mockito.mock(AuthService.class);
|
AuthService authService = Mockito.mock(AuthService.class);
|
||||||
@ -51,13 +56,13 @@ class AuthControllerTest {
|
|||||||
"accounts": [
|
"accounts": [
|
||||||
{
|
{
|
||||||
"uid": 1,
|
"uid": 1,
|
||||||
"password": "12345678"
|
"password": "%s"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"captchaCode": "ABCD",
|
"captchaCode": "ABCD",
|
||||||
"captchaId": "captcha-001"
|
"captchaId": "captcha-001"
|
||||||
}
|
}
|
||||||
"""))
|
""".formatted(DIGEST_12345678)))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(content().string(containsString("\"token\":\"token-password-001\"")))
|
.andExpect(content().string(containsString("\"token\":\"token-password-001\"")))
|
||||||
.andExpect(content().string(containsString("\"authLevel\":\"LIMITED\"")));
|
.andExpect(content().string(containsString("\"authLevel\":\"LIMITED\"")));
|
||||||
@ -113,7 +118,7 @@ class AuthControllerTest {
|
|||||||
{
|
{
|
||||||
"pubKey": "PUB-1",
|
"pubKey": "PUB-1",
|
||||||
"uid": 1,
|
"uid": 1,
|
||||||
"password": "11111111",
|
"password": "%s",
|
||||||
"serverRandom": "RB-1",
|
"serverRandom": "RB-1",
|
||||||
"issueSignature": "ISSUE-1",
|
"issueSignature": "ISSUE-1",
|
||||||
"loginPayload": "LOGIN-DATA-1",
|
"loginPayload": "LOGIN-DATA-1",
|
||||||
@ -122,7 +127,7 @@ class AuthControllerTest {
|
|||||||
{
|
{
|
||||||
"pubKey": "PUB-2",
|
"pubKey": "PUB-2",
|
||||||
"uid": 2,
|
"uid": 2,
|
||||||
"password": "22222222",
|
"password": "%s",
|
||||||
"serverRandom": "RB-2",
|
"serverRandom": "RB-2",
|
||||||
"issueSignature": "ISSUE-2",
|
"issueSignature": "ISSUE-2",
|
||||||
"loginPayload": "LOGIN-DATA-2",
|
"loginPayload": "LOGIN-DATA-2",
|
||||||
@ -130,7 +135,7 @@ class AuthControllerTest {
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
"""))
|
""".formatted(DIGEST_12345678, DIGEST_ABC1234)))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(content().string(containsString("\"token\":\"token-ukey-001\"")))
|
.andExpect(content().string(containsString("\"token\":\"token-ukey-001\"")))
|
||||||
.andExpect(content().string(containsString("\"authLevel\":\"FULL\"")));
|
.andExpect(content().string(containsString("\"authLevel\":\"FULL\"")));
|
||||||
@ -215,14 +220,14 @@ class AuthControllerTest {
|
|||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.content("""
|
.content("""
|
||||||
{
|
{
|
||||||
"oldPassword": "12345678",
|
"oldPassword": "%s",
|
||||||
"newPassword": "Abc1234!"
|
"newPassword": "%s"
|
||||||
}
|
}
|
||||||
"""))
|
""".formatted(DIGEST_12345678, DIGEST_ABC1234)))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(content().string(containsString("\"success\":true")));
|
.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
|
@Test
|
||||||
@ -241,14 +246,14 @@ class AuthControllerTest {
|
|||||||
.contentType(MediaType.APPLICATION_JSON)
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
.content("""
|
.content("""
|
||||||
{
|
{
|
||||||
"oldPassword": "12345678",
|
"oldPassword": "%s",
|
||||||
"newPassword": "Abc1234!"
|
"newPassword": "%s"
|
||||||
}
|
}
|
||||||
"""))
|
""".formatted(DIGEST_12345678, DIGEST_ABC1234)))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(content().string(containsString("\"success\":true")));
|
.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
|
@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