Skip to content

Provide a ReactiveSecurityEvaluationContextExtension via spring-security-data #8958

@christophstrobl

Description

@christophstrobl
Member

Expected Behavior

Add a ReactiveSecurityEvaluationContextExtension (similar to the existing SecurityEvaluationContextExtension) that provides access to the Authentication object obtained from a Reactor Context, so that it can be used within SpEL expressions of annotated Spring Data queries.

@Query("select m from Message m where m.to.id = ?#{ principal?.id }")
Flux<Message> findInbox();

Context

Spring Data Commons 2.4.0.M2 now contains the required SPI (ReactiveEvaluationContextExtension) to implement reactive SpEL evaluation extensions. (see: DATACMNS-1108)

Activity

added
in: dataAn issue in spring-security-data
and removed on Aug 13, 2020
added this to the 5.5.x milestone on Aug 13, 2020
ThomasVitale

ThomasVitale commented on May 5, 2021

@ThomasVitale
Contributor

@jzheaux can I help with this task?

jzheaux

jzheaux commented on May 6, 2021

@jzheaux
Contributor

Sure, @ThomasVitale, thanks for the offer!

Since ReactiveEvaluationContextExtension returns a Mono<? extends EvaluationContextExtension>, let's try and reuse SecurityEvaluationContextExtension. I'm thinking something like:

ReactiveSecurityContextHolder.getContext()
    .map(SecurityContext::getAuthentication)
    .map(SecurityEvaluationContextExtension::new)

would work nicely.

@christophstrobl, does getExtensionId need to return something different from SecurityEvaluationContextExtension ("security"), and if so, is there a naming convention that's being followed?

modified the milestones: 5.5.x, 5.6.0-M1 on May 6, 2021
antoinechamot

antoinechamot commented on Jul 17, 2021

@antoinechamot

It doesn't work I have "Authentication object cannot be null" with

 @Bean
    ReactiveEvaluationContextExtension securityExtension(){

        return new ReactiveEvaluationContextExtension() {

            @Override
            public String getExtensionId() {
                return "security";
            }

            @Override
            public Mono<? extends EvaluationContextExtension> getExtension() {
                return ReactiveSecurityContextHolder.getContext()
                        .map(SecurityContext::getAuthentication)
                        .map(SecurityEvaluationContextExtension::new);
            }
        };
    }

And
@Query("{ $or :[ {'authorId': ?#{principal?.subject}}, {'assigneeId': ?#{principal?.subject}} ] }")

modified the milestones: 5.6.0-M1, 5.6.0-M2 on Jul 19, 2021
jzheaux

jzheaux commented on Jul 19, 2021

@jzheaux
Contributor

@ThomasVitale is this something you are able to add?

Thanks for trying this out @antoinechamot. I can confirm that it works when I modify the MongoDB Spring Data example to include Spring Security and the code you posted. I wonder if your application is using reactive repositories and if the user is authenticated.

14 remaining items

added this to the 5.7.0-M1 milestone on Nov 12, 2021
modified the milestones: 5.7.0-M1, 5.7.0-M2 on Jan 14, 2022
svenuthe

svenuthe commented on Mar 2, 2022

@svenuthe

It seems that the imperative SecurityEvaluationContextExtension is registered as well and Spring Data cannot distinguish which one it should use. Probably worth its own ticket.

Originally posted by @mp911de in spring-projects/spring-data-r2dbc#658 (comment)

According to my and @mp911de findings a second SecurityEvaluationContextExtension is registered by spring-data which prevents the simple use of a ReactiveEvaluationContextExtension bean.

@christophstrobl I fixed this by setting the imperative extension to null:

    @Bean
    fun reactiveSecurityContextExtension(): ReactiveEvaluationContextExtension =
        object : ReactiveEvaluationContextExtension {
            override fun getExtensionId(): String = "reactiveSecurity"

            override fun getExtension(): Mono<out EvaluationContextExtension> =
                ReactiveSecurityContextHolder
                    .getContext()
                    .map { it.authentication as JwtAuthenticationToken }
                    .map { SecurityEvaluationContextExtension(it) }

        }

    @Bean
    fun securityContextExtension(): SecurityEvaluationContextExtension? {
        return null
    }

@marcusdacoregio Will this behavior be changed in the future?

jzheaux

jzheaux commented on Mar 11, 2022

@jzheaux
Contributor

@svenuthe, I think Spring Data is willing to take a look if you file a separate issue. I'm not sure there's anything Security can do until that is addressed.

ThomasVitale

ThomasVitale commented on Mar 14, 2022

@ThomasVitale
Contributor

@jzheaux ASecurityEvaluationContextExtension bean is configured in SecurityDataConfiguration, which is imported in SecurityAutoConfiguration. Should a new issue be opened in Spring Data, in Spring Boot, or would the change be part of this one?

I guess that one option would be adding an extra condition on the SecurityEvaluationContextExtension bean so that it's not created in a reactive application if we have already a ReactiveEvaluationContextExtension bean. Or perhaps it should be Spring Data responsible for choosing the proper bean if both are present?

modified the milestones: 5.7.0-RC1, 5.8.x on Apr 18, 2022
removed this from the 5.8.x milestone on Jun 9, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

in: dataAn issue in spring-security-datatype: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @rwinch@christophstrobl@jzheaux@sjohnr@eleftherias

      Issue actions

        Provide a ReactiveSecurityEvaluationContextExtension via spring-security-data · Issue #8958 · spring-projects/spring-security