Skip to content

Commit d5603a9

Browse files
Avoid exception if PBKDF2WithHmacSHA256 is not available
Issue gh-12873
1 parent a513fc0 commit d5603a9

File tree

3 files changed

+46
-3
lines changed

3 files changed

+46
-3
lines changed

crypto/spring-security-crypto.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,6 @@ dependencies {
1111
testImplementation "org.junit.jupiter:junit-jupiter-engine"
1212
testImplementation "org.mockito:mockito-core"
1313
testImplementation "org.mockito:mockito-junit-jupiter"
14+
testImplementation "org.mockito:mockito-inline"
1415
testImplementation "org.springframework:spring-test"
1516
}

crypto/src/main/java/org/springframework/security/crypto/factory/PasswordEncoderFactories.java

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,8 +16,13 @@
1616

1717
package org.springframework.security.crypto.factory;
1818

19+
import java.security.NoSuchAlgorithmException;
1920
import java.util.HashMap;
2021
import java.util.Map;
22+
import java.util.function.Supplier;
23+
24+
import org.apache.commons.logging.Log;
25+
import org.apache.commons.logging.LogFactory;
2126

2227
import org.springframework.security.crypto.argon2.Argon2PasswordEncoder;
2328
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@@ -34,6 +39,8 @@
3439
*/
3540
public final class PasswordEncoderFactories {
3641

42+
private static final Log logger = LogFactory.getLog(PasswordEncoderFactories.class);
43+
3744
private PasswordEncoderFactories() {
3845
}
3946

@@ -78,7 +85,8 @@ public static PasswordEncoder createDelegatingPasswordEncoder() {
7885
encoders.put("MD5", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("MD5"));
7986
encoders.put("noop", org.springframework.security.crypto.password.NoOpPasswordEncoder.getInstance());
8087
encoders.put("pbkdf2", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_5());
81-
encoders.put("pbkdf2@SpringSecurity_v5_8", Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8());
88+
putIfAlgorithmSupported("pbkdf2@SpringSecurity_v5_8", Pbkdf2PasswordEncoder::defaultsForSpringSecurity_v5_8,
89+
encoders);
8290
encoders.put("scrypt", SCryptPasswordEncoder.defaultsForSpringSecurity_v4_1());
8391
encoders.put("scrypt@SpringSecurity_v5_8", SCryptPasswordEncoder.defaultsForSpringSecurity_v5_8());
8492
encoders.put("SHA-1", new org.springframework.security.crypto.password.MessageDigestPasswordEncoder("SHA-1"));
@@ -90,4 +98,22 @@ public static PasswordEncoder createDelegatingPasswordEncoder() {
9098
return new DelegatingPasswordEncoder(encodingId, encoders);
9199
}
92100

101+
private static void putIfAlgorithmSupported(String encodingId, Supplier<PasswordEncoder> encoderSupplier,
102+
Map<String, PasswordEncoder> encoders) {
103+
try {
104+
PasswordEncoder passwordEncoder = encoderSupplier.get();
105+
encoders.put(encodingId, passwordEncoder);
106+
}
107+
catch (Exception ex) {
108+
if (ex.getCause() instanceof NoSuchAlgorithmException) {
109+
logger.warn(String.format(
110+
"Cannot create PasswordEncoder with encodingId [%s] because the algorithm is not available",
111+
encodingId), ex);
112+
}
113+
else {
114+
throw ex;
115+
}
116+
}
117+
}
118+
93119
}

crypto/src/test/java/org/springframework/security/crypto/factory/PasswordEncoderFactoriesTests.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,11 +16,17 @@
1616

1717
package org.springframework.security.crypto.factory;
1818

19+
import java.security.NoSuchAlgorithmException;
20+
1921
import org.junit.jupiter.api.Test;
22+
import org.mockito.MockedStatic;
2023

2124
import org.springframework.security.crypto.password.PasswordEncoder;
25+
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
2226

2327
import static org.assertj.core.api.Assertions.assertThat;
28+
import static org.assertj.core.api.Assertions.assertThatNoException;
29+
import static org.mockito.Mockito.mockStatic;
2430

2531
/**
2632
* @author Rob Winch
@@ -123,4 +129,14 @@ public void matchesWhenArgon2SpringSecurity_v5_8ThenWorks() {
123129
assertThat(this.encoder.matches(this.rawPassword, encodedPassword)).isTrue();
124130
}
125131

132+
@Test
133+
void constructWhenAlgorithmNotAvailableThenSkip() {
134+
try (MockedStatic<Pbkdf2PasswordEncoder> pbkdf2PasswordEncoderMock = mockStatic(Pbkdf2PasswordEncoder.class)) {
135+
pbkdf2PasswordEncoderMock.when(Pbkdf2PasswordEncoder::defaultsForSpringSecurity_v5_8)
136+
.thenThrow(new IllegalArgumentException(new NoSuchAlgorithmException()));
137+
138+
assertThatNoException().isThrownBy(PasswordEncoderFactories::createDelegatingPasswordEncoder);
139+
}
140+
}
141+
126142
}

0 commit comments

Comments
 (0)