Skip to content

Add OpenFGA Support #14121

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

Open
4 tasks
Tracked by #14595
rwinch opened this issue Nov 8, 2023 · 26 comments
Open
4 tasks
Tracked by #14595

Add OpenFGA Support #14121

rwinch opened this issue Nov 8, 2023 · 26 comments
Labels
theme: partner-use-cases Use cases we identified with a partner (an established contributor) type: enhancement A general enhancement

Comments

@rwinch
Copy link
Member

rwinch commented Nov 8, 2023

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

Some NOTES for myself:

  • We can use Testcontainers support for starting the openfga Docker image
  • We should provide a conventions based approach for loading the authorization model and data similar to how we support loading schema and test data into a database. To take it a step further, perhaps there could be an external liquibase style library for OpenFGA that Spring could leverage.
  • An example of what we might do is here
  • A working sample is at https://github.com/jimmyjames/fga-spring-examples
@rwinch rwinch added status: waiting-for-triage An issue we've not yet triaged type: enhancement A general enhancement labels Nov 8, 2023
@aaguiarz
Copy link

Hi @rwinch

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

@Crain-32
Copy link
Contributor

@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
Copy link

👋 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
Copy link
Member Author

rwinch commented Feb 7, 2024

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
Copy link
Contributor

Crain-32 commented Feb 8, 2024

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
Copy link
Member Author

rwinch commented Feb 8, 2024

@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
Copy link

@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:

  • Creating a Spring Boot Starter that initializes an OpenFGA client that can be injected into my app, so that I can write authz data when needed
  • Some sort of new annotation and Aspect that would intercept annotated methods and perform the configured check, to either allow or deny access

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
Copy link
Contributor

Crain-32 commented Feb 9, 2024

@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
Copy link

@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
Copy link
Member Author

rwinch commented Feb 13, 2024

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
Copy link

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 #14480.

Would it make sense to start with @PreAuthorize and once #14480 is available, also support that approach?

@Crain-32
Copy link
Contributor

@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

  • Disabled with spring.security.openfga.enabled=false
  • Expose the OpenFgaApi as a conditional bean, so full customization is available for power users.
    • This also solves the issue of updating the stores, since users can just inject the bean and do their own logic.
  • Expose an OpenFgaPermissionEvaluator as a conditional bean, hooking into hasPermission.
  • Expose a few @FunctionalInterface to create a strategy pattern for the Parameters of hasPermission to help resolve

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
Copy link
Member Author

rwinch commented Feb 13, 2024

@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 #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 #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
Copy link
Contributor

@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
Copy link

@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
Copy link

@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
Copy link

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 #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
Copy link
Contributor

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
Copy link

jimmyjames commented Feb 20, 2024

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
Copy link
Contributor

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.

  • Are we good to use the spring.security prefix for our properties? Or should we stick to openfga
  • Do you have a reference for the best practices with @AutoConfiguration? Exceptions to throw if beans fail to load, connections fail, etc. Just for making sure it plays nicely in the Application Startup phase.

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
Copy link
Member Author

rwinch commented Feb 22, 2024

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
Copy link
Contributor

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
Copy link
Contributor

@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
Copy link

@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
Copy link
Member Author

rwinch commented Mar 5, 2024

@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 jimmyjames/fga-spring-examples#14 (comment), 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
Copy link

@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.

@sjohnr sjohnr added theme: partner-use-cases Use cases we identified with a partner (an established contributor) and removed status: waiting-for-triage An issue we've not yet triaged labels Jun 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
theme: partner-use-cases Use cases we identified with a partner (an established contributor) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

5 participants