diff --git a/api/build.gradle b/api/build.gradle index 7fd03c814..7095daa57 100644 --- a/api/build.gradle +++ b/api/build.gradle @@ -50,6 +50,7 @@ dependencies { api "org.springdoc:springdoc-openapi-starter-webflux-ui" api 'org.openapi4j:openapi-schema-validator' api "net.bytebuddy:byte-buddy" + api "org.bouncycastle:bcpkix-jdk18on" // Apache Lucene api "org.apache.lucene:lucene-core" diff --git a/application/src/main/java/run/halo/app/infra/config/WebServerSecurityConfig.java b/application/src/main/java/run/halo/app/infra/config/WebServerSecurityConfig.java index 7a5070010..c0c22fcd3 100644 --- a/application/src/main/java/run/halo/app/infra/config/WebServerSecurityConfig.java +++ b/application/src/main/java/run/halo/app/infra/config/WebServerSecurityConfig.java @@ -2,6 +2,7 @@ package run.halo.app.infra.config; import static org.springframework.security.web.server.util.matcher.ServerWebExchangeMatchers.pathMatchers; +import java.util.HashMap; import java.util.concurrent.ConcurrentHashMap; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.ObjectProvider; @@ -13,7 +14,9 @@ import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity; import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; import org.springframework.security.config.web.server.ServerHttpSecurity; -import org.springframework.security.crypto.factory.PasswordEncoderFactories; +import org.springframework.security.crypto.argon2.Argon2PasswordEncoder; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.DelegatingPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.server.SecurityWebFilterChain; import org.springframework.security.web.server.context.ServerSecurityContextRepository; @@ -136,8 +139,17 @@ public class WebServerSecurityConfig { } @Bean + @SuppressWarnings("deprecation") PasswordEncoder passwordEncoder() { - return PasswordEncoderFactories.createDelegatingPasswordEncoder(); + // For removing the length limit of password, we have to create an argon2 password encoder + // as default encoder. + // When https://github.com/spring-projects/spring-security/issues/16879 resolved, + // we can remove this code. + var encodingId = "argon2@SpringSecurity_v5_8"; + var encoders = new HashMap(); + encoders.put(encodingId, Argon2PasswordEncoder.defaultsForSpringSecurity_v5_8()); + encoders.put("bcrypt", new BCryptPasswordEncoder()); + return new DelegatingPasswordEncoder(encodingId, encoders); } @Bean diff --git a/application/src/test/java/run/halo/app/config/SecurityConfigTest.java b/application/src/test/java/run/halo/app/config/SecurityConfigTest.java index 2c7257ccd..9a2b901e2 100644 --- a/application/src/test/java/run/halo/app/config/SecurityConfigTest.java +++ b/application/src/test/java/run/halo/app/config/SecurityConfigTest.java @@ -1,13 +1,16 @@ package run.halo.app.config; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.springframework.security.web.server.header.StrictTransportSecurityServerHttpHeadersWriter.STRICT_TRANSPORT_SECURITY; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.reactive.AutoConfigureWebTestClient; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.MediaType; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.test.web.reactive.server.WebTestClient; @SpringBootTest @@ -36,4 +39,10 @@ class SecurityConfigTest { hsts -> assertFalse(hsts.contains("includeSubDomains"))); } + @Test + void shouldAllowPasswordLengthMoreThan72(@Autowired PasswordEncoder passwordEncoder) { + var encoded = passwordEncoder.encode(RandomStringUtils.secure().nextAlphanumeric(73)); + assertNotNull(encoded); + } + } diff --git a/platform/application/build.gradle b/platform/application/build.gradle index 20aff635e..7a0a0aef8 100644 --- a/platform/application/build.gradle +++ b/platform/application/build.gradle @@ -25,6 +25,7 @@ ext { imgscalr = '4.2' exifExtractor = '2.19.0' therapiVersion = '0.13.0' + bouncycastleVersion = '1.80' } javaPlatform { @@ -37,6 +38,7 @@ dependencies { constraints { api "org.springdoc:springdoc-openapi-starter-webflux-ui:$springDocOpenAPI" api 'org.openapi4j:openapi-schema-validator:1.0.7' + api "org.bouncycastle:bcpkix-jdk18on:$bouncycastleVersion" // Apache Lucene api "org.apache.lucene:lucene-core:$lucene"