Reading through vaults documentation for ldap auth method, I am able to successfully login via a postman API call to the vault server.
ldap is currently configured with default-lease of 3600s(1hr) and max-lease 86400(s). In postman calling, I provide password and ttl KVs. however the response, while successful, still comes back with the default 1hr lease for my token.
{
"password": "mypassword",
"lease_duration": "5"
}
Related
I have an application which consists of a frontend and several backend services. The authentication is done via Keycloak.
The workflow looks like this:
The user logs into the frontend and gets a token from Keycloak. This token is sent to the backend with every request.
The following image explains the current architecture:
In Keycloak I have the following clients:
1. Frontend
Access Type: public
Client Protocol: openid-connect
2. Core Service
Access Type: bearer-only
Client Protocol: openid-connect
3. User Service
Access Type: bearer-only
Client Protocol: openid-connect
How can I validate calls between services now?
I would imagine something like a service account and these have the possibility to call each other independently from the bearer-token from the frontend. The problem is that both services can be called from the frontend as well as between each other.
Edit:
My API is written with NestJS.
The API of the user-service:
And this is how I call the user-service in my core-service:
and this is my keycloak configuration for the the user-service:
At the moment I don't add anything to the request and I don't have any extra configuration on the interface. So I added the #Resource('user-service')-Annotation to the Controller and the #Scope()-Annotation to the Endpoint.
After that I don't get an error immediately and the endpoint is called.I can log that the logic is executed. But as response I still get a 401 Unauthorized Error.
Do I need to specify a scope or what do I need to add in the #Resource-Annotation?
Edit 2:
I'll try to show you my current situation with many screenshots.
Initial situation
Here is your drawing again. For me, points 1-5 work and point 8 works even if I do not call another service.
My Configuration
That this works, I have the following configuration:
Just Frontend and Core Service
Frontend:
Core-Service:
For the core service (gutachten-backend), I do not need to make any further configurations for this. I also have 2 different roles and I can specify them within the API.
Using Postman I send a request to the API and get the token from http://KEYCLOAK-SERVER_URL/auth/realms/REALM_NAME/protocol/openid-connect/token.
These are my 2 testing methods. I call the first one and it works. The following is logged. Means the token is validated received and I get Access:
Calling the user service
Now I call the second method. This method calls the user-service.
This is my request in the core-service:
I do not add anything else to my request. Like a bearer token in the header.
The endpoint in the user service is just a test method which logs a message.
This is my configuration for the user service:
I have now tried something with resources, policies and permissions.
Resource
Policies
Role-Policy
Client-Policy:
Permission
And analogously the client permission
Questions and thoughts
All steps from the first drawing seem to work except 6 and 7
Do I need to add more information to my request from core service to user service?
How to deal with root url and resource urls?
In the code in the API, do I need to additionally configure the endpoints and specify the specific resources and policies? (NestJS offers the possibility to provide controllers with a #Resource('<name>') and endpoints with #Scopes([<list>]))
Additionally, through a tutorial on setting up keyacloak in NestJS, I turned on the following config:
This adds a global level resource guard, which is permissive.
Only controllers annotated with #Resource and
methods with #Scopes are handled by this guard.
Keycloak's Token Verification API can do it.
This is one of Architecture for Authorization of resource access permission.
Between Core Service and User Service, Core Service needs to verify the access-token to Keycloak.
It means this token can access the User service API Yes(Allow) or No(Deny)
This is API format
curl -X POST \
http://${host}:${port}/realms/${realm}/protocol/openid-connect/token \
-H "Authorization: Bearer ${access_token}" \
--data "grant_type=urn:ietf:params:oauth:grant-type:uma-ticket" \
--data "audience={resource_server_client_id}" \
--data "permission=Resource A#Scope A" \
--data "permission=Resource B#Scope B"
Demo Keycloak Token URL: localhost:8180
Authorization Enabled Realm: test
Authorization Enabled Client: core-service
Client Resource: resource:user-service
User1 : can access it (ALLOW) password: 1234
User2 : can access it (ALLOW) password:1234
Steps
Get User Access Token(instead of login) ->
Preparations
ready to assign access-token(named user-token) variable in Postman
var jsonData = JSON.parse(responseBody);
postman.setEnvironmentVariable("user-token", jsonData.access_token);
Get Token URL from Keycloak UI, click the Endpoints
Get User1's access token
with Bearer Token option with {{user-token}} in Authorization Tab
Verify with user1 token from Core Service to Keycloak
return 200 OK from Keycloak (ALLOW) - it is Circle 4 and 5 in my Architecture.
So Core Service forward API call to User Service for accessing service
Note - needs to finish Keycloak Permission setting
Verify with user2 token from Core Service to Keycloak
return 200 OK from Keycloak (Allow) too.
So Core Service return an error to Front-end, like this user can't access a resource of User Service.
More detail information is in here
Keycloak Permission setting
Create Client
Create Client Resource
Add Client Role
Add Client Policy
Add Permission
All user mapping into Client role
This is Configuration in Keycloak
Create Client
Create Client Resource
Add Client Role
Add Client Policy - role based
Add Permission
All user mapping into Client role - any user if you want to add to access the resource.
For people who have the same problem in the future. The answer from #BenchVue helped a lot to understand the concept in general.
What was missing is that a token must also be added for each request between services. Namely the token of the client.
So before the request is sent, the following query takes place. This is the method to get the token for a client:
getAccessToken(): Observable<string> {
const header = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
};
return this.httpService.post(
'{{keycloakurl}}/auth/realms/{{realm}}/protocol/openid-connect/token',
`grant_type=client_credentials&client_id={{clientId}}&client_secret={{clientSecret}}`,
header).pipe(
map((response) => {
return response.data.access_token as string;
}
));
}
i am new to keycloak.
I have made web portal that authentication (login, logout,forgot password) of users is done in backend ( PHP ) using REST Api. After successful authentication user is allowed to enter secure part of portal.
I am having trouble to get REST API endpoint so that when user is logged in i would like to get a list of permissions that this user have so i can render the UI with functions that specific user have permissions to. So far i found endpoint which can ask for specific permission only
curl -X POST http://$URL/auth/realms/argo/protocol/openid-connect/token -H "Authorization: Bearer $TOKEN" --data "audience=$CLIENTID" --data "permission=$PERMISSIONNAME#$PERMISSIONSCOPE"
Is this possible with keycloak ? I would have maybe around 10 navigation functions and some will be payable so once user buys this function we will allow this permission to this specific user.
Thanks
I spent a lot of time to make it work.
Basically, once the user is logged in (via a JWT access token) your app has to issue an additional call to an OIDC endpoint, in order to get an extended JWT token (including fine grained permissions).
Here are the details of this extra call:
POST http://server:port/auth/realms/<realm>/protocol/openid-connect/token
Content-Type: application/x-www-form-urlencoded
Authorization: "Bearer ....." (=access token of logged-in user)
Parameters:
- grant_type: the constant "urn:ietf:params:oauth:grant-type:uma-ticket"
- audience : the keycloak client id
- response_include_resource_name: true
You will get in response a JWT token that should be decoded
either programatically (quite easy)
or by invoking Keycloak token introspection endpoint (ie /auth/realms//protocol/openid-connect/token/introspect
And, once decoded, you will notice that the json payload contains an extra "authorization" node.
I'm unable to authenticate / sign-in via AzureAD when running testCafe.
const testrole = Role(
'https://login.microsoftonline.com/',
async t => {
await t
.typeText(Selector('input').withAttribute('type', 'email'), *******)
.click(Selector('#idSIButton9'))
.typeText(Selector('input').withAttribute('type', 'password'), ********)
.click(Selector('#idSIButton9'));
},
{ preserveUrl: true }
);
The above steps work fine, however after entering the password I get a message saying:
"Unable to sign in to Outlook account, Error: AADSTS900561: The endpoint only accepts POST requests. Received a GET request."
From my initial search, it seems like something to do with 3rd party cookies on the browser. However, I'm unable to find a solution at this time.
Any idea how I get around this issue?
The Azure AD product team has always reminded me that it is a bad idea to try to automate sign in like that.
They will probably detect that you are a bot and start blocking your requests, even if you succeed.
Instead, to acquire access tokens you need to use either the client credentials flow (for app-only tokens) or the resource owner password credentials flow (for delegated user tokens).
Client credentials flow: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
ROPC flow: https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc
You have to take good care to secure the credentials used for testing.
And use a test tenant if possible.
We are using App Service Authentication to protect a web API and using Google as authentication provider. It works as expected when we fire a request from a browser (when the session information is in the cookie)
IIS log:
2016-05-29T13:51:19 PID[3600] Verbose Received request: GET
https://XXXXXX.azurewebsites.net/api/user 2016-05-29T13:51:19
PID[3600] Verbose Found 'AppServiceAuthSession' cookie for site
'XXXXXX.azurewebsites.net'. Length: 728. 2016-05-29T13:51:19
PID[3600] Verbose Authenticated XXXXXX#gmail.com successfully
using 'Session Cookie' authentication.
But when we use API testing tool such as Postman and set the Authorization header with bearer token, it always results in redirection.
IIS log:
2016-05-29T13:53:38 PID[3600] Verbose Received request: POST
https://XXXXX.azurewebsites.net/api/user 2016-05-29T13:53:38
PID[3600] Information Redirecting:
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=XXXXXXX-XXXXX7attpunn9smo4.apps.googleusercontent.com&redirect_uri=https%3A%2F%2FXXXXXX.azurewebsites.net%2F.auth%2Flogin%2Fgoogle%2Fcallback&scope=openid+profile+email&state=nonce%3De5f4aabe11cb4544bf18d00920940d47_20160529135838%26redir%3D%2Fapi%2Fuser
We also tried to set X-ZUMO-AUTH header with the same bearer token, we see error as the token is not in expected format. Apparently it expects encoded JWT token.
IIS log:
016-05-29T13:51:52 PID[3600] Verbose Received request: POST
https://XXXXXX.azurewebsites.net/api/user 2016-05-29T13:51:52
PID[3600] Warning JWT validation failed: IDX10708:
'System.IdentityModel.Tokens.JwtSecurityTokenHandler' cannot read this
string: 'Bearer
ya29.XXXXXXXXXX_RDrX_zsuvMx49e_9QS5ECz9F1yhDHe5j4H9gRN6opkjLXvN1IJZjHXa_Q'.
The string needs to be in compact JSON format, which is of the form:
'..'.. 2016-05-29T13:51:52 PID[3600]
Information Redirecting:
https://accounts.google.com/o/oauth2/v2/auth?response_type=code&client_id=XXXXXXX-k5nj6dkf987attpunn9smo4.apps.googleusercontent.com&redirect_uri=https%3A%2F%2FXXXXXX.azurewebsites.net%2F.auth%2Flogin%2Fgoogle%2Fcallback&scope=openid+profile+email&state=nonce%3De15b0915406142378XXXXX_20160529135652%26redir%3D%2Fapi%2Fuser
Note:
Bearer token obtained from Google is valid as we can verify the detail by making call to
https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=[token]
Please suggest.
The Google token you're using is an access token, not a bearer token. It can be used to access Google resources but cannot be used to authenticate with your Web API.
I wasn't able to find good documentation on this, but I can tell you it works here instead:
In your client app, you must obtain an id_token and an authorization code from Google. You normally get this when the user logs in using the Google OpenID Connect login. I assume you already know how to do this since you already know how to get the access token.
Send a POST request to https://{hostname}/.auth/login/google with a JSON payload that looks like {"authorization_code":"<code>", "id_token":"<id_token>"}.
A successful login response will contain a JSON payload that contains an authenticationToken field. Cache this token.
You can use the authentication token from #3 to make authenticated calls to your web API. Put it in the x-zumo-auth HTTP request header.
Turn on Authentication / Authorization from App Service Portal
Browse to the web app or API that requires authentication, you will be redirected to google login page, when you authenticate successfully, the response will contain:
"id_token": this token can be extracted from the response, or by accessing the Token Store /.auth/me
"redirect_uri" this token will be included in the response body, also you can just set it statically in the following step since this is the callback URL and it shouldn't change unless you change it from the google console
POST a request to https://{hostname}/.auth/login/google with the following JSON payload, {"redirect_uri":"", "id_token":""}. a successful response will contain "authenticationToken" store this token or cache it
Subsequent requests to the APIs that requires authentication should contain an HTTP request header:
"x-zumo-auth" with the value of "authenitcationToken"
Bonus:
In order to verify your token you can POST to https://{hostname}/.auth/login/google with the following JSON pay load {"id_token":""}, the response should specify if the token is valid or not
I implemented the client Side of OpenIDConnect authentication/provisioning/federation for few OAuth2-OpenIdConnect providers. But I fail to get Google OpenID People https://developers.google.com/+/api/openidconnect/getOpenIdConnect working.
I have no problem with the 1st part of OpenID Authentication/Authorization and get the Identity token from JSONWEBtoken without trouble. Nevertheless I fail to access the $identityApiUrl. The odd thing is that the old google's userinfo API works!!! Only the new one fails with an authorization error.
For PeopleAPI I used a Bearer token reusing the access_token, I got with my authorization request. Exactly like I do with the old API.
Here after a short extract from my code with the URL and scopes I used, as well as the error, I get when replaying manually with a curl the request.
Questions:
Is there a special authentication method for OpenIdConnect People API ?
Do I need to request special authorization in the application console ?
Extract from code with API's URL
// main IDP configuration URLs
protected $openidconnect = true; // Google supports OpenID-Connect
protected $authTokenUrl = 'https://accounts.google.com/o/oauth2/auth';
protected $accessTokenUrl= 'https://www.googleapis.com/oauth2/v3/token';
// I fail to get Google People OpenIdConnect API to work :(
//protected $identityApiUrl= 'https://www.googleapis.com/plus/v1/people/me/OpenIdConnect';
protected $identityApiUrl= 'https://www.googleapis.com/oauth2/v1/userinfo';
// OAuth2 action-1: getAuthUrl($state) build authorization token url
protected $scopes = ['openid','email','profile']; // request authentication & email
The error code, when replaying the request with curl
[apache#vz-bzh GeoToBe]$ curl -X GET -H "Authorization: Bearer ya29.5ABSl_75eP_zYFho_E-wVjPlZJc1XfY398HZqJjMxvRxBEWteLKZwNeh2v0BPwWuoH1iLpESeBQvFw" https://www.googleapis.com/plus/v1/people/me/openIdConnect
{
"error": {
"errors": [
{
"domain": "usageLimits",
"reason": "accessNotConfigured",
"message": "Access Not Configured. The API is not enabled for your project, or there is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your configuration.",
"extendedHelp": "https://console.developers.google.com"
}
],
"code": 403,
"message": "Access Not Configured. The API is not enabled for your project, or there is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your configuration."
}
}
you need to enable the "Google+ API" under APIs & auth in the Google API console.