Below is my use case:
I need to add a claim to the access token so that i can use it during policy evaluation on my resource. My policy is a javascript based policy and it gets access only to reserved and custom attributes of the logged in user.
I have used the below api to push claims:
curl -X POST \
http://localhost:8082/auth/realms/cms-non-prod/protocol/openid-connect/token \
-H 'Authorization: Bearer eyJhbGciOiJSXXXXXXXXXXXXXXXX' \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Postman-Token: ac020c2b-9efb-4817-81ea-61895c8775a7' \
-d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Auma-ticket&claim_token=ewoiaW5zdGl0dXRpb25JZCI6WyJEQ0IiXQp9& claim_token_format=urn%3Aietf%3Aparams%3Aoauth%3Atoken-type%3Ajwt&client_id=indra-bff \
&client_Secret=5760582d-74ff-496c-a6c2-2530ddde6408&audience=indra-bff'
It adds the claim but it adds in to authorization--> Permissions-->Resources. How do i read this if i have a JS based policy.
Any pointers on this will help.
Below is the token i get when i hit above url:
{
"jti": "4c00f1a4-8038-4c45-820d-23a9c9ab6d42",
"exp": 1580733917,
"nbf": 0,
"iat": 1580730317,
"iss": "http://localhost:8082/auth/realms/cms-non-prod",
"aud": "indra-bff",
"sub": "9ab2fc80-3a5c-426d-ae78-56de01d214df",
"typ": "Bearer",
"azp": "indra-bff",
"auth_time": 0,
"session_state": "2ab35757-d09d-4d52-946b-f519a1338abf",
"acr": "1",
"realm_access": {
"roles": [
"PR_DCB_RECON_ASSOCIATE",
"PR_YBL_RECON_ASSOCIATE",
"offline_access",
"uma_authorization",
"PR_DCB_RECON_MGR"
]
},
"resource_access": {
"indra-bff": {
"roles": [
"uma_protection"
]
},
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"authorization": {
"permissions": [
{
"claims": {
"institutionId": [
"DCB"
]
},
"rsid": "17fdf554-8643-4741-b9a4-13309e830b6f",
"rsname": "Default Resource"
},
{
"scopes": [
"DELETE",
"POST",
"GET",
"PUT",
"PATCH"
],
"claims": {
"institutionId": [
"DCB"
]
},
"rsid": "56cabb7c-76a1-4260-bd9f-d5494458c6bf",
"rsname": "adjustment"
},
{
"scopes": [
"DELETE",
"POST",
"GET",
"PUT",
"PATCH"
],
"claims": {
"institutionId": [
"DCB"
]
},
"rsid": "70297346-8010-4c1d-91b1-9bc22edd3061",
"rsname": "chargeback"
}
]
},
"scope": "profile email",
"institution": "UNKNOWN",
"email_verified": false,
"preferred_username": "siva",
"email": "siva#goniyo.com"
}
Thanks for your help.
Cheers,
This method if for the UI. In your realm, select your client. For that client, go the 'Mappers' option and then click on 'Create'. You can have the mapper type as 'User Attribute' and select the option(s) to add the attribute to ID token, access token and userinfo. The attribute added here should exist on the user.
Check if you can get from the resource
var permission = $evaluation.getPermission();
var resource = permission.getResource();
Claims in your claim token can be reached through the Permission handle.
Considering your claim_token contains the following information:
{
"institutionId":["DCB"]
}
You can use this Javascript in your policy to fetch the string value "DCB":
$evaluation.getPermission().getClaims()["institutionId"].toArray()[0]
Source: Keycloak JavaDocs: ResourcePermission
Related
How do I get the timestamp at which a PR review was request/re-requested? It shows as an event in the conversations tab in a PR so it must exist somewhere.
The pulls API endpoint show who has been requested to review but I can't see when.
"requested_reviewers": [
{
"login": "tamlyn",
...
},
],
Any ideas?
You're looking for the GitHub Timeline API. See the docs for the Timeline API here.
Request:
curl \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer <YOUR-TOKEN>" \
https://api.github.com/repos/OWNER/REPO/issues/ISSUE_NUMBER/timeline
Response:
...
{
"id": "12345",
...
"actor": {
"login": "user",
...
},
"event": "review_requested",
"created_at": "2022-01-01T01:01:01Z",
...
"review_requester": {
"login": "user",
...
},
"requested_reviewer": {
"login": "user2",
...
},
...
},
...
I want to create a user and assign a client role with it in a single API in Keycloak I have attached the details.
I have this API
http://testkeycloak.com:8085/auth/admin/realms/engineer/users
{
"enabled":true,
"username":"joshbiden",
"email":"email#gmail.com",
"firstName":"Josh",
"lastName":"biden",
"attributes":
{
"Mobile Number":"3333332332"
},
"clientRoles":
{
"name": "DEVELOPER"
},
"credentials":
[
{
"type":"password",
"value":"rollback",
"temporary":false
}
]
}
CLIENT ROLE - DETAILS
{
"id": "32e432da-d0c0-45f8-a67d-f3146b7a24b4",
"name": "DEVELOPER",
"composite": false,
"clientRole": true,
"containerId": "343434-7631-4187-ac76-ad78de119b90"
}
How can I assign two clients' roles to the USER, I have tried to add users but facing an unknown error. Let me know any solution for the same
I want to create a user and assign a client role with it in a single
API in Keycloak I have attached the details.
Unfortunately, it is impossible to do that with a single API call, even though the Keycloak Admin rest API documentation infers otherwise. This can be confirmed by looking at this GitHub issue. Quoting the reply from that thread (from the Keycloak Project Leader Stian Thorgersen):
So, unfortunately, the answer from #Devendra Mahajan is simply not correct.
The solution is to perform two calls, namely:
one to create the user
another to assign the roles
First create the user using the endpoint POST /{realm}/users and with the following data (without the role):
{
"username": "joshbiden",
"enabled": true,
"firstName": "Josh",
"lastName": "biden",
"email": "email#gmail.com",
"attributes": {
"Mobile Number": [
"3333332332"
]
},
"credentials": [{
"type":"password",
"value":"rollback",
"temporary":false
}]
}
Second, you assign the role using the endpoint :
POST /{realm}/users/{id}/role-mappings/clients/{id of client}
with the data:
[{
"id": "32e432da-d0c0-45f8-a67d-f3146b7a24b4",
"name": "DEVELOPER",
"composite": false,
"clientRole": true,
"containerId": "343434-7631-4187-ac76-ad78de119b90"
}]
Step-by-Step
Warning: The /auth path was removed starting with Keycloak 17 Quarkus distribution. So you might need to remove the /auth from the endpoint calls presented on this answer.
To use Keycloak Admin REST API you need an access token from a user with the proper permissions. I will be using the admin user from the master realm:
curl "https://${KEYCLOAK_HOST}/auth/realms/master/protocol/openid-connect/token" \
-d "client_id=admin-cli" \
-d "username=$ADMIN_NAME" \
-d "password=$ADMIN_PASSWORD" \
-d "grant_type=password"
You will get a JSON with the admin's token. Extract the value of property access_token from that response. Let us save it in the variable $ACCESS_TOKEN for later reference.
To create the user in your realm $REALM_NAME:
curl -X POST "https://${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/users"
-H "Content-Type: application/json" \
-H "Authorization: bearer $ACCESS_TOKEN" \
-d "${USER_JSON_DATA}"
For those that need you can also have a look at my scripts to automatize the user creation on GitHub, namely this or this.
To assign the client role to the user you need the know beforehand the following fields:
id of the user
id of the client
client role representation
To get the user id from your realm $REALM_NAME:
curl -X GET "https://${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/users/?username=${USERNAME}" \
-H "Content-Type: application/json" \
-H "Authorization: bearer $ACCESS_TOKEN"
From the response extract the user id for example as follows
jq -r ".[] | select(.username==\"$USERNAME\")" | jq -r id
and save it in the variable ${USER_ID}.
To get the client id call the endpoint get clients with the parameter clientID:
curl -X GET "${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/clients?clientId=${CLIENT_ID}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${ACCESS_TOKEN}"
Extract id from the response (e.g., jq -r .[0].id) and save it in variable ${ID_OF_CLIENT}.
With the previous id you can get the client role as follows:
curl -X GET "http://${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/clients/${ID_OF_CLIENT}/roles/${ROLE_NAME}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${ACCESS_TOKEN}"
Save the json response in ${CLIENT_ROLE}, and assign the role to the user as follows:
curl -X POST "http://${KEYCLOAK_HOST}/auth/admin/realms/${REALM_NAME}/users/${USER_ID}/role-mappings/clients/${ID_OF_CLIENT}" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-d "${CLIENT_ROLE}"
I have created scripts for the aforementioned steps that can be accessed here and executed using the script getClientRoleByName.sh.
Try This,
{
"enabled": true,
"username": "joshbiden",
"email": "email#gmail.com",
"firstName": "Josh",
"lastName": "biden",
"attributes": {
"Mobile Number": "3333332332"
},
"clientRoles": {
"<name-of-the-client-in-realm>": ["DEVELOPER"]
},
"credentials": [
{
"type": "password",
"value": "rollback",
"temporary": false
}
]
}
This can be achieved using the partial import API
POST /{realm}/partialImport
With this API you can also import multiple users in one call.
This is not a solution for update though.
Body sample:
{
"users": [
{
"username": "user1",
"enabled": true,
"totp": false,
"emailVerified": true,
"firstName": "First name",
"lastName": "Last name",
"disableableCredentialTypes": [],
"requiredActions": [],
"notBefore": 0,
"access": {
"manageGroupMembership": true,
"view": true,
"mapRoles": true,
"impersonate": true,
"manage": true
},
"groups": [
],
"realmRoles": [
]
},
{
"username": "user2",
"enabled": true,
"totp": false,
"emailVerified": true,
"firstName": "User 2",
"lastName": "Last name",
"disableableCredentialTypes": [],
"requiredActions": [],
"notBefore": 0,
"access": {
"manageGroupMembership": true,
"view": true,
"mapRoles": true,
"impersonate": true,
"manage": true
},
"groups": [
],
"realmRoles": [
"some realm role"
],
"clientRoles": {
"some client": [
"some client role"
]
}
}
]
}
I'm trying integrate PayPal V2 Onboarding in sandbox.
My call is :
curl -v -X POST https://api-m.sandbox.paypal.com/v2/customer/partner-referrals \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <My-Access-Token> " \
-d '{
"tracking_id": "795_123",
"operations": [
{
"operation": "API_INTEGRATION",
"api_integration_preference": {
"rest_api_integration": {
"integration_method": "PAYPAL",
"integration_type": "THIRD_PARTY",
"third_party_details": {
"features": [
"PAYMENT",
"REFUND"
]
}
}
}
}
],
"products": [
"EXPRESS_CHECKOUT",
"PPPLUS"
],
"legal_consents": [
{
"type": "SHARE_DATA_CONSENT",
"granted": true
}
]
}'
And the response is :
{
"name": "INVALID_REQUEST",
"message": "Request is not well-formed, syntactically incorrect, or violates schema.",
"debug_id": "266c1b0e09a8f",
"information_link": "",
"details": [{
"issue": "INVALID_ARRAY_LENGTH",
"description": "The number of items in an array should not be more than 1",
"field": "/products",
"location": "body"
}],
"links": []
}
Has anyone come up to this error message for "products" array, or is this a PayPal v2 Onboarding bug?
I have two clients in Keycloak:
CP: Client public
CC: Client confidential with Service Accounts enabled and several resources.
Resources owners are users who created them and they manage the access too.
The User (U) who created the Resource (R) can log in to CC and use the access token for call endpoints on CP.
Now I would like U will be able to set UMA policies, but the access token is from CP, not from CC where the resources are, so Keycloak is complaining about de token.
org.keycloak.authorization.client.util.HttpResponseException: Unexpected response from server: 403 / Forbidden / Response from server: {\"error\":\"invalid_clientId\",\"error_description\":\"Client application [CP] is not registered as a resource server.\"}
fun onlyOwner(accessToken: String, id: String, resourceId: String) {
val request = UmaPermissionRepresentation()
request.name = "Only owner can view $id"
request.description = "Only owner can view this resource"
request.scopes = setOf(ResourceScope.VIEW)
request.condition = ONLY_OWNER_CONDITION
authzClient.protection(accessToken).policy(resourceId).create(request)
}
Keycloak docs mention the following:
"
The Policy API is available at:
http://${host}:${port}/auth/realms/${realm_name}/authz/protection/uma-policy/{resource_id} This API is protected by a bearer token that must represent a consent granted by the user to the resource server to manage permissions on his behalf. The bearer token can be a regular access token obtained from the token endpoint using:
Resource Owner Password Credentials Grant Type
Token Exchange, in order to exchange an access token granted to some client (public client) for a token where audience is the resource server
I exchanged the CP client to CC client:
Original token:
{
"exp": 1606687405,
"iat": 1606651407,
"auth_time": 1606651405,
"jti": "1e4075a9-ce49-4462-91f7-33b8963f56dd",
"iss": "http://localhost/auth/realms/test",
"aud": "account",
"sub": "8381b629-5f10-401c-ae90-bb37769e5f70",
"typ": "Bearer",
"azp": "CP",
"session_state": "6c2d73e7-a4bd-44da-b242-cdf26ec812bc",
"acr": "1",
"allowed-origins": [
"*"
],
"realm_access": {
"roles": [
"offline_access",
"uma_authorization"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "openid email profile",
"email_verified": true,
"name": "Test First",
"preferred_username": "test",
"given_name": "Test",
"family_name": "First",
"email": "test#invent.com"
}
Exchanged token:
{
"exp": 1606687405,
"iat": 1606652039,
"auth_time": 1606651405,
"jti": "0c84f42a-973e-4bc7-9a6d-2c4fec548512",
"iss": "http://localhost/auth/realms/test",
"aud": [
"account",
"CC"
],
"sub": "8381b629-5f10-401c-ae90-bb37769e5f70",
"typ": "Bearer",
"azp": "CP",
"session_state": "6c2d73e7-a4bd-44da-b242-cdf26ec812bc",
"acr": "1",
"allowed-origins": [
"http://localhost"
],
"realm_access": {
"roles": [
"offline_access",
"uma_authorization"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "email profile",
"email_verified": true,
"name": "Test First",
"preferred_username": "test",
"given_name": "Test",
"family_name": "First",
"email": "test#invent.com"
}
But the error persists alghout aud changed from account to [account,cc].
The solution is exchanging the token using as client_id and client_secret the target client (cc). After that, you can use the access_token returned by Keycloak as bearer token for creating the UMA_Policy.
Exchange public client token to the confidential client token
Create a policy with the new access token
When creating a subscription, it would be nice to return the subscription ID.
For instance, the following code doesn't return anything :
curl localhost:1026/v2/subscriptions -s -S --header 'Content-Type: application/json' \
-d #- <<EOF
{
"description": "A subscription to get info about Room1",
"subject": {
"entities": [
{
"id": "Room1",
"type": "Room"
}
],
"condition": {
"attrs": [
"pressure"
]
}
},
"notification": {
"http": {
"url": "http://localhost:1028/accumulate"
},
"attrs": [
"temperature"
]
},
"expires": "2040-01-01T14:00:00.00Z",
"throttling": 5
}
EOF
In the subscription case, the resource id is generated server-side (with difference to the entities endpoint, where the id is decided client-side).
It would be nice to return it in the POST call, is there any way to do this?
Subscription ID is retrieved in Location header in the response to the subscription creation request, eg:
Location: /v2/subscriptions/5b991dfa12f473cee6651a1a
More details in the NGSIv2 API specification (check "Create Subscription" section).