Keycloak how to obtain RPT - token

I'm trying to fetch all the permissions from Keycloak, ie all resources and scopes that a user has access to.
Basically, I want to fetch an RPT from Keycloak, with permissions shown as on Keycloak REST API docs and the below image
Unfortunately, the docs are either confusing, or the way of Requesting a RPT isn't shown. This example is all under RPT, and moving on, the docs just explain how to further introspect the token.
How can you obtain this token (anything that contains the permissions like in the sample token actually) from Keycloak?

You may want to try something like this:
USER=test
PASS=test
CLIENT_ID=test
CLIENT_SECRET=your-client-secret
RESULT=`curl -s --data "grant_type=password&client_id=${CLIENT}&client_secret=${CLIENT_SECRET}&username=${USER}&password=${PASS}" http://localhost:8080/realms/master/protocol/openid-connect/token`
ACCESS_TOKEN=`echo $RESULT | jq -r .access_token`
RPT_RESULT=`curl -s -H "Authorization: Bearer ${ACCESS_TOKEN}" --data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket&client_id=${CLIENT}&audience=${CLIENT}" http://localhost:8080/realms/master/protocol/openid-connect/token`
echo $RPT_RESULT | jq -r .access_token | cut -d "." -f2 | base64 -d | jq
This retrieves an access token first and then queries an RPT.
This should give you an output like this:
{
"exp": 1643134734,
"iat": 1643134674,
"jti": "f60caba8-8f20-43f0-9054-6389f998032c",
"iss": "http://localhost:8080/realms/master",
"aud": "test",
"sub": "18cce3e6-e3a0-4be9-a1ff-6635adf5928b",
"typ": "Bearer",
"azp": "test",
"session_state": "539a81bf-aa27-4ce4-911a-405f5a2c90ac",
"acr": "1",
"realm_access": {
"roles": [
"create-realm",
"default-roles-master",
"offline_access",
"admin",
"uma_authorization"
]
},
"resource_access": {
"master-realm": {
"roles": [
"view-identity-providers",
"view-realm",
"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"
]
},
"test-realm-realm": {
"roles": [
"view-identity-providers",
"view-realm",
"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"
]
}
},
"authorization": {
"permissions": [
{
"rsid": "9f708183-5aa3-4a8a-96fd-5be9aef5427d",
"rsname": "Default Resource"
}
]
},
"scope": "profile email",
"sid": "539a81bf-aa27-4ce4-911a-405f5a2c90ac",
"email_verified": false,
"preferred_username": "admin"
}

Related

Could not get a expected Response through a POST request

I am working this API https://developer-eu.elavon.com/docs/opayo/spec/api-reference-0#operation/createCi.
I faced an issue, when creating card-identifier. I could not get an expected response.
The test API is https://pi-test.sagepay.com/api/v1/card-identifiers
To create a Card Identifier, We need a merchantKey to use as a bearerToken and request body is
{ "cardholderName": "Spongebob Squarepants", "cardNumber": "4929000000006", "expiryDate": "0223", "securityCode": "123" }
To create merchantKey use this https://reqbin.com/pzag38mw
To create Card Identifieruse this https://reqbin.com/zkhuuecs
And I added My postamn request here.
My postman http request for create Card Identifier.
curl --location --request POST 'https://pi-test.sagepay.com/api/v1/card-identifiers' \
--header 'Authorization: Bearer E0780245-2701-4748-924A-A1D5A904EB62' \
--header 'Content-Type: application/json' \
--header 'Cookie: AWSALB=o44OLd5fFLrFUD4meQBU0sxMs64iiql4YlDlppQILCFio+6pOo16e+tLu7SaI+F8sDS8CgSrRTwOcMo//ODTGcJGgNSTHPHxrP5hs87mkM1I1Xos3F0hDEoTD4dV; AWSALBCORS=o44OLd5fFLrFUD4meQBU0sxMs64iiql4YlDlppQILCFio+6pOo16e+tLu7SaI+F8sDS8CgSrRTwOcMo//ODTGcJGgNSTHPHxrP5hs87mkM1I1Xos3F0hDEoTD4dV' \
--data-raw '{
"cardholderName": "Spongebob Squarepants",
"cardNumber": "4929000000006",
"expiryDate": "0223",
"securityCode": "123"
}'
I got this Response
{
"errors": [
{
"description": "Missing mandatory field",
"property": "cardDetails.cardNumber",
"clientMessage": "The card number is required",
"code": 1003
},
{
"description": "Missing mandatory field",
"property": "cardDetails.cardholderName",
"clientMessage": "The cardholder name is required",
"code": 1003
},
{
"description": "Contains invalid value",
"property": "cardDetails.expiryDate",
"clientMessage": "The expiry date is invalid",
"code": 1009
},
{
"description": "Missing mandatory field",
"property": "cardDetails.expiryDate",
"clientMessage": "The expiry date is required",
"code": 1003
}
]
}
But The response sholud be somthing like this:
{
"cardIdentifier": "C6F92981-8C2D-457A-AA1E-16EBCD6D3AC6",
"expiry": "2015-08-11T10:45:16.285Z",
"cardType": "Visa"
}
What is the mistake I did when I sent a post request
Check the method of posting you are using in postman. If you are unsure edit to add a screenshot. Check if you have selected:
As if you use another method it may not read it
So once you have set that instead of sending you data as:
{
"cardholderName": "Spongebob Squarepants",
"cardNumber": "4929000000006",
"expiryDate": "0223",
"securityCode": "123"
}
You should send it as:
{ "cardDetails":
{
"cardholderName": "Spongebob Squarepants",
"cardNumber": "4929000000006",
"expiryDate": "0223",
"securityCode": "123"
}
}
This is because it is asking the data from under cardDetails
Please tick this if it fixed your problem so I know

Twitter OAuth 1.0 "215 Bad Authentication Data" error when requesting token

My use case is 3-legged auth for my current business to get some impression data from Twitter. This stuff was a breeze on LinkedIn but I'm falling at the first hurdle with Twitter, having followed docs & videos I'm still running into a "Bad Authentication Data" error when getting an access token.
I've snipped the callback, consumer key and token, but the consumer key is the API key from my Twitter app and the token is the Access Token from the same. Below is the json. none, signature and timestamp I got auto generated by postman. Any pointers?
{
"name": "get_access_token",
"properties": {
"activities": [
{
"name": "Web1",
"type": "WebActivity",
"dependsOn": [],
"policy": {
"timeout": "7.00:00:00",
"retry": 0,
"retryIntervalInSeconds": 30,
"secureOutput": false,
"secureInput": false
},
"userProperties": [],
"typeProperties": {
"url": "https://api.twitter.com/oauth/request_token",
"method": "GET",
"headers": {
"OAuth": "oauth_nonce=\"wErUbiAbmCi\", oauth_callback=\"https%3A%2F%2F<snipped>\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"1613748394\", oauth_consumer_key=\"<snipped>", oauth_signature=\"hMnZtN5hT5KHRcyrxz8xis33C1c=\", oauth_version=\"1.0\", oauth_token = \"<snipped>\""
}
}
}
],
"annotations": []
}
}
The OAuth headers need to be sorted alphabetically. The documentation is here.

Adopt authorities from JWT in Spring Resource Server

My Spring OAuth2 client only grants the ROLE_USER authority to authenticated users, ignoring the authorities from resource_access in the provided JWT.
{
"wdb": {
"roles": [
"TestRole",
"TestRoleFoo",
"TestRoleBar"
]
}
How can I setup my OAuth2 client to also grant the authorities from resource_access (TestRole, TestRoleFoo, TestRoleBar)? Am I missing some crucial configuration here?
My configuration in detail
On my Resource Server, I'm using Springs default OAuth2 client with the following configuration:
security:
oauth2:
client:
client-id: wdb
client-secret: some-secret
access-token-uri: http://localhost:8080/auth/realms/master/protocol/openid-connect/token
user-authorization-uri: http://localhost:8080/auth/realms/master/protocol/openid-connect/auth
scope: openid profile email
authorized-grant-types: code
resource:
user-info-uri: http://localhost:8080/auth/realms/master/protocol/openid-connect/userinfo
My Keycloak Authorization Server provides me with the following JWT payload:
{
"jti": "6a666808-2b69-4de0-ab94-9ceebdac13de",
"exp": 1569674641,
"nbf": 0,
"iat": 1569674341,
"iss": "http://localhost:8080/auth/realms/master",
"aud": "account",
"sub": "f19b0443-4cce-495a-8479-ff36f82628fc",
"typ": "Bearer",
"azp": "wdb",
"auth_time": 1569674341,
"session_state": "0a411eda-0efb-4f29-99c4-b54da6298d6c",
"acr": "1",
"allowed-origins": [
"/*"
],
"realm_access": {
"roles": [
"offline_access",
"uma_authorization"
]
},
"resource_access": {
"wdb": {
"roles": [
"TestRole",
"TestRoleFoo",
"TestRoleBar"
]
},
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
},
"scope": "openid profile email",
"email_verified": true,
"user_name": "sullrich",
"name": "Sebastian Ullrich",
"preferred_username": "sullrich",
"given_name": "Sebastian",
"locale": "de",
"family_name": "Ullrich",
"email": "sebastian#wdb.local"
}
Within my Resource Server, this JWT will be derived to the following OAuth2Authentication:
{
"authorities":[
{
"authority":"ROLE_USER"
}
],
"details":{
"remoteAddress":"0:0:0:0:0:0:0:1",
"sessionId":"... session id ...",
"tokenValue":"... encoded payload ...",
"tokenType":"bearer"
},
"authenticated":true,
"userAuthentication":{
"authorities":[
{
"authority":"ROLE_USER"
}
],
"details":{
"sub":"f19b0443-4cce-495a-8479-ff36f82628fc",
"email_verified":true,
"user_name":"sullrich",
"name":"Sebastian Ullrich",
"preferred_username":"sullrich",
"given_name":"Sebastian",
"locale":"de",
"family_name":"Ullrich",
"email":"sebastian#wdb.local"
},
"authenticated":true,
"principal":"Sebastian Ullrich",
"credentials":"N/A",
"name":"Sebastian Ullrich"
},
"principal":"Sebastian Ullrich",
"credentials":"",
"clientOnly":false,
"oauth2Request":{
"clientId":"wdb",
"scope":[
],
"requestParameters":{
},
"resourceIds":[
],
"authorities":[
],
"approved":true,
"refresh":false,
"responseTypes":[
],
"extensions":{
}
},
"name":"Sebastian Ullrich"
}
Sounds like you need a custom JwtAuthenticationConverter
Spring will only map scopes into granted authorities by default.
You can create a class that extends the default implementation and overrides the extractAuthorities method.
Then you have access to the claims and you can map them to the roles you want.
public class JwtGrantedAuthoritiesConverter extends JwtAuthenticationConverter {
#Override
protected Collection<GrantedAuthority> extractAuthorities(Jwt jwt) {
Collection<GrantedAuthority> authorities = super.extractAuthorities(jwt);
if(jwt.containsClaim("roles") && jwt.getClaimAsStringList("roles").contains("TestRole")) {
authorities.add(new SimpleGrantedAuthority("ROLE_TestRole"));
} else {
.........
}
return authorities;
}
Then you plug in your version into the resource server in your WebSecurityConfigurationAdapter:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
......
.oauth2ResourceServer()
.jwt()
.jwtAuthenticationConverter(new JwtGrantedAuthoritiesConverter());
Your roles are a bit more nested i.e. under resource_access . wdb
You can always create a keycloak mapper to add them under roles in the parent node to simplify things.
Here is an example of a resource server that does something similar
https://github.com/wlesniak/effective-oauth2-with-spring-security-and-spring-boot/tree/master/module_8/mod8_support-service

How to fix "Unsupported AAD Identity" when create a call from webapp?

When I call this from my web app, I'm getting an error code 9000 - "Unsupported AAD Identity".
POST https://graph.microsoft.com/beta/app/calls
request header:
{
"Content-type" => "application/json",
"Authorization" => "Bearer eyJ0eXAiOiJKV1QiLCJub25jZSI6IkFRQUJBQUFBQUFBUDB3TGxxZExWVG9PcEE0a3d6U254TkY3UDFxM05tT0xEOHZJVXk0NmFtVWRaV1ZhbGdFUWx2Vkw4Mmp4cS1tZFpwOWdiY1kwdVB4U3ctOGlGd3JRM00zUWlBS29KS08zRzN3czNsNlFmZXlBQSIsImFsZyI6IlJTMjU2IiwieDV0IjoidTRPZk5GUEh3RUJvc0hqdHJhdU9iVjg0TG5ZIiwia2lkIjoidTRPZk5GUEh3RUJvc0hqdHJhdU9iVjg0TG5ZIn0.eyJhdWQiOiJodHRwczovL2dyYXBoLm1pY3Jvc29mdC5jb20iLCJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC81NGRkYWJiMS1kNjU5LTRhZmYtODNkZi1kYzUwODk2OTI3YjgvIiwiaWF0IjoxNTYzODQxMTQ2LCJuYmYiOjE1NjM4NDExNDYsImV4cCI6MTU2Mzg0NTA0NiwiYWNjdCI6MCwiYWNyIjoiMSIsImFpbyI6IkFTUUEyLzhNQUFBQWlhS2hob3hBalByVHJsOEZVc0w0Q2Y2Zkc4M2x4YVpIWXVYOTJaT0w5eDQ9IiwiYW1yIjpbInB3ZCIsInJzYSJdLCJhcHBfZGlzcGxheW5hbWUiOiJNeSBSdWJ5IEFwcCIsImFwcGlkIjoiYTFlMjliY2YtODYxOS00ZjVjLWEzMjAtNmY2N2QzMGZiOTlkIiwiYXBwaWRhY3IiOiIxIiwiZGV2aWNlaWQiOiJjMThiZDJmYS05YzhkLTRlOGItYTUwMi1lYWFlMmI2YzM1NjYiLCJmYW1pbHlfbmFtZSI6IuWFqOS9kyIsImdpdmVuX25hbWUiOiLnrqHnkIbogIUiLCJpcGFkZHIiOiIxNTMuMTU2Ljg5LjYzIiwibmFtZSI6IuWFqOS9kyDnrqHnkIbogIUiLCJvaWQiOiIwZGFmMzVhNS1jZjUyLTQ0ODMtYmM0NS0xM2ExYTBlYWE5Y2MiLCJwbGF0ZiI6IjMiLCJwdWlkIjoiMTAwMzIwMDA0OTE0QkVDMCIsInNjcCI6IkNhbGVuZGFycy5SZWFkIERpcmVjdG9yeS5BY2Nlc3NBc1VzZXIuQWxsIERpcmVjdG9yeS5SZWFkLkFsbCBlbWFpbCBHcm91cC5SZWFkLkFsbCBHcm91cC5SZWFkV3JpdGUuQWxsIG9wZW5pZCBwcm9maWxlIFVzZXIuUmVhZCBVc2VyLlJlYWQuQWxsIFVzZXIuUmVhZEJhc2ljLkFsbCIsInNpZ25pbl9zdGF0ZSI6WyJrbXNpIl0sInN1YiI6IktIZ3dXcEdHMWRRdHlUSGplU3pfQ1RPWk03b0w1bHRocWFUclRSbi1ucm8iLCJ0aWQiOiI1NGRkYWJiMS1kNjU5LTRhZmYtODNkZi1kYzUwODk2OTI3YjgiLCJ1bmlxdWVfbmFtZSI6ImFkbWluQGV4ZW9kZXYuaXRlZS5jby5qcCIsInVwbiI6ImFkbWluQGV4ZW9kZXYuaXRlZS5jby5qcCIsInV0aSI6IlVPRURPdnAzWEVTUU9rckU0dEFFQUEiLCJ2ZXIiOiIxLjAiLCJ3aWRzIjpbIjYyZTkwMzk0LTY5ZjUtNDIzNy05MTkwLTAxMjE3NzE0NWUxMCIsImY3MDkzOGEwLWZjMTAtNDE3Ny05ZTkwLTIxNzhmODc2NTczNyJdLCJ4bXNfc3QiOnsic3ViIjoiS2Mwc1JER3hHZFV5eDR6Qk1ucm9XWDhkNVpBTjVKN1EwSTh5SWZnUUhZZyJ9LCJ4bXNfdGNkdCI6MTU1ODMxNTU3OH0.cQmQLHWUfs8iOOPHf5SmWJYgsjQqLjZq9W5pKZzwRBtiQoOsUHILZkGYKz7_jx0bW-p87Cq6mFzswnoK30smEH6l7VW-gkzrxc2JFuDh-nKvfemTKnI3O_ZjtrEJNp-sWZF5Enm28Mg5Lh4hfBrSiROO8b0gAMytLWx9Qjy3H5x_zzdy34D1B1O8nCFrx217olDzarDCd6KqPtfCqoS00mWqCIwlEvHSi7OCtBV0HaUEl07-hi9hovu-uaHTLRW50fFP9hfoWYOz5qRyidpGNRtR26rUtexlOXtceZKYv5fD_VFNiBdT7d06EiK58UBib08eHjcvNJ6NEhcW0xTOxA"
}
request body:
{
"callbackUri": "https://bot.contoso.com/api/calls",
"mediaConfig": {
"#odata.type": "#microsoft.graph.serviceHostedMediaConfig",
"preFetchMedia": [
{
"uri": "https://cdn.contoso.com/beep.wav",
"resourceId": "1D6DE2D4-CD51-4309-8DAA-70768651088E"
},
{
"uri": "https://cdn.contoso.com/cool.wav",
"resourceId": "1D6DE2D4-CD51-4309-8DAA-70768651088F"
}
]
},
"source": {
"identity": {
"application": {
"id": "RealAppId"
}
},
"languageId": "languageId-value",
"region": "region-value"
},
"subject": "Test Call",
"targets": [
{
"identity": {
"user": {
"id": "RealTargetUserId",
"tenantId": "RealTenantId",
"displayName": "RealName"
}
}
}
],
"tenantId": "tenantId-value"
}
response:
{
"error": {
"code": "UnknownError",
"message": "{
"errorCode": "9000",
"message": "Unsupported AAD Identity.",
"instanceAnnotations": []
}",
"innerError": {
"request-id": "RealRequestId",
"date": "2019-07-23T00:25:12"
}
}
}
I n the request body, RealTargetUserId is an Azure ActiveDirectory UserID with an E1 license provisioned. RealAppId is the registered application id and with Permissions as follows:
Calls.AccessMedia.All
Calls.Initiate.All
Calls.InitiateGroupCall.All
Calls.JoinGroupCall.All
Calls.JoinGroupCallAsGuest.All
According to the documentation, you need one of the following Application scopes to create a call: Calls.JoinGroupCallsasGuest.All, Calls.JoinGroupCalls.All, Calls.Initiate.All, Calls.InitiateGroupCalls.All.
The authentication token you're using, however, is using Delegated scopes. This tells me you're either using OAuth's Authentication Code or Implicit grant flows. Neither of these will work for this operation.
In order to use this endpoint, you'll need to request an App-Only token using the OAuth Client Credentials grant. There are instructions on how to do this in the documentation: Get access without a user.
Also, you're over-requesting permission scopes. For example, there is no need to request User.Read, User.Read.All, and User.ReadBasic.All, you only need User.Read.All to accomplish the same thing. The same goes for Group.Read.All and Group.ReadWrite.All.
To fix issues with "Application is not registered in our store" you need to make sure that you use a Bot Channel Registration instead of just a normal App Registration.
The Bot Channel Registration should also have Microsoft Teams as a registered channel and have calling enabled.
For more information see: https://microsoftgraph.github.io/microsoft-graph-comms-samples/docs/articles/calls/register-calling-bot.html
The final step about adding the bot in teams can be skipped if you only care about API access.

How to set custom_fields that has an enum_value using a POST HTTP request?

I'm trying to set a custom_fields of type enum_value in a task that I'm creating with a POST HTTP request.
I managed to set a custom_field of type number but I'm having issue with the custom_fields of type enum_value
Questions:
Here's what I did so far:
1- I created the custom_fields that I want to populate on asana, I can set custom_fields of type number but not the ones of type enum_value( see picture attached)
Here's my code (I tried different implementations to set the custom_fields that were incorrect) :
var task = {
data: {
assignee: "me",
workspace: "1234567",
projects: "9876543",
parent: null,
custom_fields: {
"1234567898": 333, // this works
"98765": "Public" // this custom field holds an enum_values, this implementation doesn't work
},
notes: "Test notes"
}
}
It looks like you put the name of the enum_value instead of the id. Here is an example of a PUT/POST request and response:
# Request
curl --request PUT -H "Authorization: Bearer <personal_access_token>" \
https://app.asana.com/api/1.0/tasks/1001 \
-d
'{
"data": {
"custom_fields":{
"124578":"439"
}
}
}'
# Response
{
"data": {
"id": 1001,
"name": "Hello, world!",
"completed": false,
"...": "...",
"custom_fields": [
{
"id": 124578,
"name": "Priority",
"type": "enum",
"enum_value": {
"id": 439,
"name": "High",
"enabled": true,
"color": "red"
}
},
"~..."
]
}
}
It's admittedly a bit buried, but if you look in the Custom Fields section of the getting started documentation, there is an example of creating custom fields under "Accessing Custom Field values on Tasks".

Resources