spring-projects / spring-security

Spring Security
http://spring.io/projects/spring-security
Apache License 2.0
8.55k stars 5.79k forks source link

Add OpenFGA Support #14121

Open rwinch opened 7 months ago

rwinch commented 7 months ago

We should look into adding OpenFGA support See https://openfga.dev/

Some NOTES for myself:

aaguiarz commented 7 months ago

Hi @rwinch

It would be awesome! Let me know if we can help in any way.

Crain-32 commented 6 months ago

@rwinch I've looked into this for work before, wouldn't mind helping out.

What paths have been discussed? Is this an integration to the hasPermission SpEL? Or the Domain Object Security?

jimmyjames commented 4 months ago

:wave: Hi @rwinch,

We (at OpenFGA) would love to help with this! I am also curious about potential paths here, similar to @Crain-32 an extension to the hasPermission SpEL comes to mind, or perhaps a custom named PermissionEvaluator, but I'm interested in other potential paths.

I think any support should also provide an easy way to write authz data to OpenFGA; the OpenFGA Java SDK can be used to handle both read/writes, perhaps it could be leveraged?

rwinch commented 4 months ago

Hello everyone!

Sorry for the delayed response. We haven't outlined how the features would work yet, but I'm open to suggestions. The more concrete the suggestions the easier it will be for me to understand.

We will likely use a library like OpenFGA Java SDK to do most of the work and provide implementations of Spring Security interfaces (perhaps AuthorizationManager) to provide Spring Security specific features using OpenFGA.

Crain-32 commented 4 months ago

I think part of the issue with concrete suggestions is it is rather hard to figure out where to fit the concept (for me personally) in Spring right now.

For example reading the documentation on the ACL Module, it almost sounds like OpenFGA would be a good fit there. However looking at the Repository the code has only been maintained, which is fantastic from a library standard, but concerning if looking to add to it.

I think you could model OpenFGA decently okay in a custom PermissionEvaluator, however that is only the Authorization Decision, whereas the updating/creation of the Authorization Tuples can't be modeled corrected there. Meaning the creation of another module (Spring-OpenFGA?) or some other type of interface would be required to really make sure the creation/update portion of the SDK is available to users in a Spring like fashion.

rwinch commented 4 months ago

@Crain-32 Thank you for your response.

At this time, I think that we'd probably implement the authorization in a new AuthorizationManager interface because it is the modern API for authorization in Spring Security that allows returning a richer response.

I don't think we would provide code for managing the relations because we typically only provide integration with Spring and the management of the relations can be done with the existing OpenFGA Java SDK.

I'm curious how you imagine using OpenFGA in a Spring application. For example, do you think that you would use it in method security? If so, what do the use cases look like?

Do you think it would be used with web based authorization? Again, what would those use cases look like?

jimmyjames commented 4 months ago

@rwinch and @Crain-32, like the conversation here!

If I take a step back a bit and consider the use cases, I believe these are some of the key use cases that come to mind:

  1. Provide a way to pre- (and maybe post? need to think of specific cases where post-authorization would make sense) perform an FGA check via method security. For example, does user X have permission Y for object Z.
  2. Some sort of way to write authz data back to FGA either through the OpenFGA SDK either directly or through a wrapper we provide in Spring. I think this would have to be directly coded in the application on a case-by-case basis, as it is application specific.

Perhaps this isn't applicable to a direct integration in Spring Security, but it might provide insight into use cases - if I were looking to integrate within my company, I'd consider:

I'm not familiar with direct implementations of AuthorizationManager but I will look into it!

Also perhaps worth looking at is the Quarkus OpenFGA extension; I've not looked at it deeply but it may provide some insight.

Crain-32 commented 4 months ago

@rwinch I personal lean towards the Method Security approach, which is why I instinctively went for a custom PermissionEvaluator. From my limited perspective if I adjust my authz in the HttpSecurity bean I'd stick to simply grant checks against the Authentication, partially because the Relationship based checks that FGA are good at would be hard to express in the current Security Matcher. I believe that's currently handled by the GlobalMethodSecurityConfiguration, and I'm honestly unsure of the usage of the AuthenticationManager within that class. I'd have to give it a more thorough review.

Which also moves over to @jimmyjames comment, as if we focus on how the mapping between the Method Security Annotations and the FGA API works, we can probably rule out some options pretty quickly. If we find hasPermission lacking or wrong, I'd honestly say that having the module introduce a new hasRelationship SpEL would work. Since that would mean no special annotations or handling, we'd just get Pre/Post Filters and Authorize out of the box. Along with Native Compilation support if memory serves.

For letting the client access the OpenFGA API, I think as we push forward it would be useful to see if the SDK could have a Spring Flavored Client. I saw the OpenApi Generator auto-generated comment when I checked out the SDK yesterday, and I have an understanding that OpenApi supports Spring Clients. This would resolve the questions around "how" the user can get access to the Client, as they can just inject it as a bean where they see fit. Plus some other QoL stuff that isn't important at this stage of the conversation.

aaguiarz commented 4 months ago

@rwinch @Crain-32 we identified a few possible alternatives for implementation, would you be OK with you to jump on a quick all in the following days to align on the best path forward?

Besides the implementation questions above, which we are wondering where is the best place for the integration code to live.

rwinch commented 4 months ago

I'm curious how much of this support should be OpenFGA specific. User's can use @PreAuthorize with SpEL expressions to check permissions. For example:

@Component
class OpenFga {

    public boolean check(String user, String relation, String _object) {
        var options = new ClientCheckOptions()
          .authorizationModelId("1uHxCSuTP0VKPYSnkq1pbb1jeZw");

        var body = new ClientCheckRequest()
          .user(user)
          .relation(relation)
          ._object(_object);

        var response = fgaClient.check(body, options).get();
        return response.getAllowed();
  }
}
@PreAuthorize("@openFga.check('user:anne', 'reader', 'document:Z')")
public void securedByOpenFga() {

}

With gh-14480 we should be able to refine that quite a bit:

@Retention(RetentionPolicy.RUNTIME)
@PreAuthorize("@openFga.check({user}, {relation}, {_object})")
public @interface OpenFga {
   String user();
   String relation();
   String _object();
}
@OpenFga(user = "'user:anne'", relation="'reader'", _object = "'document:Z'")
public void securedByOpenFga() {

}

I'm not saying we don't need explicit OpenFGA support, I'm just not sure at this point. I think some concrete usecases will help us to flush things out.

What I'd like to see is someone (perhaps collaborate on) setting up some samples of use cases in a separate repository. We don't need any security, but we should have TODO comments (or better yet tests) to describe how we want things to work. Then we can start to fill in the pieces.

I've also put together gh-14595 which is a list of method security enhancements I've been thinking about. I think that these tickets will help OpenFGA support as well.

aaguiarz commented 4 months ago

Thanks @rwinch !

We were thinking of exploring the approach below as it seemed to provide a better developer experience, using custom annotations.

@Service
public class MyCustomerService {

    @FgaCheck(object = "#id", userType = "user", objectType: "doc", relation: "viewer")
    public Customer readCustomer(String id) { ... }
}

If I understand correctly, it seems pretty similar to https://github.com/spring-projects/spring-security/issues/14480.

Would it make sense to start with @PreAuthorize and once https://github.com/spring-projects/spring-security/issues/14480 is available, also support that approach?

Crain-32 commented 4 months ago

@rwinch Speaking of Test Examples, I just started working on a small project to play around with that. I think we can do pretty basic security, my plan was basically just the in-mem UserDetails Repository, and then let Spring Docker Compose handle an OpenFGA Image and a Zipkin image, that way we can check for Observability support. I'd tack in GraalVM, but native compilation has always been a headache for me.

I did a cursory glance over #14595, and I don't see anything immediately that would adjust my approach which is currently the following.

Enable OpenFGA API's to be configured and setup in a "Spring" way

Once I have that up and running I'll share it here, since having something to mess around with always helps me think about it, and will make eventual implementation go faster.

rwinch commented 4 months ago

@aaguiarz My apologies for missing your comment. I think that I may have started writing before you posted and then just didn't see it.

would you be OK with you to jump on a quick all in the following days to align on the best path forward?

I'd be happy to do this. I sent you a DM on twitter from https://twitter.com/rob_winch to start a conversation on getting a call together.

If I understand correctly, it seems pretty similar to https://github.com/spring-projects/spring-security/issues/14480.

You are correct. The idea is that once gh-14480 is done users could provide their own Bean and aAnnotation similar to what I have in my example above to provide authorization checks.

Would it make sense to start with @PreAuthorize and once https://github.com/spring-projects/spring-security/issues/14480 is available, also support that approach?

I think that this makes sense, but let's try and meet to discuss.

@Crain-32

Expose an OpenFgaPermissionEvaluator as a conditional bean, hooking into hasPermission.

I think it makes more sense to do something closer to what is suggested here as it is less verbose than specifying hasPermission

Crain-32 commented 4 months ago

@rwinch noting this more for the wider group, but your sense was correct. I attempted hooking into hasPermission, and it was just a messy grouping of builders and configuration. Otherwise users can't really specify enough to make it work within the bounds of 2-3 User defined parameters. Ended up with messy and bad code, which to be fair is my typical result, but this was worse than usual.

@aaguiarz Although I've looked into OpenFGA a decent amount, I haven't really seen it's usage in the wild. Would you be able to share any information on how dynamic the Store/Authorization Model ID are? Would at least help me wrap my head around some things.

aaguiarz commented 4 months ago

@Crain-32 for most applications, the Store ID will be always the same (you'd have a different one per dev/staging/prod environment), and the Model ID will change infrequently. They can be part of the application configuration.

aaguiarz commented 4 months ago

@Crain-32 we'll have a call with Rob next Wednesday 21st 2pm EST, if you are interested in attending please email me andres.aguiar @ openfga.dev and I'll add you.

jimmyjames commented 4 months ago

I'm going to work on a little sample repo to demonstrate some sample use cases I'm envisioning, and I'll share that here for further discussion. The goal would be to provide some simple use cases and drive discussion around the potential need for direct FGA support (and what that may look like), or if guidance is best either today or with https://github.com/spring-projects/spring-security/issues/14480.

Also @Crain-32 regarding a hasPermission implementation, my understanding is that it does not support WebFlux, and I wouldn't want us to not support reactive or have to implement separately unless required.

Crain-32 commented 4 months ago

Alright, took a bit longer to working than I wanted. @jimmyjames I'm not sure how your sample repo is going, but I got my own baseline working and pushed to here

OpenFgaClient is exposed as a Bean, and it uses a similar approach to @rwinch's earlier bean comment, but separates out the tuples to more closely replicate @aaguiarz's annotation.

I was just using OpenFGA's Api itself for playing around, but you could easily add in a database/another API if you want. Zipkin is in there to check if the OpenFGA API calls are reported for Distributed Tracing, but I haven't really configured that yet, more so to check for that once we're further along.


Regarding approaches and Webflux, I honestly haven't touched Webflux much before, so I'm just trusting whatever people say in here with regards to it. Virtual Threads have saved me from needing to learn it for work, but I assume the day will come when I'm forced to.

jimmyjames commented 4 months ago

Hey @Crain-32, that's nice! I did something similar too here. There's a configured OpenFgaClient and a simple bean to provide a check. I also included a custom FGA annotation to explore the DX of that and what the implementation might look like.

I also included an example of using Fga in a client credentials flow to demonstrate using the the principal for FGA operations.

Crain-32 commented 4 months ago

That was a wonderful call today! Thanks again for inviting me, it means a lot as someone who is relatively new to the Industry. Been thinking a lot after going over it, so I'm going to dump a lot of information here in one post instead of four, hopefully it's chunked out in an easy way to isolate the idea/question it targets.


@aaguiarz follow up question regarding

for most applications, the Store ID will be always the same (you'd have a different one per dev/staging/prod environment

What does a common local development setup look like? I've set mine up following your Docker Setup Guide, which is great for quickly testing the proof of concepts. But I'm not sure if there would be a benefit to running it locally if I was doing a long term project, instead of just pointing to a development environment. Or running the OpenFGA server locally, but pointed to an external database. Really want to understand what that looks like for investigating how to make sure we can enable developers to setup their project in a way that is both easy to replicate and easy to mirror their authorization models in tests.


We'll be keeping the Proof of Concept on @jimmyjames' Repository, so I've made an Issue there where we can keep track of Test Cases we want to model. @rwinch I know Adib mentioned having a couple, could you send him over there to give us some inspiration?


@rwinch I lean towards the idea of structuring the Proof of Concept in 2 parts, a Spring Security Extension, and then example implementations. I think that can help us decouple what is Spring, and what is OpenFGA. Since I've never tried to "officially" model a Spring Library, I was wondering the following.


General question for the group before I play around with it. Would it be beneficial to check out if the SDK would be better autogenerated in a Spring Flavor? Just because it would mean the Client is already exposed as a Bean by default, we'd get better Observability integration off the bat, etc. Likewise it might create a roadmap for consumers to slowly transition as support improves. Java SDK -> Spring SDK -> Whatever we come up with.

rwinch commented 4 months ago

Are we good to use the spring.security prefix for our properties? Or should we stick to openfga

Right now I don't think that there are rules around the code / property structures. We will iterate and try to make progress on this gradually. In the end if it becomes a Spring Boot property, it will be owned and thus reviewed by the Spring Boot team.

Would it be beneficial to check out if the SDK would be better autogenerated in a Spring Flavor?

I'm not convinced that the Spring team will ever own an OpenFGA client as it is a complicated/specific thing that would take up quite a bit of time for the team. At least for now, I think that we will get more value out of ensuring that Spring integrates well with OpenFGA.

Crain-32 commented 4 months ago

I'm not convinced that the Spring team will ever own an OpenFGA client as it is a complicated/specific thing that would take up quite a bit of time for the team

@rwinch poor phrasing on my part, from what I've seen the OpenFGA Java SDK is a mix of OpenAPI Generated and some light touch ups. You can generate Spring Framework Interfaces (Beta) for clients, and that was what I was referring to.

Crain-32 commented 4 months ago

@rwinch, bringing my thoughts from your comment on the PR to here instead.

I'm not sure if I'm fully understanding the AuthorizationManager<ReBACContext> idea. My initial thought with @ReBAC was a Meta Annotation wrapping @PreAuthorize/@PostAuthorize, which was nice because that's a pretty low effort implementation from the Spring Side. But I'm not sure how the AuthorizationManager<ReBACContext> fits into that, since that sounds like we'd no longer be hooking into the @PreAuthorize/@PostAuthorize Authorization flow.

jimmyjames commented 3 months ago

@rwinch demonstrated nicely how meta-annotations can enable adding method-level FGA checks pretty seamless 👏

Given that, I think at this time we (OpenFGA) are going to provide an FGA starter that exposes a configured OpenFgaClient bean and the ability to add an FGA method security check, to start. We may start with Spring 6.x but be ready to go with the meta-annotations feature once 6.3 is GA in May.

Perhaps a higher-level abstraction may be appropriate in Spring Security as noted, and some of those abstractions may become more apparent as we work through it.

rwinch commented 3 months ago

@jimmyjames Thanks for your reply.

how meta-annotations can enable adding method-level FGA checks pretty seamless

I'm glad the meta annotations support is proving to be valuable.

Given that, I think at this time we (OpenFGA) are going to provide an FGA starter that exposes a configured OpenFgaClient bean and the ability to add an FGA method security check, to start. We may start with Spring 6.x but be ready to go with the meta-annotations feature once 6.3 is GA in May.

That sounds good. As we iterate (especially if we end up with a ReBAC API in Spring Security) it may make sense for Spring to provide autoconfiguration / starter / etc.

Perhaps a higher-level abstraction may be appropriate in Spring Security https://github.com/jimmyjames/fga-spring-examples/pull/14#discussion_r1507030805, and some of those abstractions may become more apparent as we work through it.

I like this approach. Thank you for creating some additional use cases for us in the issues. I'll be periodically revisiting those as time permits. I'm hoping as we see more use cases it will help us with further refining integration and perhaps make it more obvious what abstractions make sense & where they should be located (Spring, OpenFGA, etc).

jimmyjames commented 2 months ago

@rwinch We have shipped an initial version of the OpenFGA Spring Boot Starter 🎉

Thanks again to you, @Crain-32 and others for feedback and collaboration! We will be continuing to iterate and gather feedback as we go forward.