Can't create composite roles in Keycloak using Admin REST Api - json

I'm attempting to manage roles and composites programmatically in my Keycloak 6.0.1 system using the Admin REST API. According to the documentation, this is what I want to be using:
https://www.keycloak.org/docs-api/6.0/rest-api/index.html#_roles_resource
Right off the bat, my base URL for Keycloak's API seems to be:
https://example.com/auth/admin
instead of /auth, as the docs seem to suggest. If I use the base URL specified in the docs I get a 404. I discovered this alternate URL structure by inspecting what the Kubernetes admin page was doing when I manage the installation through my browser.
In any case, I am now successfully creating roles using the POST /{realm}/clients/{id}/roles endpoint. Problems begin when I try to add a composite using POST /{realm}/clients/{id}/roles/{role-name}/composites with a POST like this:
/auth/admin/realms/REDACTED/clients/546052d9-6ba1-483e-93a5-a5fda51505b8/roles/%5ECouponAttemptsLog%25Unowned%25Write/composites
authorization: Bearer REDACTED
Content-Type: application/json
Accept: */*
Content-Length: 217
User-Agent: node-fetch/1.0 (+https://github.com/bitinn/node-fetch)
Accept-Encoding: gzip,deflate
Connection: close
Host: REDACTED
{"roles":[{"name":"^CouponAttemptsLog/id%Unowned%Write"},{"name":"^CouponAttemptsLog/code%Unowned%Write"},{"name":"^CouponAttemptsLog/eventId%Unowned%Write"},{"name":"^CouponAttemptsLog/attemptedDate%Unowned%Write"}]}
The error message logged by Keycloak is:
14:18:02,617 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-4884) Uncaught server error: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList` out of START_OBJECT token
...and Keycloak returns a 500 response with no text.
As far as I can tell, this matches the expected request shape specified in the Keycloak 6 API documentation, and I'm at a loss for what could be causing this deserialization failure. Just for yuks, I tried sending in a naked JSON array as the body, with no improvement.
What am I doing wrong? I understand that the error from Keycloak means it's trying to convert something to an ArrayList which can't be, but I'm at a loss to figure out what and why.

It wants an array of role objects. Try this:
[
{
"name": "^CouponAttemptsLog/id%Unowned%Write"
},
{
"name": "^CouponAttemptsLog/code%Unowned%Write"
},
{
"name": "^CouponAttemptsLog/eventId%Unowned%Write"
},
{
"name": "^CouponAttemptsLog/attemptedDate%Unowned%Write"
}
]
Glancing at the code, I think you'll need to include a role id in addition the name...even if the doc says all fields within RoleRepresentation are optional.

I don't know if you solved your problem but in my case I need to use both id and name while assigning roles to composite role. And yes "partial" roles need to be created before assignment to composite role.
[
{
"id": UUID of created role
"name": "^CouponAttemptsLog/id%Unowned%Write"
}
]
Flow in my looks like this:
In a loop create partial role(s) - Keycloak api return location of new role in headers so you need to call GET to obtain role's json
Push {"id": UUID} to array - or even better {"id": UUID, "name": name } or whole role's representation (to call composites id is enough but in case of service roles you need both
Create composite role
Call composites endpoint

Related

Calling external APIs through fiware orion context broker to validate using keyrock

I am a student working on a project and exploring viability of using fiware for that. So far I've learnt that to call external APIs we can use registrations for an entity to fetch dynamic data.
Here is the situation:
In my project, I am calling external APIs for fetching some data at frontend.
I want to add access control for users so that they are restricted from calling the APIs if not permitted. For this reason I am trying to find out a way such that keyrock can validate the requests so that I don't have to manually validate these external APIs. Since these aren't related to any entity I don't want to use registration for this purpose.
I intend to do user management through keyrock itself. Currently keyrock can restrict based on resources (i.e. URL path) of the application and permission. I am very confused at this point that if I add an API call at any page to fetch data from external API, how can I make use of keyrock access control in this situation.
Also, can I make orion call the external API somehow and make the data an entity?
Any help and hint is greatly appreciated. Thanks in Advance.
A registration is a contract to return a series of attributes connected to an entity, how that is connected to an external API is up to you. There is an annotated example in the NGSI v2 tutorials - the code is also available for NGSI-LD but the documentation for NGSI-LD needs updating to reflect certain recent changes and clarifications made in NGSI-LD 1.6.1.
Regardless of the version of NGSI you use, the steps to call an external API are the same.
Create a proxy service with a handler to deal with one or more NGSI endpoints - for NGSI-v2 this will usually be the batch endpoint /op/query, for NGSI-LD I would recommend /ngsi-ld/v1/entities/<id>.
Create a registration from your context broker to this proxy e.g. for NGSI-v2:
curl -iX POST \
'http://localhost:1026/v2/registrations' \
-H 'Content-Type: application/json' \
-d '{
"description": "Random Weather Conditions",
"dataProvided": {
"entities": [
{
"id": "urn:ngsi-ld:Store:001",
"type": "Store"
}
],
"attrs": [
"relativeHumidity"
]
},
"provider": {
"http": {
"url": "http://location/of/the/proxy/interface"
}
}
}'
Note that you can also pass additional custom information using custom headers or annotating the path of the URL or whatever.
Within the proxy code make a request to the third party API and convert the response back to NGSI format. The tutorial example explains how to connect to Twitter or Cat Facts as examples.
I want to add access control for users so that they are restricted from calling the APIs if not permitted.
This is purely a matter of placing a PEP proxy in front of the call to the registrant. Imagine a context broker request like this one to Kong:
curl -X GET \
http://localhost:8000/orion/v2/entities/urn:ngsi-ld:Store:001?options=keyValues \
-H 'Authorization: Bearer {{X-Access-token}}'
Either you place the PEP in front of the context broker (in which case the entity is only returned if you have appropriate permissions, or you place a PEP in front of your registrant webservice, in which case the attributes are only appended to the entity if you have appropriate permissions. Note that the context broker Registration needs to be configured to ensure that the Authorization header will be passed on to the registrant as well.

Use Postman to Login a Cognito user with API alone

I'm migrating from Firebase where this was rather simple to do.
I'm building a custom api because the environment I need to build in will not let me use any official sdk's or anything, so this solely has to be done via rest type actions.
I essentially want to just post the username/password to aws cognito, and recieve an auth token that I can then append to the headers of future requests (to other api calls)
After hunting for quite a bit, almost all help has postman connecting to Amazon's login UI etc, and I cannot do that. It must completely handle the login process "behind the scenes" and not prompt the user with Amazon's own UI.
So, assuming this is possible:
What headers do I need (content-type etc)
How do I format the body json (or is it using something else?)
I assume I'd send it as "raw" body.
This is as far as I got so far and I'm scratching my head:
Url: https://[DOMAIN].auth.us-east-1.amazoncognito.com/oauth2/token
Body Json:
{
"ClientId": "1234etc",
"Password": "Password1_",
"UserAttributes": [
{
"Name": "email",
"Value": "test#test.com"
}
],
"Username": "test#test.com"
}
No idea if this is even the right format for the JSON I just scalped it from other posts.

REST API Posting two request simultaneously with different properties fails with 403 status code due to CSRF check

I'm sending two post requests using the REST API: http://localhost:8111/app/rest/buildQueue but my second request fails with
403 Forbidden: Responding with 403 status code due to failed CSRF check: no "Origin" header is present and no authentication provided with the request, consider adding "Origin: http://localhost:8111" header.
I'm wondering why is this happening since if I run the build in the UI and change the params ex. build1 has %version=2% and build2 has %version=3% it will run parallel with each other running on different available agents.
Here's my json request:
REST API endpoint: http://localhost:8111/app/rest/buildQueue
JSON body:
{
"branchName": "master",
"buildType": {
"id": "DockerBuild",
"projectId": "Test"
},
"properties": {
"property": [
{
"name": "DOCKER_IMAGE_NAME",
"value": "test-3"
},
{
"name": "SNAPSHOT_DEPENDENCY_VERSION",
"value": "0.6"
}
]
}
}
Am I missing a parameter to be able to run builds in parallel with each other?
When you face problems regarding CSRF protection in TeamCity (for example, you get the "Responding with 403 status code due to failed CSRF check" response from the server), you can follow these steps:
If you use a reverse proxy, make sure you correctly configure Host/Origin headers, as described above. In the meantime, you may want to add the public URL of your server to CORS-enabled origins.
You can temporary disable CSRF protection at all by setting the teamcity.csrf.origin.check.enabled=logOnly internal property.
Information about failed CSRF attempts are logged into TeamCity/logs/teamcity-auth.log files. For more detailed diagnostics of the requests, enable debug-auth logging preset.
Try pass in the request header -H 'Origin: http://localhost:8111'
Maybe this can be useful for someone, I got the same error with a single POST using Postman:
403 Forbidden: Responding with 403 status code due to failed CSRF check: no "Origin" header is present and no authentication provided with the request, consider adding "Origin: http://teamcity:20011" header.
So I followed the recommendation of the error message, and in Header I added "Origin" with the value "http://teamcity:20011" and that fixed the issue. BTW, in Authorization I selected "Bearer Token" and I pasted the token generated previously through TeamCity. This is the call:
http://teamcity:20011/app/rest/buildQueue
I was just testing how to trigger a build using the API and it worked successfully. Now the following step is to implement this call using JavaScript.
Request a CSRF header with the appropriate request:
https://teamcity/authenticationTest.html?csrf
and set it in the "X-TC-CSRF-TOKEN" header of your POST request
If you specify an Access Token to the request header like Authorization: Bearer ..., you don't need to specify a CSRF token, and what you should actually check is if you're not sending Cookies.
This is from the developer in JetBrains:
If you're using a token-based authentication, there should be no need to provide CSRF token header and obtain it with authenticationTest.html call.
In this scenario, it is expected that there are no session Cookies in the HTTP request (otherwise, TeamCity will try to find a token).
I.e. basically, you should be able to do the HTTP call in no-session way by providing the Authorization: Bearer {{token}} header only.
https://youtrack.jetbrains.com/issue/TW-69566/Flaky-builds-with-CSRF-Header-X-TC-CSRF-Token-does-not-match-CSRF-session-value#focus=Comments-27-4644138.0-0
Well, the error and the documentation don't seem to explain this, though...

Unable to create a session via CouchBase sync gateway admin REST API

I am working on implementing custom authentication using cookie Auth. So, I was playing around the sync gateway REST API to create user and session. I could successfully create the user but unable to create session via /_session API.
Following are the steps I followed.
1. Create user
POST /cookbook/_user/ HTTP/1.1
Host: localhost:4985
Content-Type: application/json
{
"name": "chef123",
"password": "1234"
}
2. Get Users
GET /cookbook/_user/ HTTP/1.1
Host: localhost:4985
Content-Type: application/json
Respone :["chef123"]
3. Create Session
POST /cookbook/_session HTTP/1.1
Host: localhost:59840
Content-Type: application/json
{
"name": "chef123",
"ttl": 1800
}
Expected:
{
"cookie_name": "SyncGatewaySession",
"expires": "2014-11-07T16:42:11.675519255-08:00",
"session_id": "c2425fa7d734bc8c3f6c507854166bef56a5fbc6"
}
Instead received:
{"authentication_handlers":["default","cookie"],"ok":true,"userCtx":{"channels":{},"name":null}}
Can Anyone please explain why is the API giving the following response.
{"authentication_handlers":["default","cookie"],"ok":true,"userCtx":{"channels":{},"name":null}}
authentication_handlers is the method you used to create the session (it could be the built-in facebook or persona login features as well). userCtx has useful information on the data access for this user like:
channels: The channels the user was given access to via the Sync Function
admin_channels: The channels the user was given access to in the config file
roles: The roles of this user
See the session docs for details: http://developer.couchbase.com/documentation/mobile/1.2/develop/references/sync-gateway/admin-rest-api/session-admin/get-db-session-sessionid/index.html
To set up authentication with Sync Gateway you can check those blogs:
Adding user Sign Up to your Android app with Node.js and Couchbase Mobile
Adding Google Sign-In with Node.js to a Couchbase Mobile application
As mentioned in the comments by krishnan, the solution to this problem is removing the trailing slash from the URI. I had the same issue.
So, instead of: POST /cookbook/_session/
Use: POST /cookbook/_session

Making REST API call using curl to Bluemix Predictive Modeling service

I would like to create HTTP GET request to REST API using the curl tool that comes with the Cloud Foundry command line interface (cf). The content/format of the request is described here, under "Retrieving a list of all currently deployed models:" subtitle. In short, the description gives me the url that I can make the request to, it also gives me the following "request example":
Content-Type: */*
Parameters:
Query Parameters:
accesskey: access_key from env.VCAP_SERVICES
I know how to retrieve all necessary parameters (i.e. the access keys, etc). The problem is that I am not sure how to interpret the above "request example" (is it header or body of the request?) and how to create curl command that will properly send the request.
I want to briefly describe what I have tried so far. When I try:
cf curl -X GET "http://{my_url}/model?accesskey={my_access_key}"
I always get the following response:
{
"code": 10000,
"description": "Unknown request",
"error_code": "CF-NotFound"
}
, when I try:
cf curl -X 'GET' http://{my_url}/model?accesskey={my_access_key}
, I think I actually get a response from the server:
<html>
<head><title>400 Bad Request</title></head>
<body bgcolor="white">
<center><h1>400 Bad Request</h1></center>
<hr><center>nginx</center>
</body>
</html>
Whenerver I try to use just "normal" curl (not the one that comes with the cf command line interface) the Bluemix Predictive Modeling service doesn't respond at all - the connection always times out. I'm not sure why, since Bluemix documentation says that any programming language can be used to make the REST API calls. In the future I would also like to use POST requests - an explanation of how to make one would be very helpful too.
Any help will be greatly appreciated.
You first need to "bind" an instance of the Predictive Model service to an app. When you have done it, you will have a "Show credentials" link below the app widget in your Bluemix dashboard. Click "Show credentials", and you will see a JSON object (which happens to be the VCAP_SERVICES value that Bluemix sets as environment variable for your app), for example:
{
"pm-20": [
{
"name": "Predictive Modeling-i6",
"label": "pm-20",
"plan": "free",
"credentials": {
"url": "https://ibmpmsrvus1.pmservice.ibmcloud.com:8443/pm/v1",
"access_key": "xxxyyyzzz"
}
}
]
}
(I have just removed my own credentials).
Finally for the Curl command, use the "url" above as root of your API, and add a query parameter "?accesskey=xxxyyyzzz" (whatever credentials you have on your own) to all API calls. For example, I add /model to my URL to query my list of models (none created):
curl -X GET "https://ibmpmsrvus1.pmservice.ibmcloud.com:8443/pm/v1/model?accesskey=xxxyyyzzz"
which returns
[]
(as I have not created any models). Note that you will likely need to quote the URL, since the access key contains characters that may mess up your shell command.
I explicitly used "-X GET": You will want to do "-X PUT" in some commands (PUT HTTP method), and most likely you can use "-d #" to upload a file as form data payload:
curl -X PUT -d #mymodelfile "https://..."