Skip to content

[KEYCLOAK-7367] - User-Managed Policy Provider#5211

Merged
pedroigor merged 1 commit intokeycloak:masterfrom
pedroigor:KEYCLOAK-7367
Jun 4, 2018
Merged

[KEYCLOAK-7367] - User-Managed Policy Provider#5211
pedroigor merged 1 commit intokeycloak:masterfrom
pedroigor:KEYCLOAK-7367

Conversation

@pedroigor
Copy link
Contributor

No description provided.

Copy link
Contributor

@chicco785 chicco785 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not much to say on my side, just a small doubt on management of denied permissions in case of uma policies.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pedroigor stupid question, should i use the same header in my code?
i copied an old one that refers to Jboss.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, please.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if the user deleted the policy directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The policy lifetime is closely related with the tickets granted by the user. It will be removed, eventually, when the last granted ticket is removed.

Does that answer your question ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking to the other case, suppose the owner of a resource authorise the ticket, and then instead of removing the ticket, he remove the policy. Probably we should remove the ticket (if it is not attached to other policies). Just a small glitch that may happen.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Policies should never be removed directly. It is a managed thing that only Keycloak knows how to do it properly. Today, whenever you grant, revoke or remove a ticket, policies are updated/removed accordingly.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't be collected also the denied user managed policies?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Denied permissions are already collected and considered when calculating the scopes the user is allowed to access. However, user-managed policies that evaluated to a PERMIT override the final decision. For instance, suppose scopes A, B and C were denied for Resource Z. If there is a user managed policy that grants access to scopes A and C, these two scopes will be granted at the end although they were denied by other policies.

@chicco785
Copy link
Contributor

chicco785 commented May 22, 2018

@pedroigor the AuthorizationTokenService needs to be updated right?

i am asking because i still can't evaluate as a normal permission an uma granted one.

i made the following test:

  1. created a ticket for a resource
  2. asked grant permission for a resource using the ticket
  3. using the ticket i am granted the access to the resource
  4. using the all "permission request"
    curl --request POST \
      --url http://127.0.0.1:8081/auth/realms/master/protocol/openid-connect/token \
      --header 'Authorization: Bearer  xxx' \
      --header 'Content-Type: application/x-www-form-urlencoded' \
      --data 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Auma-ticket&audience=test'
    
    the resource is not listed in the ones i can access.
  5. using a specific "permission request" for the resource:
    curl --request POST \
      --url http://127.0.0.1:8081/auth/realms/master/protocol/openid-connect/token \
      --header 'Authorization: Bearer xxx' \
      --header 'Content-Type: application/x-www-form-urlencoded' \
      --data 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Auma-ticket&permission=resource#write&audience=test'
    
    i can access it.

@pedroigor
Copy link
Contributor Author

@chicco785, I may be missing this scenario. Will check it out. I think user managed policies are not being considered when obtaining all entitlements for a user.

@chicco785
Copy link
Contributor

chicco785 commented May 22, 2018 via email

@pedroigor
Copy link
Contributor Author

@chicco785, it should be fixed now. You should be able to obtain permissions for resources granted via UMA when evaluating all permissions.

@chicco785
Copy link
Contributor

chicco785 commented May 23, 2018

@pedroigor i think there may be still some issues in the evaluation:

  1. created a ticket for a resource
  2. created (in ui, so not a UMA one) a policy that says that user in a given role can access a given resource with a given scope
  3. using the all "permission request"
    curl --request POST \
      --url http://127.0.0.1:8081/auth/realms/master/protocol/openid-connect/token \
      --header 'Authorization: Bearer  xxx' \
      --header 'Content-Type: application/x-www-form-urlencoded' \
      --data 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Auma-ticket&audience=test'
    
    the resource is not listed in the ones i can access.
  4. using a specific "permission request" for the resource:
    curl --request POST \
      --url http://127.0.0.1:8081/auth/realms/master/protocol/openid-connect/token \
      --header 'Authorization: Bearer xxx' \
      --header 'Content-Type: application/x-www-form-urlencoded' \
      --data 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Auma-ticket&permission=resource&audience=test'
    
    i can access it correctly.

even worst...

  1. cancel (from the ui) the permission created above
  2. i still can access according to "permission request" for the resource:
    curl --request POST \
      --url http://127.0.0.1:8081/auth/realms/master/protocol/openid-connect/token \
      --header 'Authorization: Bearer xxx' \
      --header 'Content-Type: application/x-www-form-urlencoded' \
      --data 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Auma-ticket&permission=resource&audience=test'
    

this occurs after I created a UMA user policy via the ticket permission. If i remove that policy, everything gets back to normal.

@pedroigor
Copy link
Contributor Author

@chicco785 , how did you create the ticket ?

@chicco785
Copy link
Contributor

chicco785 commented May 23, 2018

  1. get the ticket permission
curl --request POST \
  --url http://127.0.0.1:8081/auth/realms/master/authz/protection/permission \
  --header 'Content-Type: application/json' \
  --header 'authorization: Bearer xxx' \
  --data '[\n	{\n		"resource_id": "6c237d99-59d7-47e9-ae71-f95a2274cbbf",\n		"resource_scopes": ["read"],\n		"resource_server_id" : "test"\n	}\n]'
  1. use the rtp to ask access
curl --request POST \
--url http://127.0.0.1:8081/auth/realms/master/protocol/openid-connect/token \
--header 'Authorization: Bearer xxx' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Auma-ticket&ticket=xxx'
  1. grant access
curl --request PUT \
  --url http://127.0.0.1:8081/auth/realms/master/authz/protection/permission/ticket \
  --header 'Content-Type: application/json' \
  --header 'authorization: Bearer xxx' \
  --data '    {\n        "id": "b95ecc86-342d-4a6c-b1be-179e466c1df5",\n        "owner": "44dc0cf0-b50d-49b6-83fe-da477595bec0",\n        "resource": "6c237d99-59d7-47e9-ae71-f95a2274cbbf",\n        "scope": "5786cb18-bbd5-47d0-a6a9-917d44682bee",\n        "granted": true,\n        "scopeName": "read",\n        "resourceName": "8906",\n        "requester": "889ee9cb-8065-4149-bbd0-f5dadfe0f40e",\n        "ownerName": "test",\n        "requesterName": "admin"\n    }'
  1. now i can access 8906 but apparently also any other resource using a "permission request" (this apply to any user).

if it helps, here is the current configuration of my client:

{
  "allowRemoteResourceManagement": true,
  "policyEnforcementMode": "ENFORCING",
  "resources": [
    {
      "name": "EntityType",
      "uri": "/v2/type/{id}",
      "type": "urn:orchestracities:type",
      "ownerManagedAccess": false,
      "displayName": "EntityType",
      "attributes": {},
      "scopes": [
        {
          "name": "read"
        }
      ]
    },
    {
      "name": "Entity",
      "uri": "/v2/entities/{id}",
      "type": "urn:orchestracities:entity",
      "ownerManagedAccess": false,
      "displayName": "Entity",
      "attributes": {},
      "scopes": [
        {
          "name": "read"
        },
        {
          "name": "write"
        },
        {
          "name": "delete"
        }
      ]
    },
    {
      "name": "8910",
      "uri": "/v2/entities/8910",
      "type": "urn:orchestracities:entity",
      "owner": {
        "name": "admin"
      },
      "ownerManagedAccess": true,
      "attributes": {},
      "scopes": [
        {
          "name": "read"
        },
        {
          "name": "write"
        },
        {
          "name": "delete"
        }
      ]
    },
    {
      "name": "8906",
      "uri": "/v2/entities/8906",
      "type": "urn:orchestracities:entity",
      "owner": {
        "name": "test"
      },
      "ownerManagedAccess": true,
      "attributes": {},
      "scopes": [
        {
          "name": "read"
        },
        {
          "name": "write"
        },
        {
          "name": "delete"
        }
      ]
    },
    {
      "name": "8905",
      "uri": "/v2/entities/8905",
      "type": "urn:orchestracities:entity",
      "owner": {
        "name": "test"
      },
      "ownerManagedAccess": true,
      "attributes": {},
      "scopes": [
        {
          "name": "read"
        },
        {
          "name": "write"
        },
        {
          "name": "delete"
        }
      ]
    },
    {
      "name": "Default Resource",
      "uri": "/*",
      "type": "urn:test:resources:default",
      "ownerManagedAccess": false,
      "attributes": {},
      "scopes": [
        {
          "name": "read"
        },
        {
          "name": "write"
        },
        {
          "name": "delete"
        }
      ]
    }
  ],
  "policies": [
    {
      "name": "Default Policy",
      "description": "A policy that grants access only to owners of a resource",
      "type": "js",
      "logic": "POSITIVE",
      "decisionStrategy": "AFFIRMATIVE",
      "config": {
        "code": "var context = $evaluation.getContext();\nvar identity = context.getIdentity();\nvar permission = $evaluation.getPermission();\nvar resource = permission.getResource();\n\nif (resource.getOwner().equals(identity.getId())) {\n    $evaluation.grant();\n}else{\n    $evaluation.deny();\n}"
      }
    },
    {
      "name": "f2811679-d7b0-4c36-8c8f-65fe7dbcfa17",
      "type": "user",
      "logic": "POSITIVE",
      "decisionStrategy": "UNANIMOUS",
      "config": {
        "users": "[\"admin\"]"
      }
    },
    {
      "name": "526a8a3b-d039-45e0-9d5a-47139df3d3ad",
      "type": "uma",
      "logic": "POSITIVE",
      "decisionStrategy": "UNANIMOUS",
      "config": {
        "resources": "[\"8906\"]",
        "scopes": "[\"read\"]",
        "applyPolicies": "[\"f2811679-d7b0-4c36-8c8f-65fe7dbcfa17\"]"
      }
    },
    {
      "name": "Default permission",
      "description": "only owner can do anything",
      "type": "scope",
      "logic": "POSITIVE",
      "decisionStrategy": "UNANIMOUS",
      "config": {
        "scopes": "[\"write\",\"delete\",\"read\"]",
        "applyPolicies": "[\"Default Policy\"]"
      }
    }
  ],
  "scopes": [
    {
      "name": "delete"
    },
    {
      "name": "write"
    },
    {
      "name": "read"
    }
  ]
}

@pedroigor
Copy link
Contributor Author

@chicco785, I was able to reproduce the issue. Thanks for all the details. It should be fixed now and I have added tests that make sure this won't happen again.

The issue was related to how permissions associated with resources set with a type were being evaluated.

@chicco785
Copy link
Contributor

@pedroigor happy to be helpful :) as soon as i have some time, I am going to check again. At the latest tomorrow morning.

@chicco785
Copy link
Contributor

chicco785 commented May 23, 2018

@pedroigor i think there are stills issues.

issue 1:

  1. user test shares a resource in read, write, delete with admin.

  2. admin ask authorization read to the resource, while the expected behaviour (given that only scope read was asked) is that the permission include only that scope, all scopes are returned.

issue 2:

  1. admin create from the interface a group policy that gives read access to a resource for any member of a given group.

  2. user test members of the group ask authorization read to the resource, he is rejected.

issue 3:

  1. admin user creates from uma-policy api (so it's classified as uma policy) a group policy (the same policy as above) that gives read access to a resource for any member of a given group.

  2. user test member of the authorised group ask authorization read to the resource, he is authorised to access the resource (correct behaviour).

  3. user test member of the authorised group ask for all the authorisation he can have on all resources, shared resource is not listed in the authorised one (wrong behaviour).

@pedroigor
Copy link
Contributor Author

The behaviour for Issue 1 is expected it is not an issue. Although you did not request a particular scope it will be returned in case access is granted.

I think the issue you are facing with Issue 2 and Issue 3 is because of the access token not containing a claim holding the user groups. Where these claim should be the same as the one you defined in your group policy.

@chicco785
Copy link
Contributor

chicco785 commented May 23, 2018

issue 1 occurs only for ticket managed permissions, that's why i thought it was weird. in fact, for other "Permissions" even though the user has additional scopes on the resource, only the requested scope is returned.

issue 2 and issue 3, i have to check, but i am not sure is that the issue.

i introspected the token it contains the groups (but maybe this is not what you mean by "claim"):

{
    "jti": "31e2cba1-8fb0-4314-926e-113149b4b48b",
    "exp": 1527105938,
    "nbf": 0,
    "iat": 1527105878,
    "iss": "http://127.0.0.1:8081/auth/realms/master",
    "aud": "test",
    "sub": "889ee9cb-8065-4149-bbd0-f5dadfe0f40e",
    "typ": "Bearer",
    "azp": "test",
    "auth_time": 0,
    "session_state": "035875eb-8423-47bf-926d-31e0e781fb7c",
    "preferred_username": "admin",
    "acr": "1",
    "allowed-origins": [],
    "realm_access": {
        "roles": [
            "create-realm",
            "admin",
            "uma_authorization",
            "user"
        ]
    },
    "resource_access": {
        "test": {
            "roles": [
                "uma_protection"
            ]
        },
        "master-realm": {
            "roles": [
                "view-realm",
                "view-identity-providers",
                "manage-identity-providers",
                "impersonation",
                "create-client",
                "manage-users",
                "query-realms",
                "view-authorization",
                "query-clients",
                "query-users",
                "manage-events",
                "manage-realm",
                "view-events",
                "view-users",
                "view-clients",
                "manage-authorization",
                "manage-clients",
                "query-groups"
            ]
        },
        "account": {
            "roles": [
                "manage-account",
                "manage-account-links",
                "view-profile"
            ]
        }
    },
    "groups": [
        "/antwerpen"
    ],
    "client_id": "test",
    "username": "admin",
    "active": true
}

Regardless the claim, if that was the problem, in issue 2 and issue 3, shouldn't be the behaviour the same? issue 2 group permission is created as scope permission in the ui, issue 3 the uma permission is created via uma-policy API.

Also, i tested with a role permission and i am experiencing a similar same behaviour:

issue 2:

  1. admin creates from the admin interface a role policy that gives read access to a resource for any user with a given role.

  2. user test having the needed role ask authorization read to the resource, he is rejected.

issue 3:

  1. admin creates from uma-policy api (so it's classified as uma policy) role policy (same policy as above) that gives read access to a resource for any user with a given role.

  2. user test having the requested role ask authorization read to the resource, he is authorised to access the resource (correct behaviour).

  3. user test having the requested role ask for all the authorisation he can have on all resources, the shared resource via the requested role is not listed in the authorised one (wrong behaviour).

@pedroigor
Copy link
Contributor Author

I'll need to test those issues using your changes. So far I was basically checking my changes to #5211.

@pedroigor
Copy link
Contributor Author

@chicco785, I was checking Issue #2. Can you check if you have conflict permissions ? What I mean is that you may have 2 permissions being evaluated where one of them denies access to the read scope. Although the second one is granting the same scope, the final result will actually be a deny.

@chicco785
Copy link
Contributor

chicco785 commented May 24, 2018

@pedroigor maybe I am doing something wrong.

test 1:

  1. using the UI create a role policy associated to a resource via a read scope permissions (the only other policy is related to ownership), role is user. (so it is not UMA).
  2. admin can see the resource (he owns it)
  3. test user has role user. he should be able to access it being in the role user.
  4. test user is not granted access neither with "permission" request neither with "all permission" request.

request are made as follow:

  1. get the token for the role:

    curl --request POST \
    --url http://127.0.0.1:8081/auth/realms/master/protocol/openid-connect/token \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data 'username=test&password=test&grant_type=password&client_id=test&client_secret=2ac7b9f0-24b2-4e72-a4d2-733bc344a15a&scope=test%2Fuma_protection%20user'
    
  2. get permission

    curl --request POST \
    --url http://127.0.0.1:8081/auth/realms/master/protocol/openid-connect/token \
    --header 'Authorization: Bearer xxx' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Auma-ticket&permission=29dcfb3c-cbe0-42fe-a8d9-04ad4effb62f&audience=test'
    
  3. get all permission

    curl --request POST \
    --url http://127.0.0.1:8081/auth/realms/master/protocol/openid-connect/token \
    --header 'Authorization: Bearer xxx' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Auma-ticket&audience=test'
    
  4. introspect:

    curl --request POST \
    --url http://127.0.0.1:8081/auth/realms/master/protocol/openid-connect/token/introspect \
    --header 'Authorization: Bearer xxxx' \
    --header 'Content-Type: application/x-www-form-urlencoded' \
    --data 'client_id=test&client_secret=2ac7b9f0-24b2-4e72-a4d2-733bc344a15a&token=xxx&token_type_hint=requesting_party_token'
    

see the configuration:

  {
  "allowRemoteResourceManagement": true,
  "policyEnforcementMode": "ENFORCING",
  "resources": [
  {
    "name": "8911",
    "uri": "/v2/entities/8911",
    "type": "urn:orchestracities:entity",
    "owner": {
      "name": "test2"
    },
    "ownerManagedAccess": true,
    "attributes": {},
    "scopes": [
      {
        "name": "read"
      },
      {
        "name": "write"
      },
      {
        "name": "delete"
      }
    ]
  },
  {
    "name": "EntityType",
    "uri": "/v2/type/*",
    "type": "urn:orchestracities:type",
    "ownerManagedAccess": false,
    "displayName": "EntityType",
    "attributes": {},
    "scopes": [
      {
        "name": "read"
      }
    ]
  },
  {
    "name": "Entity",
    "uri": "/v2/entities/{id}",
    "type": "urn:orchestracities:entity",
    "ownerManagedAccess": false,
    "displayName": "Entity",
    "attributes": {},
    "scopes": [
      {
        "name": "read"
      },
      {
        "name": "write"
      },
      {
        "name": "delete"
      }
    ]
  },
  {
    "name": "8910",
    "uri": "/v2/entities/8910",
    "type": "urn:orchestracities:entity",
    "owner": {
      "name": "admin"
    },
    "ownerManagedAccess": true,
    "attributes": {},
    "scopes": [
      {
        "name": "read"
      },
      {
        "name": "write"
      },
      {
        "name": "delete"
      }
    ]
  },
  {
    "name": "8906",
    "uri": "/v2/entities/8906",
    "type": "urn:orchestracities:entity",
    "owner": {
      "name": "test"
    },
    "ownerManagedAccess": true,
    "attributes": {},
    "scopes": [
      {
        "name": "read"
      },
      {
        "name": "write"
      },
      {
        "name": "delete"
      }
    ]
  },
  {
    "name": "8905",
    "uri": "/v2/entities/8905",
    "type": "urn:orchestracities:entity",
    "owner": {
      "name": "test"
    },
    "ownerManagedAccess": true,
    "attributes": {},
    "scopes": [
      {
        "name": "read"
      },
      {
        "name": "write"
      },
      {
        "name": "delete"
      }
    ]
  },
  {
    "name": "Default Resource",
    "uri": "/*",
    "type": "urn:test:resources:default",
    "ownerManagedAccess": false,
    "attributes": {},
    "scopes": [
      {
        "name": "read"
      },
      {
        "name": "write"
      },
      {
        "name": "delete"
      }
    ]
  }
  ],
  "policies": [
  {
    "name": "user role policy",
    "type": "role",
    "logic": "POSITIVE",
    "decisionStrategy": "UNANIMOUS",
    "config": {
      "roles": "[{\"id\":\"user\",\"required\":true}]"
    }
  },
  {
    "name": "Default Policy",
    "description": "A policy that grants access only to owners of a resource",
    "type": "js",
    "logic": "POSITIVE",
    "decisionStrategy": "AFFIRMATIVE",
    "config": {
      "code": "var context = $evaluation.getContext();\nvar identity = context.getIdentity();\nvar permission = $evaluation.getPermission();\nvar resource = permission.getResource();\n\nif (resource.getOwner().equals(identity.getId()))\n    $evaluation.grant();"
    }
  },
  {
    "name": "grant",
    "description": "grant to any user in the realm",
    "type": "js",
    "logic": "POSITIVE",
    "decisionStrategy": "UNANIMOUS",
    "config": {
      "code": "$evaluation.grant();"
    }
  },
  {
    "name": "Default permission",
    "description": "only owner can do anything",
    "type": "scope",
    "logic": "POSITIVE",
    "decisionStrategy": "UNANIMOUS",
    "config": {
      "resources": "[\"Entity\"]",
      "scopes": "[\"write\",\"delete\",\"read\"]",
      "applyPolicies": "[\"Default Policy\"]"
    }
  },
  {
    "name": "user ro",
    "type": "scope",
    "logic": "POSITIVE",
    "decisionStrategy": "UNANIMOUS",
    "config": {
      "resources": "[\"8910\"]",
      "scopes": "[\"read\"]",
      "applyPolicies": "[\"user role policy\"]"
    }
  },
  {
    "name": "entitytype permission",
    "type": "scope",
    "logic": "POSITIVE",
    "decisionStrategy": "UNANIMOUS",
    "config": {
      "resources": "[\"EntityType\"]",
      "scopes": "[\"read\"]",
      "applyPolicies": "[\"grant\"]"
    }
  }
  ],
  "scopes": [
  {
    "name": "delete"
  },
  {
    "name": "write"
  },
  {
    "name": "read"
  }
  ]
  }

test 2:

  1. using the uma api create a role policy associated to a resource via a read scope permissions (the only other policy is related to ownership), role is user. (so it is UMA).
  2. admin can see the resource (he owns it)
  3. test user has role user. he should be able to access it being in the role user.
  4. test user is granted access with "permission" request
  5. test user is not granted access with "all permission" request.

configuration.

{
"allowRemoteResourceManagement": true,
"policyEnforcementMode": "ENFORCING",
"resources": [
 {
   "name": "8911",
   "uri": "/v2/entities/8911",
   "type": "urn:orchestracities:entity",
   "owner": {
     "name": "test2"
   },
   "ownerManagedAccess": true,
   "attributes": {},
   "scopes": [
     {
       "name": "read"
     },
     {
       "name": "write"
     },
     {
       "name": "delete"
     }
   ]
 },
 {
   "name": "EntityType",
   "uri": "/v2/type/*",
   "type": "urn:orchestracities:type",
   "ownerManagedAccess": false,
   "displayName": "EntityType",
   "attributes": {},
   "scopes": [
     {
       "name": "read"
     }
   ]
 },
 {
   "name": "Entity",
   "uri": "/v2/entities/{id}",
   "type": "urn:orchestracities:entity",
   "ownerManagedAccess": false,
   "displayName": "Entity",
   "attributes": {},
   "scopes": [
     {
       "name": "read"
     },
     {
       "name": "write"
     },
     {
       "name": "delete"
     }
   ]
 },
 {
   "name": "8910",
   "uri": "/v2/entities/8910",
   "type": "urn:orchestracities:entity",
   "owner": {
     "name": "admin"
   },
   "ownerManagedAccess": true,
   "attributes": {},
   "scopes": [
     {
       "name": "read"
     },
     {
       "name": "write"
     },
     {
       "name": "delete"
     }
   ]
 },
 {
   "name": "8906",
   "uri": "/v2/entities/8906",
   "type": "urn:orchestracities:entity",
   "owner": {
     "name": "test"
   },
   "ownerManagedAccess": true,
   "attributes": {},
   "scopes": [
     {
       "name": "read"
     },
     {
       "name": "write"
     },
     {
       "name": "delete"
     }
   ]
 },
 {
   "name": "8905",
   "uri": "/v2/entities/8905",
   "type": "urn:orchestracities:entity",
   "owner": {
     "name": "test"
   },
   "ownerManagedAccess": true,
   "attributes": {},
   "scopes": [
     {
       "name": "read"
     },
     {
       "name": "write"
     },
     {
       "name": "delete"
     }
   ]
 },
 {
   "name": "Default Resource",
   "uri": "/*",
   "type": "urn:test:resources:default",
   "ownerManagedAccess": false,
   "attributes": {},
   "scopes": [
     {
       "name": "read"
     },
     {
       "name": "write"
     },
     {
       "name": "delete"
     }
   ]
 }
],
"policies": [
 {
   "name": "2515472c-6d47-4772-aa60-c0fe40ce9e14",
   "description": "user managed role policy",
   "type": "role",
   "logic": "POSITIVE",
   "decisionStrategy": "UNANIMOUS",
   "config": {
     "roles": "[{\"id\":\"user\",\"required\":false}]"
   }
 },
 {
   "name": "e7d59adb-e017-44ca-bd23-022fdba608b3",
   "description": "user managed permission for resource [29dcfb3c-cbe0-42fe-a8d9-04ad4effb62f]",
   "type": "uma",
   "logic": "POSITIVE",
   "decisionStrategy": "UNANIMOUS",
   "config": {
     "resources": "[\"8910\"]",
     "scopes": "[\"read\"]",
     "applyPolicies": "[\"2515472c-6d47-4772-aa60-c0fe40ce9e14\"]"
   }
 },
 {
   "name": "Default Policy",
   "description": "A policy that grants access only to owners of a resource",
   "type": "js",
   "logic": "POSITIVE",
   "decisionStrategy": "AFFIRMATIVE",
   "config": {
     "code": "var context = $evaluation.getContext();\nvar identity = context.getIdentity();\nvar permission = $evaluation.getPermission();\nvar resource = permission.getResource();\n\nif (resource.getOwner().equals(identity.getId()))\n    $evaluation.grant();"
   }
 },
 {
   "name": "grant",
   "description": "grant to any user in the realm",
   "type": "js",
   "logic": "POSITIVE",
   "decisionStrategy": "UNANIMOUS",
   "config": {
     "code": "$evaluation.grant();"
   }
 },
 {
   "name": "Default permission",
   "description": "only owner can do anything",
   "type": "scope",
   "logic": "POSITIVE",
   "decisionStrategy": "UNANIMOUS",
   "config": {
     "resources": "[\"Entity\"]",
     "scopes": "[\"write\",\"delete\",\"read\"]",
     "applyPolicies": "[\"Default Policy\"]"
   }
 },
 {
   "name": "entitytype permission",
   "type": "scope",
   "logic": "POSITIVE",
   "decisionStrategy": "UNANIMOUS",
   "config": {
     "resources": "[\"EntityType\"]",
     "scopes": "[\"read\"]",
     "applyPolicies": "[\"grant\"]"
   }
 }
],
"scopes": [
 {
   "name": "delete"
 },
 {
   "name": "write"
 },
 {
   "name": "read"
 }
]
}

@pedroigor
Copy link
Contributor Author

@chicco785, regarding test 1. I think it is not issue and like I said, you have two conflicting permissions. The resource user test is trying to access is 8910, right ?

If so, check the Default Permission, you`ll see that read is among the list of protected scope. Now try to remove ```read``` from there and you should be able to access ```8910``` with ```read``` scope.

You can better visualize this using the Policy Evaluation Tool, there you can check which permission/policy was evaluated and the outcome.

@pedroigor
Copy link
Contributor Author

@chicco785, regarding test 2. Two things is happening from what I tested:

  • The test user is granted when doing a permission request because you are telling Keycloak the resource you want to access. So the policy engine is able to process permissions/policies associated with this resource. Also, note that differently than test 1, in this case, the user got the permission because it was granted by a UMA policy, which, like we discussed, overrides any other decision from other permissions. In test 1 there is no UMA permission involved and permission is not granted because of one of them had denied access (the Default Permission).

  • Get All permission will never work for UMA policies created via uma-policy. The reason is that when doing a "get all" it is unfeasible to identify these resources protected by these policies. It would require evaluating every single resource in the database (at least those with owner managed marked as enabled) and you may have a lot of them. This is a drawback when using "get all" and a problem really hard to solve without sacrifice performance. However, "get all" works when you have resources granted via UMA flow, using a ticket. In this case, we are able to easily obtain all resources requested by the user.

@chicco785
Copy link
Contributor

@pedroigor clearly i need to better understand how it works. what do you mean by "protected" scopes? is then the only way then to an "affermative" aggregate permission to not conflict the policies?

@pedroigor
Copy link
Contributor Author

@chicco785, permissions are mutually exclusive by default. If Permission A gives access to scope A and Permission B denies access to scope A. Scope A will be denied.

UMA permissions work differently as they override any other permission decision.

Yeah, an aggregate policy marked as "affirmative" is a way to solve this problem. In this case you will have a single ṕermission for scope A and if any policy gives access then access will be granted.

@pedroigor pedroigor merged commit f8919f8 into keycloak:master Jun 4, 2018
@pedroigor pedroigor deleted the KEYCLOAK-7367 branch June 4, 2018 12:35
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

Successfully merging this pull request may close these issues.

5 participants