|
@@ -16,24 +16,21 @@
|
|
|
|
|
|
package org.springframework.security.crypto.password4j;
|
|
package org.springframework.security.crypto.password4j;
|
|
|
|
|
|
-import com.password4j.AlgorithmFinder;
|
|
|
|
import com.password4j.Argon2Function;
|
|
import com.password4j.Argon2Function;
|
|
import com.password4j.BcryptFunction;
|
|
import com.password4j.BcryptFunction;
|
|
-import com.password4j.CompressedPBKDF2Function;
|
|
|
|
import com.password4j.ScryptFunction;
|
|
import com.password4j.ScryptFunction;
|
|
import com.password4j.types.Argon2;
|
|
import com.password4j.types.Argon2;
|
|
import org.junit.jupiter.api.Test;
|
|
import org.junit.jupiter.api.Test;
|
|
|
|
|
|
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder;
|
|
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder;
|
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
|
-import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
|
|
|
|
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
|
|
import org.springframework.security.crypto.scrypt.SCryptPasswordEncoder;
|
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
|
|
|
|
/**
|
|
/**
|
|
* Tests compatibility between existing Spring Security password encoders and
|
|
* Tests compatibility between existing Spring Security password encoders and
|
|
- * {@link Password4jPasswordEncoder}.
|
|
|
|
|
|
+ * Password4j-based password encoders.
|
|
*
|
|
*
|
|
* @author Mehrdad Bozorgmehr
|
|
* @author Mehrdad Bozorgmehr
|
|
*/
|
|
*/
|
|
@@ -45,7 +42,8 @@ class PasswordCompatibilityTests {
|
|
@Test
|
|
@Test
|
|
void bcryptEncodedWithSpringSecurityShouldMatchWithPassword4j() {
|
|
void bcryptEncodedWithSpringSecurityShouldMatchWithPassword4j() {
|
|
BCryptPasswordEncoder springEncoder = new BCryptPasswordEncoder(10);
|
|
BCryptPasswordEncoder springEncoder = new BCryptPasswordEncoder(10);
|
|
- Password4jPasswordEncoder password4jEncoder = new Password4jPasswordEncoder(BcryptFunction.getInstance(10));
|
|
|
|
|
|
+ BcryptPassword4jPasswordEncoder password4jEncoder = new BcryptPassword4jPasswordEncoder(
|
|
|
|
+ BcryptFunction.getInstance(10));
|
|
|
|
|
|
String encodedBySpring = springEncoder.encode(PASSWORD);
|
|
String encodedBySpring = springEncoder.encode(PASSWORD);
|
|
boolean matchedByPassword4j = password4jEncoder.matches(PASSWORD, encodedBySpring);
|
|
boolean matchedByPassword4j = password4jEncoder.matches(PASSWORD, encodedBySpring);
|
|
@@ -54,9 +52,10 @@ class PasswordCompatibilityTests {
|
|
}
|
|
}
|
|
|
|
|
|
@Test
|
|
@Test
|
|
- void bcryptEncodedWithPassword4jShouldMatchWithSpringSecurity() {
|
|
|
|
|
|
+ void bcryptEncodedWithPassword4jShouldMatchWithSpringSecirity() {
|
|
|
|
+ BcryptPassword4jPasswordEncoder password4jEncoder = new BcryptPassword4jPasswordEncoder(
|
|
|
|
+ BcryptFunction.getInstance(10));
|
|
BCryptPasswordEncoder springEncoder = new BCryptPasswordEncoder(10);
|
|
BCryptPasswordEncoder springEncoder = new BCryptPasswordEncoder(10);
|
|
- Password4jPasswordEncoder password4jEncoder = new Password4jPasswordEncoder(BcryptFunction.getInstance(10));
|
|
|
|
|
|
|
|
String encodedByPassword4j = password4jEncoder.encode(PASSWORD);
|
|
String encodedByPassword4j = password4jEncoder.encode(PASSWORD);
|
|
boolean matchedBySpring = springEncoder.matches(PASSWORD, encodedByPassword4j);
|
|
boolean matchedBySpring = springEncoder.matches(PASSWORD, encodedByPassword4j);
|
|
@@ -64,12 +63,12 @@ class PasswordCompatibilityTests {
|
|
assertThat(matchedBySpring).isTrue();
|
|
assertThat(matchedBySpring).isTrue();
|
|
}
|
|
}
|
|
|
|
|
|
- // SCrypt Compatibility Tests
|
|
|
|
|
|
+ // Argon2 Compatibility Tests
|
|
@Test
|
|
@Test
|
|
- void scryptEncodedWithSpringSecurityShouldMatchWithPassword4j() {
|
|
|
|
- SCryptPasswordEncoder springEncoder = new SCryptPasswordEncoder(16384, 8, 1, 32, 64);
|
|
|
|
- Password4jPasswordEncoder password4jEncoder = new Password4jPasswordEncoder(
|
|
|
|
- ScryptFunction.getInstance(16384, 8, 1, 32));
|
|
|
|
|
|
+ void argon2EncodedWithSpringSecurityShouldMatchWithPassword4j() {
|
|
|
|
+ Argon2PasswordEncoder springEncoder = new Argon2PasswordEncoder(16, 32, 1, 4096, 3);
|
|
|
|
+ Argon2Password4jPasswordEncoder password4jEncoder = new Argon2Password4jPasswordEncoder(
|
|
|
|
+ Argon2Function.getInstance(4096, 3, 1, 32, Argon2.ID));
|
|
|
|
|
|
String encodedBySpring = springEncoder.encode(PASSWORD);
|
|
String encodedBySpring = springEncoder.encode(PASSWORD);
|
|
boolean matchedByPassword4j = password4jEncoder.matches(PASSWORD, encodedBySpring);
|
|
boolean matchedByPassword4j = password4jEncoder.matches(PASSWORD, encodedBySpring);
|
|
@@ -78,10 +77,10 @@ class PasswordCompatibilityTests {
|
|
}
|
|
}
|
|
|
|
|
|
@Test
|
|
@Test
|
|
- void scryptEncodedWithPassword4jShouldMatchWithSpringSecurity() {
|
|
|
|
- SCryptPasswordEncoder springEncoder = new SCryptPasswordEncoder(16384, 8, 1, 32, 64);
|
|
|
|
- Password4jPasswordEncoder password4jEncoder = new Password4jPasswordEncoder(
|
|
|
|
- ScryptFunction.getInstance(16384, 8, 1, 32));
|
|
|
|
|
|
+ void argon2EncodedWithPassword4jShouldMatchWithSpringSecirity() {
|
|
|
|
+ Argon2Password4jPasswordEncoder password4jEncoder = new Argon2Password4jPasswordEncoder(
|
|
|
|
+ Argon2Function.getInstance(4096, 3, 1, 32, Argon2.ID));
|
|
|
|
+ Argon2PasswordEncoder springEncoder = new Argon2PasswordEncoder(16, 32, 1, 4096, 3);
|
|
|
|
|
|
String encodedByPassword4j = password4jEncoder.encode(PASSWORD);
|
|
String encodedByPassword4j = password4jEncoder.encode(PASSWORD);
|
|
boolean matchedBySpring = springEncoder.matches(PASSWORD, encodedByPassword4j);
|
|
boolean matchedBySpring = springEncoder.matches(PASSWORD, encodedByPassword4j);
|
|
@@ -89,12 +88,12 @@ class PasswordCompatibilityTests {
|
|
assertThat(matchedBySpring).isTrue();
|
|
assertThat(matchedBySpring).isTrue();
|
|
}
|
|
}
|
|
|
|
|
|
- // Argon2 Compatibility Tests
|
|
|
|
|
|
+ // SCrypt Compatibility Tests
|
|
@Test
|
|
@Test
|
|
- void argon2EncodedWithSpringSecurityShouldMatchWithPassword4j() {
|
|
|
|
- Argon2PasswordEncoder springEncoder = new Argon2PasswordEncoder(16, 32, 1, 65536, 3);
|
|
|
|
- Password4jPasswordEncoder password4jEncoder = new Password4jPasswordEncoder(
|
|
|
|
- Argon2Function.getInstance(65536, 3, 1, 32, Argon2.ID));
|
|
|
|
|
|
+ void scryptEncodedWithSpringSecurityShouldMatchWithPassword4j() {
|
|
|
|
+ SCryptPasswordEncoder springEncoder = new SCryptPasswordEncoder(16384, 8, 1, 32, 64);
|
|
|
|
+ ScryptPassword4jPasswordEncoder password4jEncoder = new ScryptPassword4jPasswordEncoder(
|
|
|
|
+ ScryptFunction.getInstance(16384, 8, 1, 32));
|
|
|
|
|
|
String encodedBySpring = springEncoder.encode(PASSWORD);
|
|
String encodedBySpring = springEncoder.encode(PASSWORD);
|
|
boolean matchedByPassword4j = password4jEncoder.matches(PASSWORD, encodedBySpring);
|
|
boolean matchedByPassword4j = password4jEncoder.matches(PASSWORD, encodedBySpring);
|
|
@@ -103,10 +102,10 @@ class PasswordCompatibilityTests {
|
|
}
|
|
}
|
|
|
|
|
|
@Test
|
|
@Test
|
|
- void argon2EncodedWithPassword4jShouldMatchWithSpringSecurity() {
|
|
|
|
- Argon2PasswordEncoder springEncoder = new Argon2PasswordEncoder(16, 32, 1, 65536, 3);
|
|
|
|
- Password4jPasswordEncoder password4jEncoder = new Password4jPasswordEncoder(
|
|
|
|
- Argon2Function.getInstance(65536, 3, 1, 32, Argon2.ID));
|
|
|
|
|
|
+ void scryptEncodedWithPassword4jShouldMatchWithSpringSecirity() {
|
|
|
|
+ ScryptPassword4jPasswordEncoder password4jEncoder = new ScryptPassword4jPasswordEncoder(
|
|
|
|
+ ScryptFunction.getInstance(16384, 8, 1, 32));
|
|
|
|
+ SCryptPasswordEncoder springEncoder = new SCryptPasswordEncoder(16384, 8, 1, 32, 64);
|
|
|
|
|
|
String encodedByPassword4j = password4jEncoder.encode(PASSWORD);
|
|
String encodedByPassword4j = password4jEncoder.encode(PASSWORD);
|
|
boolean matchedBySpring = springEncoder.matches(PASSWORD, encodedByPassword4j);
|
|
boolean matchedBySpring = springEncoder.matches(PASSWORD, encodedByPassword4j);
|
|
@@ -114,47 +113,4 @@ class PasswordCompatibilityTests {
|
|
assertThat(matchedBySpring).isTrue();
|
|
assertThat(matchedBySpring).isTrue();
|
|
}
|
|
}
|
|
|
|
|
|
- // PBKDF2 Compatibility Tests - Note: Different format implementations
|
|
|
|
- @Test
|
|
|
|
- void pbkdf2BasicFunctionalityTest() {
|
|
|
|
- // Test that both encoders work independently with their own formats
|
|
|
|
- // Spring Security PBKDF2
|
|
|
|
- Pbkdf2PasswordEncoder springEncoder = new Pbkdf2PasswordEncoder("", 16, 100000,
|
|
|
|
- Pbkdf2PasswordEncoder.SecretKeyFactoryAlgorithm.PBKDF2WithHmacSHA256);
|
|
|
|
- String springEncoded = springEncoder.encode(PASSWORD);
|
|
|
|
- assertThat(springEncoder.matches(PASSWORD, springEncoded)).isTrue();
|
|
|
|
-
|
|
|
|
- // Password4j PBKDF2
|
|
|
|
- Password4jPasswordEncoder password4jEncoder = new Password4jPasswordEncoder(
|
|
|
|
- CompressedPBKDF2Function.getInstance("SHA256", 100000, 32));
|
|
|
|
- String password4jEncoded = password4jEncoder.encode(PASSWORD);
|
|
|
|
- assertThat(password4jEncoder.matches(PASSWORD, password4jEncoded)).isTrue();
|
|
|
|
-
|
|
|
|
- // Note: These encoders use different hash formats and are not cross-compatible
|
|
|
|
- // This is expected behavior due to different implementation standards
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Cross-Algorithm Tests (should fail)
|
|
|
|
- @Test
|
|
|
|
- void bcryptEncodedPasswordShouldNotMatchArgon2Encoder() {
|
|
|
|
- Password4jPasswordEncoder bcryptEncoder = new Password4jPasswordEncoder(BcryptFunction.getInstance(10));
|
|
|
|
- Password4jPasswordEncoder argon2Encoder = new Password4jPasswordEncoder(AlgorithmFinder.getArgon2Instance());
|
|
|
|
-
|
|
|
|
- String bcryptEncoded = bcryptEncoder.encode(PASSWORD);
|
|
|
|
- boolean matchedByArgon2 = argon2Encoder.matches(PASSWORD, bcryptEncoded);
|
|
|
|
-
|
|
|
|
- assertThat(matchedByArgon2).isFalse();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- void argon2EncodedPasswordShouldNotMatchScryptEncoder() {
|
|
|
|
- Password4jPasswordEncoder argon2Encoder = new Password4jPasswordEncoder(AlgorithmFinder.getArgon2Instance());
|
|
|
|
- Password4jPasswordEncoder scryptEncoder = new Password4jPasswordEncoder(AlgorithmFinder.getScryptInstance());
|
|
|
|
-
|
|
|
|
- String argon2Encoded = argon2Encoder.encode(PASSWORD);
|
|
|
|
- boolean matchedByScrypt = scryptEncoder.matches(PASSWORD, argon2Encoded);
|
|
|
|
-
|
|
|
|
- assertThat(matchedByScrypt).isFalse();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
}
|
|
}
|