I successfully configured Wildfly 26 to authenticate via Keycloak following the usual tutorial. Example: https://www.youtube.com/watch?v=2gQO4_7Z5CI
It works as announced - when required the user's browser gets redirected to keycloak, after login it redirects back. That much for authentication. I also checked that the authorization can be performed by running request.isUserInRole(...) which is true if and only if in keycloak some role was associated to that user. That much for authorization.
But the methods request.getRemoteUser() and request.getUserPrincipal().getName() only return the keycloak's userid, which looks like 896128e8-3260-42c8-9457-3c8ee236eb4d.
How can I make Wildfly OIDC to report the username by looking at the preferred_username token claim?
So I learned that Wildfly's OIDC client can be configured to read the principal name from another token claim. For this it was sufficient to add the line
"principal-attribute": "preferred_username",
into my web application's WEB-INF/oidc.json. This is the only line required on top of the configuration generated by Keycloak:
{
"principal-attribute": "preferred_username",
"realm" : "myrealm",
"auth-server-url" : "http://localhost:8180/",
"ssl-required" : "external",
"resource" : "webapp",
"credentials" : {
"secret" : "7BqGXjt7cw6p88DNoiXCi1663bIzKPwY"
},
"confidential-port" : 0
}
When authenticating, the tokens emitted by Keycloak are exactly the same however the client uses the specified field's value instead of the sub value.
From the documentation:
principal-attribute
OpenID Connect ID Token attribute to populate the UserPrincipal name with. If token attribute is null, defaults to sub. Possible values are sub, preferred_username, email, name, nickname, given_name, family_name.
Related
I would like to programmatically register confidential OIDC client (the client is a backend service). I checked the keycloak document about it. And I use the “Initial access token“ approach as recommended.
After I created a "initial access token" on the UI console, I register a new client by:
POST https://my-keycloak-host/auth/realms/MyRealm/clients-registrations/default
Headers: Authorization: Bearer <initial access token>
{ "clientId": "my-client" }
The response contains a registrationAccessToken. But I expect to get a client secret. How can I get it? And what is the usage for that registrationAccessToken?
For some unknown reason Keycloak doesn't set secret properly. But you can define own secret with secret property in the payload (tested with Keycloak 16.1.1), e.g.:
{
"clientId": "my-client",
"secret": "my-secret"
}
Doc:
https://openid.net/specs/openid-connect-registration-1_0.html
https://www.keycloak.org/docs/latest/securing_apps/index.html#_client_registration
I am trying to generate a JSON Web Token(JWT) via named credentials as per user.
I want to use this named creds for authentincation purpose. So that using them after salesforce providing JSON web token, in exchange my local auth server will provide a token.
Below are the settings I have added while creating the named credentials as per user.
Label : TestJWTCredential
Name : TestJWTCredential
URL : -> external-endpoint <-
In Authentication Part
Certificate : MulesoftJWT
Identity Type : Per User
Authentication Protocol : JWT Token Exchange
Token Endpoint Url : http://localhost:8091/api/provider/token
Scope : refresh_token full
Issuer : -> my-username <-
Per User Subject : $userId
Audience : http://localhost:8091/api/provider/token
Token Valid for : 1 Hours
JWT Signing Certificate : MulesoftJWT
Ref :- https://help.salesforce.com/articleView?err=1&id=sf.named_credentials_about.htm&type=5#language-combobox
"http://localhost:8091/api/provider/token" This is the url of my authorization server which is a mule application deployed on my local.
Also while calling this named creds from developer console, it gives this error
System.CalloutException: Unable to complete the JWT token exchange.
Below is the APEX code,
HttpRequest req = new HttpRequest();
req.setEndpoint('callout:TestJWTCredential/services/oauth2/userinfo');
req.setMethod('GET');
req.setHeader('Authorization', 'Bearer'+ UserInfo.getSessionId());
Http http = new Http();
System.debug('REQUEST :::: ' + req);
HTTPResponse resp = http.send(req);
System.debug('RESPONSE :::: ' + resp.getBody());
Can any body help me how to do it.
I was just viewing some Salesforce videos on this topic. In the "Deep Dive into Salesforce Connected App - Part 3" video, at the 23:56 mark, the Salesforce presenter had to delete the "scope" value to get it to work. https://youtu.be/wN8d4vwSA-E?t=1436
My current use case is: I have a frontend application where a user is logged in via Keycloak. I would like to implement some parts of the Ditto HTTP API in this frontend (https://www.eclipse.org/ditto/http-api-doc.html).
For example I want to create policies (https://www.eclipse.org/ditto/basic-policy.html) for authorization. I've read in the documentation that one can use an OpenID Connect compliant provider and the form is : (https://www.eclipse.org/ditto/basic-policy.html#who-can-be-addressed).
There's basic auth example at the bottom of the page, it seems to use the username in this case.
{
"policyId": "my.namespace:policy-a",
"entries": {
"owner": {
"subjects": {
"nginx:ditto": {
"type": "nginx basic auth user"
}
},
...
}
My question is: What exactly would be the sub-claim if I want to use Keycloak? Is it also the username of the user I want to grant rights to? And how would I get this in my frontend where I want to specify the policy for sending it to Ditto afterwards?
UPDATE 1:
I tried to enable keycloak authentication in Ditto like suggested below and as stated here: https://www.eclipse.org/ditto/installation-operating.html#openid-connect
Because I'm running Ditto with Docker Compose, I added the following line as an environment variable in ditto/deployment/docker/docker-compose.yml in line 136: - Dditto.gateway.authentication.oauth.openid-connect-issuers.keycloak=http://localhost:8090/auth/realms/twin
This URL is the same as in the issuer claim of my token which I'm receiving from keycloak.
Now if I try to make for example a post request with Postman to {{basePath}}/things I get the following error:
<html>
<head>
<title>401 Authorization Required</title>
</head>
<body bgcolor="white">
<center>
<h1>401 Authorization Required</h1>
</center>
<hr>
<center>nginx/1.13.12</center>
</body>
</html>
I chose Bearer Token as Auth in Postman and pasted a fresh token. Basic Auth with the default ditto user is still working.
Do I have to specify the new subject/my user in Ditto before?
UPDATE 2:
I managed to turn basic auth in nginx off by commenting out "auth_basic" and "auth_basic_user_file" in nginx.conf!
It seems to be forwarded to Ditto now, because now I get the following error with Postman:
{
"status": 401,
"error": "gateway:jwt.issuer.notsupported",
"message": "The JWT issuer 'localhost:8090/auth/realms/twin' is not supported.",
"description": "Check if your JWT is correct."
}
UPDATE 3:
My configuration in gateway.conf looks now like this:
oauth {
protocol = "http"
openid-connect-issuers = {
keycloak = "localhost:8090/auth/realms/twin"
}
}
I also tried to add these two lines in the docker-compose.yml:
- Dditto.gateway.authentication.oauth.protocol=http
- Dditto.gateway.authentication.oauth.openid-connect-issuers.keycloak=localhost:8090/auth/realms/twin
Unfortunately I still had no luck, same error as above :/ It seems like an user had a similar problem with keycloak before (https://gitter.im/eclipse/ditto?at=5de3ff186a85195b9edcb1a6), but sadly he mentioned no solution.
EDIT: It turns out that I specified these variables in the wrong way, the correct solution is to add them as part of command: java ... more info here
UPDATE 4:
I tried to build Ditto locally instead of using the latest docker images and I think I might be one step further now, it seems like my oauth config is working. I get now:
{
"status": 503,
"error": "gateway:publickey.provider.unavailable",
"message": "The public key provider is not available.",
"description": "If after retry it is still unavailable, please contact the service team."
}
The error message from the log is:
gateway_1 | 2020-11-05 15:33:18,669 WARN [] o.e.d.s.g.s.a.j.DittoPublicKeyProvider - Got Exception from discovery endpoint <http://localhost:8090/auth/realms/twin/.well-known/openid-configuration>.
gateway_1 | akka.stream.StreamTcpException: Tcp command [Connect(localhost:8090,None,List(),Some(10 seconds),true)] failed because of java.net.ConnectException: Connection refused
gateway_1 | Caused by: java.net.ConnectException: Connection refused
...
gateway_1 | java.util.concurrent.CompletionException: org.eclipse.ditto.services.gateway.security.authentication.jwt.PublicKeyProviderUnavailableException [message='The public key provider is not available.', errorCode=gateway:publickey.provider.unavailable, statusCode=SERVICE_UNAVAILABLE, description='If after retry it is still unavailable, please contact the service team.', href=null, dittoHeaders=ImmutableDittoHeaders [{}]]
...
gateway_1 | Caused by: org.eclipse.ditto.services.gateway.security.authentication.jwt.PublicKeyProviderUnavailableException [message='The public key provider is not available.', errorCode=gateway:publickey.provider.unavailable, statusCode=SERVICE_UNAVAILABLE, description='If after retry it is still unavailable, please contact the service team.', href=null, dittoHeaders=ImmutableDittoHeaders [{}]]
...
gateway_1 | Caused by: akka.stream.StreamTcpException: Tcp command [Connect(localhost:8090,None,List(),Some(10 seconds),true)] failed because of java.net.ConnectException: Connection refused
gateway_1 | Caused by: java.net.ConnectException: Connection refused
My keyloak is definitely running, I'm able to get tokens. If I'm opening http://localhost:8090/auth/realms/twin/.well-known/openid-configuration which is in the first error message, I'm able to see my openid-configuration from keycloak config.
Edit: It seems that my gateway container cannot reach my keycloak container, will try to figure this out.
FINAL UPDATE:
Unreachable keycloak docker container from the gateway docker container was the issue. I'm now using traefik:
Keycloak container has the following alias: keycloak.localhost
Oauth configuration in the gateway looks like this:
oauth {
protocol = "http"
openid-connect-issuers = {
keycloak = "keycloak.localhost/auth/realms/twin"
}
}
Now the gateway can find the keycloak container via the alias and I can still use the keycloak admin ui from my localhoast: http://keycloak.localhost:8090/auth/admin/
Additional info: Traefic Blog
What exactly would be the sub-claim if I want to use Keycloak?
Keycloak provides you a JWT.
A JWT is an encrypted JSON which contains multiple fields called "claims". You can check how your token looks like by visiting https://jwt.io and pasting your token there. One of those fields is called sub. This is the sub claim.
To enable your keycloak authentication in eclipse ditto you need to add the issuer to the ditto configuration.
An example can be founde here.
The address must match the URL in the issuer claim of your JWT token.
ditto.gateway.authentication {
oauth {
protocol = "http"
openid-connect-issuers = {
some-name = "localhost:8090/auth/realms/twin"
}
}
}
Is it also the username of the user I want to grant rights to?
In eclipse ditto there is not really a concept of "user names". Eclipse ditto authentication is based on authorization subjects. For the basic authentication example you provided, the authorization subject which is generated within ditto is nginx:ditto.
For JWT authentication the authorization subject is generated as a combination of the name for the open id connect issuer which you configured (in my case some-name) and the value of the sub claim. An authorization subject could look like this: some-name:8d078113-3ee5-4dbf-8db1-eb1a6cf0fe81.
And how would I get this in my frontend where I want to specify the policy for sending it to Ditto afterwards?
I'm not sure if I understand the question correctly. If you mean how to authenticate your frontend HTTP requests to eclipse ditto, you need to provide the JWT to eclipse ditto by adding it to the authorization header of your HTTP requests in the following form:
authorization: Bearer yourJWT
If you mean how you would know the sub claim of a JWT, you need to parse the JWT to a JSON object and then read the sub claim out of the payload section.
how can I test the Keycloak native services
The documentation presents several services such as: users management, customers, groups and sessions, I have tried in many ways to test these services and without success. Perhaps due to the incorrect configuration
I saw an example on Stackoverflow that showed the correct path for services
Eg.
http://{address-and-port}/auth/admin/realms/{Realm}/users
And some settings on how to test on the postman, but I did not succeed in invoking
does anyone have an example or can help me how to activate / consume these services.
Thanks!
Services to consume: (Keycloak Admin REST API)
https://www.keycloak.org/docs-api/8.0/rest-api/index.html]
I exported you a Postman Collection: https://pastebin.com/Aaf3BUah you can import it into postman.
But I want to point out, how to use the API:
My example uses a running keycloak instance (8.0.2) on
http://localhost:80
with the user admin and the password Pa55w0rd
In consists of 2 requests:
Login:
Login with my admin user and fetch a access-token used in Request 2.
POST http://localhost:80/auth/realms/master/protocol/openid-connect/token
Content-Type:x-www-form-urlencoded
with the following parameters (change username/password)
username:admin
password:Pa55w0rd
grant_type:password
client_id:admin-cli
As a result i will get some data, but important is the access_Token-Bearer:
{
"access_token": "eyJhbGc...JDjfg", //i reduced the string
...
}
Keep in mind, this token is necessary to execute Request2. But it is only valid for 60 seconds, so be fast while testing :-)
Get all Users:
GET http://localhost:80/auth/admin/realms/master/users
Header Authorization: Bearer eyJhbGc...JDjfg
Response:
[
{
"id": "9fec4b6c-3648-425b-a90f-f6dd78f421ab",
"createdTimestamp": 1581017581626,
"username": "admin",
"enabled": true,
"totp": false,
"emailVerified": false,
"disableableCredentialTypes": [],
"requiredActions": [],
"notBefore": 0,
"access": {
"manageGroupMembership": true,
"view": true,
"mapRoles": true,
"impersonate": true,
"manage": true
}
}
]
With this example, you should be able to access different REST API endpoints. But make sure you include a valid access_token in every request you send - otherwise you will just get Not Authorized response
Here is the full Postman Administration Rest API of keycloak
https://documenter.getpostman.com/view/7294517/SzmfZHnd
It is for keycloak 10 (but work for 11 too - tested)
Open it in postman, adjust environment variables with your keycloak host and params.
You will get a full functionnal keycloak admin rest api.
I started to work with keycloak, and here is a setup I want to test.
I want to test this scenario:
It works, but I want to implement role-based access to apps behind Nginx proxy and I can't understand how exactly payload of jwt token generates.
Here is my JWT tokens payload:
"jti": "f5f07b6f-ccae-4f57-a8ea-ae02ebb3cb12",
"exp": 1569263630,
"nbf": 0,
"iat": 1569227630,
"iss": "https://keycloak.domain.local/auth/realms/LDAP_test",
"sub": "fedc6baf-4ba4-4fa6-924c-9501edf070f7",
"typ": "Serialized-ID",
"auth_time": 0,
"session_state": "aa0052ee-b5e1-45cc-bee4-e7bccdfa4a59",
"state_checker": "sC_nvlDXfjUDHhC15ZDpPauX5JkxhvVtYUOn62PhtV8"
I want my token to contain roles, username and email and i run out of ideas how to put it there. Is client somehow related to the content of the token or keycloak always gives everything he have into it?
Here are my Nginx client settings:
server {
server_name demo-a.domain.local;
location / {
proxy_pass http://10.10.10.168/index.html;
access_by_lua '
local opts = {
redirect_uri_path = "/redirect_uri",
accept_none_alg = true,
discovery = "https:/keycloak.domain.local/auth/realms/LDAP_test/.well-known/openid-configuration",
client_id = "nginx-gateway",
client_secret = "19fe43bc-4167-4433-816a-eb96da33f9a3",
redirect_uri_scheme = "https",
logout_path = "/logout",
redirect_after_logout_uri = "https://keycloak.domain.local/auth/realms/LDAP_test/protocol/openid-connect/logout?redirect_uri=https://www.nginx-gateway.domain.local/",
redirect_after_logout_with_id_token_hint = false,
session_contents = {id_token=true}
}
-- call introspect for OAuth 2.0 Bearer Access Token validation
local res, err = require("resty.openidc").authenticate(opts)
if err then
ngx.status = 403
ngx.say(err)
ngx.exit(ngx.HTTP_FORBIDDEN)
end
';
}
Thanks in advance!
Did you configure the client to be openid client? Is it UI or machine client?
To cause your JWT to have roles, one follows usual below flow:
Create client in Keycloak admin-console and configure it to support
open-id-connect.
Add users to Keycloak.
Assign roles to users.
Configure your client to have the client id of Keycloak client.
Exercise browser or machine flow which involves passing of JWT to the
client. JWT will contain the roles as claims.
Still debugging it, but here are a few pointers you will definitely need....
You need to be Authenticating Reverse Proxy with KeyCloak while using the keycloak behind an nginx proxy
Ok, completely forget about this question, but still here is a solution.
Just use a proper oidc proxy like gatekeeper (louketo now) or oauth2-proxy.