Skip to content

Spring Security annotations on subclasses support intercepting parent class methods. #14479

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 41 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
9f63c4f
Closes gh-13783
kse-music Jan 22, 2024
04394a6
Update Formatting
jzheaux Jan 22, 2024
7ee9744
Update Checkstyle
jzheaux Jan 22, 2024
7a8f9b4
Configure Dependabot for docs-build's build.gradle
marcusdacoregio Jan 23, 2024
bdc0bd6
Add usernameParameter and passwordParameter to FormLoginDsl
ty-v1 Jan 24, 2024
f6f28bf
Polish
kse-music Jan 25, 2024
ca10187
Enhance JWT decoding error handling
Kardeen Jan 18, 2024
44f22ee
Merge branch '5.8.x' into 6.1.x
jzheaux Jan 26, 2024
84c45ad
Merge branch '6.1.x' into 6.2.x
jzheaux Jan 26, 2024
01b7ad4
Merge branch '6.2.x'
jzheaux Jan 26, 2024
602d2be
Automatically assign milestone to Dependabot PR
marcusdacoregio Jan 26, 2024
27ebeef
Fix Failing Test
jzheaux Jan 26, 2024
45f8ab3
Add permission to Edit Dependabot PR workflow
marcusdacoregio Jan 29, 2024
6f7b9bb
Migrate spring-security-rsa into spring-security-crypto
marcusdacoregio Dec 27, 2023
3a53422
Fix Failing Test
jzheaux Jan 26, 2024
ee45d6c
Merge branch '6.2.x'
jzheaux Jan 30, 2024
a808c13
Enhance IpAddressMatcher performance
ahmd-nabil Jan 26, 2024
6e1bcfe
Add argument resolver for SecurityContext
NerminKarapandzic Jan 13, 2024
8a75382
Bump slackapi/slack-github-action from 1.24.0 to 1.25.0
dependabot[bot] Jan 29, 2024
b0fe1da
Merge branch '5.8.x' into 6.1.x
jzheaux Jan 30, 2024
810818b
Merge branch '6.1.x' into 6.2.x
jzheaux Jan 30, 2024
0dcd7e7
Merge branch '6.2.x'
jzheaux Jan 30, 2024
7011930
Bump gradle/gradle-build-action from 2 to 3
dependabot[bot] Jan 29, 2024
ebfe8e3
Merge branch '5.8.x' into 6.1.x
jzheaux Jan 30, 2024
3b615c8
Merge branch '6.1.x' into 6.2.x
jzheaux Jan 30, 2024
77e1935
Merge branch '6.2.x'
jzheaux Jan 30, 2024
5b281ee
Update Revved up by Develocity badge
erichaagdev Jan 18, 2024
93c2d1c
Disable spring-security-rsa tests on Windows
marcusdacoregio Jan 30, 2024
d9d22c7
Add support for nested username attribute in DefaultOAuth2User
ahmd-nabil Dec 8, 2023
04f0f25
Polish DefaultOAuth2UserService
ahmd-nabil Jan 23, 2024
d7599ab
Polish setAttributesConverter
jzheaux Jan 30, 2024
c1adeef
Add validation IpAddressMatcher
FdHerrera Jan 25, 2024
cb84efd
Fix command in CONTRIBUTING.adoc
ty-v1 Jan 24, 2024
fbb35a1
Typo: Update ldap.adoc
boulce Jan 30, 2024
49f447f
Update session-management.adoc
boulce Jan 31, 2024
df46169
Merge branch '6.1.x' into 6.2.x
marcusdacoregio Jan 31, 2024
c2dc610
Merge branch '6.2.x'
marcusdacoregio Jan 31, 2024
6066245
Add Passive Serialization to What's New
marcusdacoregio Jan 31, 2024
ceb5100
Optimize Saml2MetadataFilter
leshalv Jan 20, 2024
d2bc340
Fix Method Security Docs Typo
irerin07 Jan 20, 2024
c62f760
Merge remote-tracking branch 'origin/gh-13783' into gh-13783
kse-music Feb 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@ updates:
- dependency-name: "*"
update-types: [ "version-update:semver-major", "version-update:semver-minor" ]

- package-ecosystem: "gradle"
target-branch: "docs-build"
directory: "/"
schedule:
interval: "daily"
time: "03:00"
timezone: "Etc/UTC"
labels: [ "type: dependency-upgrade" ]

# GitHub Actions

- package-ecosystem: github-actions
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/continuous-integration-workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
distribution: 'temurin'
cache: 'gradle'
- name: Set up Gradle
uses: gradle/gradle-build-action@v2
uses: gradle/gradle-build-action@v3
- name: Set up gradle user name
run: echo 'systemProp.user.name=spring-builds+github' >> gradle.properties
- name: Build with Gradle
Expand Down Expand Up @@ -254,7 +254,7 @@ jobs:
./gradlew createGitHubRelease -PnextVersion=$VERSION -Pbranch=$BRANCH -PcreateRelease=true -PgitHubAccessToken=$TOKEN
- name: Announce Release on Slack
id: spring-security-announcing
uses: slackapi/slack-github-action@v1.24.0
uses: slackapi/slack-github-action@v1.25.0
with:
payload: |
{
Expand Down
55 changes: 55 additions & 0 deletions .github/workflows/edit-dependabot-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# This workflow is an adaptation from https://github.com/spring-projects/spring-integration/blob/main/.github/workflows/merge-dependabot-pr.yml
# and https://github.com/spring-io/spring-github-workflows/blob/main/.github/workflows/spring-merge-dependabot-pr.yml

name: Edit Dependabot PR

on:
pull_request:

run-name: Edit Dependabot PR ${{ github.ref_name }}

env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

jobs:
edit-dependabot-pr:
runs-on: ubuntu-latest
if: github.actor == 'dependabot[bot]'
permissions: write-all
steps:

- uses: actions/checkout@v4
with:
show-progress: false

- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17

- name: Dependabot metadata
id: metadata
uses: dependabot/fetch-metadata@v1
with:
github-token: ${{ env.GH_TOKEN }}

- name: Set Milestone to Dependabot pull request
id: set-milestone
run: |
if test -f pom.xml
then
CURRENT_VERSION=$(mvn help:evaluate -Dexpression="project.version" -q -DforceStdout)
else
CURRENT_VERSION=$(cat gradle.properties | sed -n '/^version=/ { s/^version=//;p }')
fi
export CANDIDATE_VERSION=${CURRENT_VERSION/-SNAPSHOT}
MILESTONE=$(gh api repos/$GITHUB_REPOSITORY/milestones --jq 'map(select(.due_on != null and (.title | startswith(env.CANDIDATE_VERSION)))) | .[0] | .title')

if [ -z $MILESTONE ]
then
gh run cancel ${{ github.run_id }}
echo "::warning title=Cannot merge::No scheduled milestone for $CURRENT_VERSION version"
else
gh pr edit ${{ github.event.pull_request.number }} --milestone $MILESTONE
echo mergeEnabled=true >> $GITHUB_OUTPUT
fi
2 changes: 1 addition & 1 deletion CONTRIBUTING.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ See https://github.com/spring-projects/spring-security/tree/main#building-from-s

The wiki pages https://github.com/spring-projects/spring-framework/wiki/Code-Style[Code Style] and https://github.com/spring-projects/spring-framework/wiki/IntelliJ-IDEA-Editor-Settings[IntelliJ IDEA Editor Settings] define the source file coding standards we use along with some IDEA editor settings we customize.

To format the code as well as check the style, run `./gradle format check`.
To format the code as well as check the style, run `./gradlew format check`.

[[submit-a-pull-request]]
=== Submit a Pull Request
Expand Down
2 changes: 1 addition & 1 deletion README.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ image::https://badges.gitter.im/Join%20Chat.svg[Gitter,link=https://gitter.im/sp

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"]

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"]
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"]

= Spring Security

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,17 +85,14 @@ public Mono<Authentication> authenticate(Authentication authentication) throws A

private Mono<Jwt> decode(ClientRegistration registration, String token) {
ReactiveJwtDecoder logoutTokenDecoder = this.logoutTokenDecoderFactory.createDecoder(registration);
try {
return logoutTokenDecoder.decode(token);
}
catch (BadJwtException failed) {
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST, failed.getMessage(),
"https://openid.net/specs/openid-connect-backchannel-1_0.html#Validation");
return Mono.error(new OAuth2AuthenticationException(error, failed));
}
catch (Exception failed) {
return Mono.error(new AuthenticationServiceException(failed.getMessage(), failed));
}
return logoutTokenDecoder.decode(token).onErrorResume(Exception.class, (ex) -> {
if (ex instanceof BadJwtException) {
OAuth2Error error = new OAuth2Error(OAuth2ErrorCodes.INVALID_REQUEST, ex.getMessage(),
"https://openid.net/specs/openid-connect-backchannel-1_0.html#Validation");
return Mono.error(new OAuth2AuthenticationException(error, ex));
}
return Mono.error(new AuthenticationServiceException(ex.getMessage(), ex));
});
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -38,6 +38,8 @@ import jakarta.servlet.http.HttpServletRequest
* @property loginProcessingUrl the URL to validate the credentials
* @property permitAll whether to grant access to the urls for [failureUrl] as well as
* for the [HttpSecurityBuilder], the [loginPage] and [loginProcessingUrl] for every user
* @property usernameParameter the HTTP parameter to look for the username when performing authentication
* @property passwordParameter the HTTP parameter to look for the password when performing authentication
*/
@SecurityMarker
class FormLoginDsl {
Expand All @@ -48,6 +50,8 @@ class FormLoginDsl {
var loginProcessingUrl: String? = null
var permitAll: Boolean? = null
var authenticationDetailsSource: AuthenticationDetailsSource<HttpServletRequest, *>? = null
var usernameParameter: String? = null
var passwordParameter: String? = null

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

Expand Down Expand Up @@ -95,6 +99,8 @@ class FormLoginDsl {
authenticationSuccessHandler?.also { login.successHandler(authenticationSuccessHandler) }
authenticationFailureHandler?.also { login.failureHandler(authenticationFailureHandler) }
authenticationDetailsSource?.also { login.authenticationDetailsSource(authenticationDetailsSource) }
usernameParameter?.also { login.usernameParameter(usernameParameter) }
passwordParameter?.also { login.passwordParameter(passwordParameter) }
if (disabled) {
login.disable()
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -33,6 +33,7 @@ import org.springframework.security.config.test.SpringTestContextExtension
import org.springframework.security.core.userdetails.User
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.formLogin
import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf
import org.springframework.security.test.web.servlet.response.SecurityMockMvcResultMatchers.authenticated
import org.springframework.security.web.SecurityFilterChain
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler
Expand Down Expand Up @@ -367,6 +368,50 @@ class FormLoginDslTests {
verify(exactly = 1) { CustomAuthenticationDetailsSourceConfig.AUTHENTICATION_DETAILS_SOURCE.buildDetails(any()) }
}

@Configuration
@EnableWebSecurity
open class CustomUsernameParameterConfig {
@Bean
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
formLogin {
usernameParameter = "custom-username"
}
}
return http.build()
}
}

@Test
fun `form login when custom username parameter then used`() {
this.spring.register(CustomUsernameParameterConfig::class.java, UserConfig::class.java).autowire()

this.mockMvc.perform(formLogin().userParameter("custom-username"))
.andExpect(authenticated())
}

@Configuration
@EnableWebSecurity
open class CustomPasswordParameterConfig {
@Bean
open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain {
http {
formLogin {
passwordParameter = "custom-password"
}
}
return http.build()
}
}

@Test
fun `form login when custom password parameter then used`() {
this.spring.register(CustomPasswordParameterConfig::class.java, UserConfig::class.java).autowire()

this.mockMvc.perform(formLogin().passwordParam("custom-password"))
.andExpect(authenticated())
}

@Configuration
@EnableWebSecurity
open class CustomAuthenticationDetailsSourceConfig {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -29,6 +29,7 @@
* For internal use only, as this contract is likely to change
*
* @author Evgeniy Cheban
* @author DingHao
*/
abstract class AbstractExpressionAttributeRegistry<T extends ExpressionAttribute> {

Expand Down Expand Up @@ -67,4 +68,8 @@ final T getAttribute(Method method, Class<?> targetClass) {
@NonNull
abstract T resolveAttribute(Method method, Class<?> targetClass);

Class<?> targetClass(Method method, Class<?> targetClass) {
return (targetClass != null) ? targetClass : method.getDeclaringClass();
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2023 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -44,6 +44,7 @@
*
* @author Evgeniy Cheban
* @author Josh Cummings
* @author DingHao
* @since 5.6
*/
public final class Jsr250AuthorizationManager implements AuthorizationManager<MethodInvocation> {
Expand Down Expand Up @@ -121,7 +122,8 @@ AuthorizationManager<MethodInvocation> resolveManager(Method method, Class<?> ta
private Annotation findJsr250Annotation(Method method, Class<?> targetClass) {
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
Annotation annotation = findAnnotation(specificMethod);
return (annotation != null) ? annotation : findAnnotation(specificMethod.getDeclaringClass());
return (annotation != null) ? annotation
: findAnnotation((targetClass != null) ? targetClass : specificMethod.getDeclaringClass());
}

private Annotation findAnnotation(Method method) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -31,6 +31,7 @@
* For internal use only, as this contract is likely to change.
*
* @author Evgeniy Cheban
* @author DingHao
* @since 5.8
*/
final class PostAuthorizeExpressionAttributeRegistry extends AbstractExpressionAttributeRegistry<ExpressionAttribute> {
Expand All @@ -54,7 +55,7 @@ MethodSecurityExpressionHandler getExpressionHandler() {
@Override
ExpressionAttribute resolveAttribute(Method method, Class<?> targetClass) {
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
PostAuthorize postAuthorize = findPostAuthorizeAnnotation(specificMethod);
PostAuthorize postAuthorize = findPostAuthorizeAnnotation(specificMethod, targetClass);
if (postAuthorize == null) {
return ExpressionAttribute.NULL_ATTRIBUTE;
}
Expand All @@ -63,10 +64,10 @@ ExpressionAttribute resolveAttribute(Method method, Class<?> targetClass) {
return new ExpressionAttribute(postAuthorizeExpression);
}

private PostAuthorize findPostAuthorizeAnnotation(Method method) {
private PostAuthorize findPostAuthorizeAnnotation(Method method, Class<?> targetClass) {
PostAuthorize postAuthorize = AuthorizationAnnotationUtils.findUniqueAnnotation(method, PostAuthorize.class);
return (postAuthorize != null) ? postAuthorize
: AuthorizationAnnotationUtils.findUniqueAnnotation(method.getDeclaringClass(), PostAuthorize.class);
return (postAuthorize != null) ? postAuthorize : AuthorizationAnnotationUtils
.findUniqueAnnotation(targetClass(method, targetClass), PostAuthorize.class);
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -30,6 +30,7 @@
* For internal use only, as this contract is likely to change.
*
* @author Evgeniy Cheban
* @author DingHao
* @since 5.8
*/
final class PostFilterExpressionAttributeRegistry extends AbstractExpressionAttributeRegistry<ExpressionAttribute> {
Expand All @@ -53,7 +54,7 @@ MethodSecurityExpressionHandler getExpressionHandler() {
@Override
ExpressionAttribute resolveAttribute(Method method, Class<?> targetClass) {
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
PostFilter postFilter = findPostFilterAnnotation(specificMethod);
PostFilter postFilter = findPostFilterAnnotation(specificMethod, targetClass);
if (postFilter == null) {
return ExpressionAttribute.NULL_ATTRIBUTE;
}
Expand All @@ -62,10 +63,10 @@ ExpressionAttribute resolveAttribute(Method method, Class<?> targetClass) {
return new ExpressionAttribute(postFilterExpression);
}

private PostFilter findPostFilterAnnotation(Method method) {
private PostFilter findPostFilterAnnotation(Method method, Class<?> targetClass) {
PostFilter postFilter = AuthorizationAnnotationUtils.findUniqueAnnotation(method, PostFilter.class);
return (postFilter != null) ? postFilter
: AuthorizationAnnotationUtils.findUniqueAnnotation(method.getDeclaringClass(), PostFilter.class);
: AuthorizationAnnotationUtils.findUniqueAnnotation(targetClass(method, targetClass), PostFilter.class);
}

}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -31,6 +31,7 @@
* For internal use only, as this contract is likely to change.
*
* @author Evgeniy Cheban
* @author DingHao
* @since 5.8
*/
final class PreAuthorizeExpressionAttributeRegistry extends AbstractExpressionAttributeRegistry<ExpressionAttribute> {
Expand Down Expand Up @@ -58,7 +59,7 @@ MethodSecurityExpressionHandler getExpressionHandler() {
@Override
ExpressionAttribute resolveAttribute(Method method, Class<?> targetClass) {
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
PreAuthorize preAuthorize = findPreAuthorizeAnnotation(specificMethod);
PreAuthorize preAuthorize = findPreAuthorizeAnnotation(specificMethod, targetClass);
if (preAuthorize == null) {
return ExpressionAttribute.NULL_ATTRIBUTE;
}
Expand All @@ -67,10 +68,10 @@ ExpressionAttribute resolveAttribute(Method method, Class<?> targetClass) {
return new ExpressionAttribute(preAuthorizeExpression);
}

private PreAuthorize findPreAuthorizeAnnotation(Method method) {
private PreAuthorize findPreAuthorizeAnnotation(Method method, Class<?> targetClass) {
PreAuthorize preAuthorize = AuthorizationAnnotationUtils.findUniqueAnnotation(method, PreAuthorize.class);
return (preAuthorize != null) ? preAuthorize
: AuthorizationAnnotationUtils.findUniqueAnnotation(method.getDeclaringClass(), PreAuthorize.class);
return (preAuthorize != null) ? preAuthorize : AuthorizationAnnotationUtils
.findUniqueAnnotation(targetClass(method, targetClass), PreAuthorize.class);
}

}
Loading