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

Álvaro Gómez alvaro.gomez.gimenez at tecsisa.com
Thu Jul 25 08:12:10 EDT 2019


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