Skip to content
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

[Discussion] Organization tiering (permissions) #148

Open
GME-O opened this issue Dec 15, 2023 · 12 comments
Open

[Discussion] Organization tiering (permissions) #148

GME-O opened this issue Dec 15, 2023 · 12 comments

Comments

@GME-O
Copy link

GME-O commented Dec 15, 2023

Hi

I'm putting this question here to have some feedback.

We have a SaaS solution currently based on Keycloak and we are looking to move toward multi-tenancy with Organizations where some users can self-manage themselves (admin of the organization can invite users to the organization).
This extension looks interesting (did some test on https://github.com/p2-inc/phasetwo-containers) and it answer our problem regarding organizations.

However, in our case we want to apply a "tier" (Freemium, Premium, etc) on the Organization (which is then inherited by users of the organization) and an user can belong to multiple Organizations.
So we have:

  • An Organization A with Freemium tier
  • An Organization B with Premium tier
  • An User A part of both Organization.
    And on our solution we would like that when the user is in the "Organization A" context (kinda "active organization"), he should get the freemium tier features. But when he switch to the "Organization B" context, he should now get the premium tier features.
    For security, I'm currently checking Keycloak Authorization with policy, resource & permission.

I there a way to achieve that ?

I noticed that we can't assign realm roles on an Organization. But we can assign attributes on the organization. And we could leverage "user attributes" to keep track of the "active-organization-id".
So I had in mind to setup a custom JS based policy which:

  1. validate token.
  2. decode token.
  3. verify that this active organization is in the list of the organizations the user belongs to.
  4. leverage Organizations API to GET attributes of this active organization.
  5. validate feature access based on tiering of the active organization.

Also we are looking to move this check step on an API Gateway, so that's something which could be done outside keycloak custom policy.
I would be interested to have some ideas or feedbacks on how we could set this up with keycloak-orgs.

Thanks in advance
Best regards

@xgp
Copy link
Member

xgp commented Dec 15, 2023

For your tiering question, it seems like something you probably want to keep in application state rather than in the Organization.

We haven't really had requests to get this working with Keycloak Authorization Services. However, what you suggest for your JS policy sounds reasonable.

There's both a mapper for Organization Roles and Organization Attributes, so you could have everything in the token without calling the API. We are aware of customers mapping those to the token and then doing custom authorization in their own API gateway (or in the case of AWS, using an Lambda Authorizer).

@GME-O
Copy link
Author

GME-O commented Dec 15, 2023

First of all, thanks,

So you would recommend to keep the "tier" and "organization_tier" link outside keycloak or keycloak-orgs, like in a micro-service (or nano-service) and leverage this service to assign, verify or remove tiering of an Organizations ?
(And of course query this API to retrieve tiering & verify it).

Would that be something you might be interested to have ? (proposition to contribute on that maybe)

We are indeed looking at Lambda Authorizer for our API Gateway.
On the "Organization Roles" I was mainly thinking of realm-role not accessible to Organization where we could define tiering vs "Organization Role" which is what you can create in the organization and assign to user you invite.

@xgp
Copy link
Member

xgp commented Dec 15, 2023

I don't have a concrete idea of how you would implement it, but I just don't see a strong case for including it here.

We made the decision pretty explicitly not to mix Realm Roles with Organization Roles. In general, if that's something that you need to do, this probably isn't the best extension for it.

@MGLL
Copy link
Contributor

MGLL commented Dec 16, 2023

Hi,

I have noticed that an user with manage-organization role can modify the organization attributes through the REST API (PUT .../realms/testing/orgs/ID).

Is there a plan to make some attributes read-only to users but manageable to keycloak admin ?
Similar to this: https://www.keycloak.org/docs/latest/server_admin/#read_only_user_attributes

(Also tried to see if spi-user-profile-declarative-user-profile-read-only-attributes would also restrict for attributes on organization but it's not working)

Best regards

@xgp
Copy link
Member

xgp commented Dec 16, 2023

Users with the realm-management Client role manage-organizations have complete control over all aspects of the Organization.

Users with the manage-organizations Organization role have control over the settings and attributes of an Organization.

There is no plan to make Organization attributes read-only, or make the management of them subject to some fine-grained permissions.

The SPI you mentioned pertains to the Keycloak declarative user profile functionality, and has nothing to do with Organization attributes.

@MGLL
Copy link
Contributor

MGLL commented Dec 24, 2023

Thanks a lot for all your answers.

I'm looking to implement something like "organization read-only attributes" similar to declarative user profile for "organization meta-data" (I'm actively looking at Keycloak codebase around the mechanism for user read-only attributes as inspiration). The idea is to have attributes restricted to the realm admin / manager and users in organization can't modify so we can keep track of specific info.

I had in mind to create a separate SPI, but actually I would need to influence the OrganizationResource (updateOrg) flow to validate attribute change. I have read your license, and I will clearly put in a NOTICE.md my modification. But let me know, if you would like to have this, I will try to do a proper PR.

But I'm struggling a bit with something, and I would be really grateful if you could help me.
I have read:

I'm able to remote debug Keycloak based on quarkus with IDEA (going through code with breakpoints), but it's not clear how I could "live code" or "debug" external SPI like keycloak-orgs.

I had in mind to build the modified keycloak-orgs and put it in the quarkus/dist/src/main/content/providers, run "kc.sh build" in the bin folder and then run again ../mvnw -f server/pom.xml -Dsuspend=true compile quarkus:dev -Dquarkus.args="start-dev".
But, by doing that, would I be able to set breakpoints in keycloak-orgs for debugging?
I have a but difficulties to visualize how it works as keycloak-orgs code won't be in the same location as keycloak code and I will have my remote debugger in the keycloak repo window.

I guess you already have gone through all that and you are able to do "live code" or "live debug" your SPI with keycloak, could you indicate me how I can do it?

Again, I would be really grateful.
Thanks again for your support!

@MGLL
Copy link
Contributor

MGLL commented Dec 29, 2023

Hello @xgp

So I managed to extend organization update flow with attributes validation based on Keycloak declarative profile (partial adaptation, as I focused on attribute update process and don't support configuration through API).

You can have a look here for modificiations:

Also added & modified code is on this branch:

Added specific tests there:

Let me know if you are interested.
(Tried to do a separate SPI, but as I have to influence updateOrg resource flow, I basically need to copy/paste & override full Organization* resources.
Also, I will need to override Admin UI to leverage new endpoint for Platform Admin update flow)

Best regards

@MGLL
Copy link
Contributor

MGLL commented Feb 8, 2024

Some update on this topic.
I will much likely work on a separate extension (the name will probably be "keycloak-orgs-subscription" (following licensing according to your license)).

The topic is to be able to assign "realm roles" to organization which are inherited by users (similar to assigning roles to a group in Keycloak).

The Use Case:

  • Context: SaaS Platform
  • Description: I want to be able to define some "subscription tier" (Freemium, Premium) based on realm roles, and I want to be able to assign it on the whole organization instead of per user to simplify the management.

This way, we could also use it in the Authorization setup (role based policy).

Plan:
Base scope

  • Create a new table "organization_subscription" with role_id, organization_id
  • Create necessary CRUD (restricted to SaaS Platform Admins (and not organization members))
  • Create a mapper to append the role assigned on the organization to members
  • Cover with tests (of course)

Bigger scope
Probably extend it with more logic like timed subscription (add timestamp to make subscription expires)

@xgp
Copy link
Member

xgp commented Feb 8, 2024

Thanks for the update on this. Also happy to look at this as a PR, depending on the final feature set you decide.

@MGLL
Copy link
Contributor

MGLL commented Feb 19, 2024

@xgp Here is the "requirements" I will use, let me know for any adjustments (naming or anything) before I start working on it or provide the PR.
I will probably start working on this during this week.


Objective:

I'm able to assign one or more Realm Roles to an Organization and the members of the organization inherit the roles in the tokens through a mapper.
Similar to the Group in Keycloak.

On top of that, I'm able to define an expiration date to those roles assignations. This expiration date is optional (so an assignation/tier could never expire).

Use Case

As a SaaS Platform with tiered context (Freemium, Premium, etc), I would like to leverage the Keycloak Realm Roles to define and assign those tiers (as my platform already use those realm roles).

Then, it could be used in the Authorization system of Keycloak if necessary (or any own or 3rd party system).

Out of Scope

Client specific roles.
Could be added later.

Implementation Details

Database:

Create a new table: organization_role_mapping
Columns:

  • organization_id: varchar(36)
  • role_id: varchar(36)
  • expiration_date: timestamp

CRUD:

Implementation will be similar to the Keycloak approach.

  • POST organizations/{id}/role-mappings/realm.

Example body:

[
    {
        "id": "ROLE-ID",
        "name": "ROLE-NAME",
        "description": "DESCRIPTION",
        "composite": false,
        "clientRole": false,
        "containerId": "REALM-NAME",
        "expirationDate": "yyyy-mm-dd hh:mm:ss"
    }
]

Expected response status: 204.

  • DELETE organizations/{id}/role-mappings/realm

Example body:

[
    {
        "id": "ROLE-ID",
        "name": "ROLE-NAME"
    }
]

Expected response status: 204.

  • GET organizations/{id}/role-mappings
{
    "realmMappings": [
        {
            "id": "ROLE-ID",
            "name": "ROLE-NAME",
            "description": "DESCRIPTION",
            "composite": false,
            "clientRole": false,
            "containerId": "REALM-NAME",
            "expirationDate": "yyyy-mm-dd hh:mm:ss"
        }
    ]
}

Expected response status: 200.

Additional CRUD (optional)

  • GET organizations/expired-tiers
    • To get an overview of organizations with expired tiers
  • DELETE organizations/expired-tiers
    • To run some clean-up process from an external call (useful in a distributed-system).

Mappers:

At least one mapper will be added:

  • Active Organization Realm Role
    Which will add the user's active organization realm roles (tiers) into the role: [] property of the access_token.

  • Organization Realm Role (optional, not sure if relevant)
    Which will add the user's organizations realm roles (tiers) into the role: [] property of the access_token.

Business Logic:

  • Only platform administrators should be able to assign or remove tiers to an organization. It will be protected by the ROLE_MANAGE_ORGANIZATION role ("manage-organizations").
    • Let me know if I should create a separate one.
  • The mappers won't map the role into the token if it's expired.
    • and lazily remove the role from the organization. (?)
  • We won't keep an history of the assigned roles to an organization.
  • During a POST request, if the role is already assigned to the organization, the expiration date will be updated.
  • ?

@MGLL
Copy link
Contributor

MGLL commented May 24, 2024

@xgp hi,
I will start to work a bit on that as it start to be an important need.
I have a question regarding entity and the keycloak org implementation:

  • should I use a prefix ?
  • if yes, which one is recommended ?

(I will start with p2_organization_role_mapping locally while waiting your feedback)

@xgp
Copy link
Member

xgp commented May 25, 2024

@MGLL Thanks for the clarification request. We haven't yet, but we plan to migrate tables in our extensions to the prefix EXT_P2_, so in your example, a table name would be EXT_P2_ORGANIZATION_ROLE_MAPPING. If you start working on this now, I would request to please use this prefix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants