[keycloak-user] Question about CBAC + Pushing Claims + Authorization Scopes

Pedro Igor Silva psilva at redhat.com
Thu Jul 25 08:16:41 EDT 2019


Considering you are in control on how the ticket is created and how claims
are set on it, would be an option to use a specific claim for each tenant
so that in your policies you check tenants based on the claim's key ?

On Thu, Jul 25, 2019 at 9:12 AM Álvaro Gómez <
alvaro.gomez.gimenez at tecsisa.com> wrote:

> Hi Pedro,
>
> We are performing HTTP ticket requests from our application (An API acting
> as a Resource Server). As an example, having the following endpoint:
>
> GET /api/tenants/__TENANT_ID__/products/__PRODUCT_ID__
>
> If we use non-scoped resources (In order to simplify the example) the API
> behaves as follows:
>
>   ** The Requesting Party performs this action:
>
>      GET /api/tenants/Organization-1/products/Product-X
>
>   1.- If there is no "permissions" claim (Or it does not contain the
> required authorization info, described in step 2) the API performs a ticket
> request for the resource "Product-X" pushing the tenant "Organization-1" in
> a claim:
>
>     POST
> https://localhost:8080/auth/realms/***/authz/protection/permission
>        [{
>             "resource_id": "Product-X",
>             "claims": { "tenant": [ "Organization-1" ] }
>        }]
>
>   The Requesting Party uses the ticket to obtain a valid RPT containing
> the following authorization info:
>
>       "permissions": [
>         {
>             "resource_id": "Product-X",
>             "claims": { "tenant" : ["Organization-1"] }
>         }
>       ]
>
>   ** The Requesting Party performs the following action using the
> previously obtained RPT:
>
>      GET /api/tenants/Organization-2/product/Product-X
>
>   2.- The API checks if the specified resource "Product-X" exists in the
> RPT "permissions" claim and contains "Organization-2" in the "tenant"
> pushed claim. Since the resource "Product-X" is only provided for the
> context "Organization-1" the API requests a ticket for the resource
> "Product-X" in the context of the tenant "Organization-2".
>
>    POST https://localhost:8080/auth/realms/***/authz/protection/permission
>         [{
>             "resource_id": "Product-X",
>             "claims": { "tenant": [ "Organization-2" ] }
>         }]
>
>     The Requesting Party uses the ticket to upgrade the previous RPT. The
> upgraded RPT now contains both tenants in the pushed claims:
>
>         "permissions": [
>             {
>                 "resource_id": "Product-X",
>                 "claims": { "tenant" : ["Organization-1",
> "Organization-2"] }
>             }
>         ]
>
> This works great with non-scoped resources since, for now on, the Resource
> server can grant access to "Product-X" in both contexts "Organization-1"
> and "Organization-2". Also, the Resource Server will obtain new tickets if
> new contexts (tenants) are requested. However, when we use
> scoped-resources, since the pushing claims are not specific to the scopes
> being requested, the Resource Server could not determine if the combination
> of "Product-X" and some scope is defined for an specific tenant. We could
> support this use-case removing scopes from the equation and creating
> non-scoped resources like "Product-X:read", "Product-X:write", etc.
> However, while we think that this should be implemented using scopes
> instead of non-scoped resources, we don't know how to manage claims as we
> discussed in the first mail.
>
> Regards,
> Álvaro.
>
> El mié., 24 jul. 2019 a las 22:34, Pedro Igor Silva (<psilva at redhat.com>)
> escribió:
>
>> Hi Álvaro,
>>
>> You are not missing anything and that is how claims are handled. They are
>> a permission-level (resource + scopes) info and not specific to only the
>> scopes being requested/granted.
>>
>> Before finding alternatives, could you tell me how are you pushing these
>> claims? Are you using our adapters or manually performing HTTP requests
>> from your app?
>>
>> Regards.
>>
>> On Wed, Jul 24, 2019 at 10:20 AM Álvaro Gómez <
>> alvaro.gomez.gimenez at tecsisa.com> wrote:
>>
>>> Hi,
>>>
>>> We are applying RBAC and CBAC models to evaluate permissions in a
>>> multi-tenant UMA application. We are using Pushing Claims to let custom
>>> policies determine if an user has an specific role in a provided context
>>> (tenant) via Pushing Claims.
>>>
>>> Everything works fine if we use non-scoped resources but things get a bit
>>> confusing when we use scoped ones since the pushing-claims (representing
>>> the tenants) end up mixed in the RPT permission claim without leaving any
>>> trace of the scopes with which they were pushed along. Consider the
>>> following example:
>>>
>>> We have an application which manages products (represented by resources).
>>> There are profiles (represented by roles) which allow users to sell,
>>> modify
>>> or delete products (represented by scopes). A certain user may interact
>>> with one product in the context of a tenant (Determined by the Pushing
>>> claim) with an specific role and with some different role from other
>>> tenant.
>>>
>>> - Resource:
>>>   * product (With scopes sell and update)
>>>
>>> - Roles:
>>>   * Seller
>>>   * Product-Manager
>>>
>>> - Policies:
>>>   * Is-Seller (In the Tenant specified in the Pushing Claim "tenant")
>>>   * Is-Product-Manager (In the Tenant specified in the Pushing Claim
>>> "tenant")
>>>
>>> - Permissions:
>>>   * product:sell -> Provides the "sell" scope of the resource "product"
>>> if
>>> the "Is-Seller" policy evaluates to grant.
>>>   * product:update -> Provides the "update" scope of the resource
>>> "product" if the "Is-Product-Manager" policy evaluates to grant.
>>>
>>> - Users:
>>>   * Alice -> Alice is "Seller" in the tenant "Organization-1" and is
>>> "Product-Manager" in the tenant "Organization 2" so she should be able to
>>> sell products in the context of the tenant "Organization-1" and update
>>> products in the context of "Organization-2" but neither "update" products
>>> in the context of "Organization-1" or sell products in the context of
>>> "Organization-2".
>>>
>>> 1.- Alice requests an RPT using the following ticket:
>>>      { "resource": "product", "resource_scopes": ["sell"], "claims": {
>>> "tenant": ["Organization-1"] } }
>>>
>>>     Since Alice is "Seller" in the "Organization-1" (meaning the Policy
>>> "Is-Seller" will evaluate to "grant" if the provided claim value is
>>> "Organization-1" and the evaluated Identity is Alice) an RPT is emitted
>>> with the following "permission" claim:
>>>
>>>     [{
>>>        "resource": "product",
>>>        "resource_scopes": ["sell"],
>>>        "claims": { "tenant": ["Organization-1"] }
>>>     }]
>>>
>>> 2.- Alice upgrades the previous RPT with the following ticket:
>>>      { "resource": "product", "resource_scopes": ["update"], "claims": {
>>> "tenant": ["Organization-2"] } }
>>>
>>>    Here is were things get confusing to us. We'd expect Alice to be
>>> granted
>>> when requesting the scope "update" in the context of "Organization-2"
>>> since
>>> Alice has the role "Product-Manager" in that tenant. That would be what
>>> happened if Alice was requesting the RPT for the first time instead of
>>> upgrading a previous one. However, since we are upgrading the RPT
>>> obtained
>>> in Step 1, when the policy "Is-Product-Manager" is evaluated, the claim
>>> "tenant" is mixed with the one in Step 1 (Since they are not grouped by
>>> scope) resulting in the following permission:
>>>
>>>    {
>>>       "resource": "product",
>>>       "resource_scopes": ["sell", "update"],
>>>       "claims": {
>>>           "tenant": ["Organization-1", "Organization-2"]
>>>        }
>>>    }
>>>
>>>   The policy can't evaluate to grant since Alice is not "Product-Manager"
>>> in both tenants "Organization-1" and "Organization-2" (Obtained through
>>> $evaluation.getPermission().getClaims()). When evaluating this policy we
>>> would only be interested in the pushing-claim `{ "tenant":
>>> ["Organization-2"] }` which was pushed along with the scope "update"
>>> (which
>>> is the one being evaluated by the permission "product:update" associated
>>> with this Policy).
>>>
>>>    Shouldn't the claims be grouped by the scopes which with they were
>>> pushed along? (See example at the end of this text), Are we missing
>>> something?
>>>
>>>    Example:
>>>    {
>>>       "resource": "product",
>>>       "resource_scopes": [
>>>           { "name": "sell", "claims": { "tenant": ["Organization-1"] } },
>>>           { "name": "update", "claims": { "tenant": ["Organization-2"] }
>>> },
>>>       ]
>>>
>>> Thanks in advance,
>>> Álvaro.
>>> _______________________________________________
>>> keycloak-user mailing list
>>> keycloak-user at lists.jboss.org
>>> https://lists.jboss.org/mailman/listinfo/keycloak-user
>>
>>


More information about the keycloak-user mailing list