Skip to content

Commit 64d5ab5

Browse files
authored
Merge branch 'spring-projects:main' into main
2 parents d42da04 + c1adeef commit 64d5ab5

File tree

43 files changed

+2063
-102
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+2063
-102
lines changed

.github/dependabot.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,15 @@ updates:
9494
- dependency-name: "*"
9595
update-types: [ "version-update:semver-major", "version-update:semver-minor" ]
9696

97+
- package-ecosystem: "gradle"
98+
target-branch: "docs-build"
99+
directory: "/"
100+
schedule:
101+
interval: "daily"
102+
time: "03:00"
103+
timezone: "Etc/UTC"
104+
labels: [ "type: dependency-upgrade" ]
105+
97106
# GitHub Actions
98107

99108
- package-ecosystem: github-actions

.github/workflows/continuous-integration-workflow.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ jobs:
6060
distribution: 'temurin'
6161
cache: 'gradle'
6262
- name: Set up Gradle
63-
uses: gradle/gradle-build-action@v2
63+
uses: gradle/gradle-build-action@v3
6464
- name: Set up gradle user name
6565
run: echo 'systemProp.user.name=spring-builds+github' >> gradle.properties
6666
- name: Build with Gradle
@@ -254,7 +254,7 @@ jobs:
254254
./gradlew createGitHubRelease -PnextVersion=$VERSION -Pbranch=$BRANCH -PcreateRelease=true -PgitHubAccessToken=$TOKEN
255255
- name: Announce Release on Slack
256256
id: spring-security-announcing
257-
uses: slackapi/slack-github-action@v1.24.0
257+
uses: slackapi/slack-github-action@v1.25.0
258258
with:
259259
payload: |
260260
{
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# This workflow is an adaptation from https://github.com/spring-projects/spring-integration/blob/main/.github/workflows/merge-dependabot-pr.yml
2+
# and https://github.com/spring-io/spring-github-workflows/blob/main/.github/workflows/spring-merge-dependabot-pr.yml
3+
4+
name: Edit Dependabot PR
5+
6+
on:
7+
pull_request:
8+
9+
run-name: Edit Dependabot PR ${{ github.ref_name }}
10+
11+
env:
12+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
13+
14+
jobs:
15+
edit-dependabot-pr:
16+
runs-on: ubuntu-latest
17+
if: github.actor == 'dependabot[bot]'
18+
permissions: write-all
19+
steps:
20+
21+
- uses: actions/checkout@v4
22+
with:
23+
show-progress: false
24+
25+
- uses: actions/setup-java@v4
26+
with:
27+
distribution: temurin
28+
java-version: 17
29+
30+
- name: Dependabot metadata
31+
id: metadata
32+
uses: dependabot/fetch-metadata@v1
33+
with:
34+
github-token: ${{ env.GH_TOKEN }}
35+
36+
- name: Set Milestone to Dependabot pull request
37+
id: set-milestone
38+
run: |
39+
if test -f pom.xml
40+
then
41+
CURRENT_VERSION=$(mvn help:evaluate -Dexpression="project.version" -q -DforceStdout)
42+
else
43+
CURRENT_VERSION=$(cat gradle.properties | sed -n '/^version=/ { s/^version=//;p }')
44+
fi
45+
export CANDIDATE_VERSION=${CURRENT_VERSION/-SNAPSHOT}
46+
MILESTONE=$(gh api repos/$GITHUB_REPOSITORY/milestones --jq 'map(select(.due_on != null and (.title | startswith(env.CANDIDATE_VERSION)))) | .[0] | .title')
47+
48+
if [ -z $MILESTONE ]
49+
then
50+
gh run cancel ${{ github.run_id }}
51+
echo "::warning title=Cannot merge::No scheduled milestone for $CURRENT_VERSION version"
52+
else
53+
gh pr edit ${{ github.event.pull_request.number }} --milestone $MILESTONE
54+
echo mergeEnabled=true >> $GITHUB_OUTPUT
55+
fi

README.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ image::https://badges.gitter.im/Join%20Chat.svg[Gitter,link=https://gitter.im/sp
22

33
image:https://github.com/spring-projects/spring-security/actions/workflows/continuous-integration-workflow.yml/badge.svg?branch=main["Build Status", link="https://github.com/spring-projects/spring-security/actions/workflows/continuous-integration-workflow.yml"]
44

5-
image:https://img.shields.io/badge/Revved%20up%20by-Gradle%20Enterprise-06A0CE?logo=Gradle&labelColor=02303A["Revved up by Gradle Enterprise", link="https://ge.spring.io/scans?search.rootProjectNames=spring-security"]
5+
image:https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A["Revved up by Develocity", link="https://ge.spring.io/scans?search.rootProjectNames=spring-security"]
66

77
= Spring Security
88

config/src/main/java/org/springframework/security/config/web/server/OidcBackChannelLogoutReactiveAuthenticationManager.java

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -85,17 +85,14 @@ public Mono<Authentication> authenticate(Authentication authentication) throws A
8585

8686
private Mono<Jwt> decode(ClientRegistration registration, String token) {
8787
ReactiveJwtDecoder logoutTokenDecoder = this.logoutTokenDecoderFactory.createDecoder(registration);
88-
try {
89-
return logoutTokenDecoder.decode(token);
90-
}
91-
catch (BadJwtException failed) {
92-
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST, failed.getMessage(),
93-
"https://openid.net/specs/openid-connect-backchannel-1_0.html#Validation");
94-
return Mono.error(new OAuth2AuthenticationException(error, failed));
95-
}
96-
catch (Exception failed) {
97-
return Mono.error(new AuthenticationServiceException(failed.getMessage(), failed));
98-
}
88+
return logoutTokenDecoder.decode(token).onErrorResume(Exception.class, (ex) -> {
89+
if (ex instanceof BadJwtException) {
90+
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST, ex.getMessage(),
91+
"https://openid.net/specs/openid-connect-backchannel-1_0.html#Validation");
92+
return Mono.error(new OAuth2AuthenticationException(error, ex));
93+
}
94+
return Mono.error(new AuthenticationServiceException(ex.getMessage(), ex));
95+
});
9996
}
10097

10198
/**

config/src/main/kotlin/org/springframework/security/config/annotation/web/FormLoginDsl.kt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 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.
@@ -38,6 +38,8 @@ import jakarta.servlet.http.HttpServletRequest
3838
* @property loginProcessingUrl the URL to validate the credentials
3939
* @property permitAll whether to grant access to the urls for [failureUrl] as well as
4040
* for the [HttpSecurityBuilder], the [loginPage] and [loginProcessingUrl] for every user
41+
* @property usernameParameter the HTTP parameter to look for the username when performing authentication
42+
* @property passwordParameter the HTTP parameter to look for the password when performing authentication
4143
*/
4244
@SecurityMarker
4345
class FormLoginDsl {
@@ -48,6 +50,8 @@ class FormLoginDsl {
4850
var loginProcessingUrl: String? = null
4951
var permitAll: Boolean? = null
5052
var authenticationDetailsSource: AuthenticationDetailsSource<HttpServletRequest, *>? = null
53+
var usernameParameter: String? = null
54+
var passwordParameter: String? = null
5155

5256
private var defaultSuccessUrlOption: Pair<String, Boolean>? = null
5357

@@ -95,6 +99,8 @@ class FormLoginDsl {
9599
authenticationSuccessHandler?.also { login.successHandler(authenticationSuccessHandler) }
96100
authenticationFailureHandler?.also { login.failureHandler(authenticationFailureHandler) }
97101
authenticationDetailsSource?.also { login.authenticationDetailsSource(authenticationDetailsSource) }
102+
usernameParameter?.also { login.usernameParameter(usernameParameter) }
103+
passwordParameter?.also { login.passwordParameter(passwordParameter) }
98104
if (disabled) {
99105
login.disable()
100106
}

config/src/test/kotlin/org/springframework/security/config/annotation/web/FormLoginDslTests.kt

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2023 the original author or authors.
2+
* Copyright 2002-2024 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.
@@ -33,6 +33,7 @@ import org.springframework.security.config.test.SpringTestContextExtension
3333
import org.springframework.security.core.userdetails.User
3434
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin
3535
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf
36+
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated
3637
import org.springframework.security.web.SecurityFilterChain
3738
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
3839
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler
@@ -367,6 +368,50 @@ class FormLoginDslTests {
367368
verify(exactly = 1) { CustomAuthenticationDetailsSourceConfig.AUTHENTICATION_DETAILS_SOURCE.buildDetails(any()) }
368369
}
369370

371+
@Configuration
372+
@EnableWebSecurity
373+
open class CustomUsernameParameterConfig {
374+
@Bean
375+
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
376+
http {
377+
formLogin {
378+
usernameParameter = "custom-username"
379+
}
380+
}
381+
return http.build()
382+
}
383+
}
384+
385+
@Test
386+
fun `form login when custom username parameter then used`() {
387+
this.spring.register(CustomUsernameParameterConfig::class.java, UserConfig::class.java).autowire()
388+
389+
this.mockMvc.perform(formLogin().userParameter("custom-username"))
390+
.andExpect(authenticated())
391+
}
392+
393+
@Configuration
394+
@EnableWebSecurity
395+
open class CustomPasswordParameterConfig {
396+
@Bean
397+
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
398+
http {
399+
formLogin {
400+
passwordParameter = "custom-password"
401+
}
402+
}
403+
return http.build()
404+
}
405+
}
406+
407+
@Test
408+
fun `form login when custom password parameter then used`() {
409+
this.spring.register(CustomPasswordParameterConfig::class.java, UserConfig::class.java).autowire()
410+
411+
this.mockMvc.perform(formLogin().passwordParam("custom-password"))
412+
.andExpect(authenticated())
413+
}
414+
370415
@Configuration
371416
@EnableWebSecurity
372417
open class CustomAuthenticationDetailsSourceConfig {

crypto/spring-security-crypto.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ apply plugin: 'io.spring.convention.spring-module'
33
dependencies {
44
management platform(project(":spring-security-dependencies"))
55
optional 'org.springframework:spring-jcl'
6+
optional 'org.springframework:spring-core'
67
optional 'org.bouncycastle:bcpkix-jdk15on'
7-
8+
89
testImplementation "org.assertj:assertj-core"
910
testImplementation "org.junit.jupiter:junit-jupiter-api"
1011
testImplementation "org.junit.jupiter:junit-jupiter-params"
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*
2+
* Copyright 2013-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.crypto.encrypt;
18+
19+
import java.io.InputStream;
20+
import java.security.KeyFactory;
21+
import java.security.KeyPair;
22+
import java.security.KeyStore;
23+
import java.security.PublicKey;
24+
import java.security.cert.Certificate;
25+
import java.security.interfaces.RSAPrivateCrtKey;
26+
import java.security.spec.RSAPublicKeySpec;
27+
28+
import org.springframework.core.io.Resource;
29+
import org.springframework.util.StringUtils;
30+
31+
/**
32+
* @author Dave Syer
33+
* @author Tim Ysewyn
34+
* @since 6.3
35+
*/
36+
public class KeyStoreKeyFactory {
37+
38+
private final Resource resource;
39+
40+
private final char[] password;
41+
42+
private KeyStore store;
43+
44+
private final Object lock = new Object();
45+
46+
private final String type;
47+
48+
public KeyStoreKeyFactory(Resource resource, char[] password) {
49+
this(resource, password, type(resource));
50+
}
51+
52+
private static String type(Resource resource) {
53+
String ext = StringUtils.getFilenameExtension(resource.getFilename());
54+
return (ext != null) ? ext : "jks";
55+
}
56+
57+
public KeyStoreKeyFactory(Resource resource, char[] password, String type) {
58+
this.resource = resource;
59+
this.password = password;
60+
this.type = type;
61+
}
62+
63+
public KeyPair getKeyPair(String alias) {
64+
return getKeyPair(alias, this.password);
65+
}
66+
67+
public KeyPair getKeyPair(String alias, char[] password) {
68+
try {
69+
synchronized (this.lock) {
70+
if (this.store == null) {
71+
synchronized (this.lock) {
72+
this.store = KeyStore.getInstance(this.type);
73+
try (InputStream stream = this.resource.getInputStream()) {
74+
this.store.load(stream, this.password);
75+
}
76+
}
77+
}
78+
}
79+
RSAPrivateCrtKey key = (RSAPrivateCrtKey) this.store.getKey(alias, password);
80+
Certificate certificate = this.store.getCertificate(alias);
81+
PublicKey publicKey = null;
82+
if (certificate != null) {
83+
publicKey = certificate.getPublicKey();
84+
}
85+
else if (key != null) {
86+
RSAPublicKeySpec spec = new RSAPublicKeySpec(key.getModulus(), key.getPublicExponent());
87+
publicKey = KeyFactory.getInstance("RSA").generatePublic(spec);
88+
}
89+
return new KeyPair(publicKey, key);
90+
}
91+
catch (Exception ex) {
92+
throw new IllegalStateException("Cannot load keys from store: " + this.resource, ex);
93+
}
94+
}
95+
96+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2013-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.security.crypto.encrypt;
18+
19+
/**
20+
* @author Dave Syer
21+
* @since 6.3
22+
*/
23+
public enum RsaAlgorithm {
24+
25+
DEFAULT("RSA", 117), OAEP("RSA/ECB/OAEPPadding", 86);
26+
27+
private final String name;
28+
29+
private final int maxLength;
30+
31+
RsaAlgorithm(String name, int maxLength) {
32+
this.name = name;
33+
this.maxLength = maxLength;
34+
}
35+
36+
public String getJceName() {
37+
return this.name;
38+
}
39+
40+
public int getMaxLength() {
41+
return this.maxLength;
42+
}
43+
44+
}

0 commit comments

Comments
 (0)