I have a running jupyterhub service and I want to interact with the REST API with admin privileges.
The docs suggest I can get a authorisation token like this, where username is an admin user:
$ jupyterhub token --config=<path-to-config> <username>
f9ed5a19d62d4285bbebe2ded9028baf
However, if I use this token in a request to the API it fails:
>>> t1 = 'f9ed5a19d62d4285bbebe2ded9028baf'
>>> requests.get('http://myjupyterhub/hub/api/users', headers={'Authorization': 'token {}'.format(t1)})
>>> <Response [403]>
I can get a token if I have the user's password but this is inconvenient in my scenario:
>>> r = requests.post('http://myjupyterhub/hub/api/authorizations/token', json={'username': 'myadmin', 'password': myadminpass})
>>> t2 = r.json()['Authentication']
>>> requests.get('http://myjupyterhub/hub/api/users', headers={'Authorization': 'token {}'.format(t2)})
>>> <Response [200]>
Have I misunderstood how jupyterhub token works?
Related
I'm following through this link: https://developers.google.com/identity/protocols/oauth2/service-account#httprest_1 in order to have my flutter app log to a log bucket in a google cloud project. Currently getting a
{
"error": "invalid_client",
"error_description": "The OAuth client was not found."
}
when I run the code below to get the access token in dart:
var jsonFile =
await File(jsonPath).readAsString();
var map = jsonDecode(jsonFile);
final jwt = JWT(
{
'iss': map['client_email'],
'sub': map['client_email'],
'aud': map['token_uri'],
'iat': (DateTime.now().millisecondsSinceEpoch / 1000).floor(),
'exp':
(DateTime.now().add(Duration(hours: 1)).millisecondsSinceEpoch / 1000)
.floor(),
},
issuer: map['private_key_id'],
);
final token = jwt.sign(SecretKey(map['private_key']));
print(token);
final accessToken = await http.post(
Uri.parse(map['token_uri']),
headers: {
HttpHeaders.contentTypeHeader: 'application/x-www-form-urlencoded',
},
body: {
'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'assertion': token,
},
);
The JSON file is the credentials of a service account with logging admin role in the GCP project.
Invalid client means that the client id or the client secret that you are using are not valid.
As per the official documentation,
When attempting to get an access or refresh token, you will get an
"Invalid client" error if you provide an incorrect OAuth 2.0 Client
Secret. Make sure the client_secret value you're using in access and
refresh token calls is the one for the OAuth 2.0 Client ID being used,
as found in your GCP Credentials page.
Also refer to this SO link Github link for more information.
I used Spring Cloud Gateway 2021.0.2 and Spring Boot 2.6.6: gateway 3.1.2, session 2021.1, security 5.8 . My user resource is web, and I use gateway as an Oauth 2.0 client. This scheme actively uses the redirect mechanism. And it work great.
1. GET HTTP:// ho299:8080/login or http://ho299:9000/users
2. GET http://ho299:9000/oauth2/authorization/keycloak
3. POST http://kcloak:8080/realms/crm-test/protocol/openid-connect/auth?response_type=code&client_id=crm-app&scope=roles&state=0QkhBXSVB- tlInqCXWUv2BnFodaWuqrABeiwmsRtPyk=&redirect_uri=http://ho299:9000/login/oauth2/code/keycloak
4. Login Form : Enter login and password
5. POST http://kcloak:8080/realms/crm-test/login-actions/authenticate?session_code=6wdxHqaU22101_3u2HnmmUyyzcP_nKSuTBeFXpu7G54&execution=a85ae60c-65af-460a-b7b2-720e3608ff52&client_id=crm-app&tab_id=GvMx7LSBHdQ
6. POST /realms/crm-test/protocol/openid-connect/token
grant_type=authorization_code&code=0b3b268f-1567-4c6c-b91c-b0f866c8fcd7.da32c5a8-79d3-4b1b-8e9a-3aa35b44ff8b.504aaa05-a6e6-490b-8d83-ff00752f4e4f&redirect_uri=http%3A%2F%2Fho299%3A9000%2Flogin%2Foauth2%2Fcode%2Fkeycloak
7. Keep mapping session id = access token receiving by step 5
8. GET http://ho299:9000/users Session = Session ID (( Return SESSION=17c6eac9-c193-476f-bb58-f0dec3ba642c; Path=/; HttpOnly; SameSite=Lax))
9. GET http://ho299:9000/users Session = 17c6eac9-c193-476f-bb58-f0dec3ba642c
10. GET HTTP:// ho11:8181/users Bearer AccessToken
My gateway application.yml :
spring:
security:
oauth2:
client:
provider:
keycloak:
issuer-uri: ${KEYCLOAK_URL:http://kcloak:8080}/realms/crm-test
authorization-uri: http://kcloak:8080/realms/crm-test/protocol/openid-connect/auth
registration:
keycloak:
provider: keycloak
client-id: crm-app
client-secret: J9fHivY3GtfVbfc1Y6dnznVCu7IChpGU
scope:
- roles
cloud:
gateway:
default-filters:
- TokenRelay
- SaveSession
globalcors:
corsConfigurations:
'[/**]':
allowedOrigins: "*"
allowedMethods: "*"
allowedHeaders: "*"
routes:
- id: book-route
uri: ${BOOK_SERVICE_URL:http://ho299:9002}
predicates:
- Path=/users/**
However, for mobile API this scheme does not work for me. How to setup gateway auth2 authentification as follows(through 'grant_type=password')?
1) curl --location --request POST 'http://ho299:8080/login' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=crm-app' \
--data-urlencode 'username=so1' \
--data-urlencode 'password=so1' \
--data-urlencode 'grant_type=password'
2) Redirect to Keycloak. It authenticate cridentials.
3) Keycloak return access token and Gateway save it to session mapping
4) Returning session ID issuering by Gateway
5) Make request to resource /users adding Session Id
6) Downstream request to resource service with adding access token
I'm setting up Keycloak as an authentication server https://github.com/keycloak/keycloak/releases/download/12.0.0/keycloak-12.0.0.zip
Java 11
Documentation: https://github.com/keycloak/keycloak-documentation/blob/master/securing_apps/topics/oidc/oidc-generic.adoc
I can generate the access_token via /realms/{realm-name}/protocol/openid-connect/token
but I cannot call the userinfo endpoint /realms/{realm-name}/protocol/openid-connect/userinfo using a valid access_token which I get from the first API.
POST http://127.0.0.1:8080/auth/realms/test/protocol/openid-connect/token
{
client_secret: ...,
grant_type: ...,
client_id: ...,
}
response
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIxOE..."
"expires_in": 3600,
"refresh_expires_in": 0,
"token_type": "Bearer",
"not-before-policy": 0,
"scope": "create"
}
But here is the result when I call the get user info API
GET http://127.0.0.1:8080/auth/realms/test/protocol/openid-connect/userinfo
Header: Bearer ${access_token}
Are there any suggestions?
Thank you
Post man test
Keycloak server's log is same
Keycloak bug
I think this is an issue on KC 12.0
When I use KC 11.0.3, above APIs work fine
https://github.com/keycloak/keycloak-community/issues/224
The Jira story:
https://issues.redhat.com/browse/KEYCLOAK-17217
Make sure you are calling the endpoint as follows.
First getting the token:
curl -d "client_id=$YOUR_CLIENT_ID" \
-d "client_secret=$YOUR_CLIENT_SECRET" \
-d "grant_type=client_credentials" \
http://127.0.0.1:8080/auth/realms/test/protocol/openid-connect/token)
Extract from the JSON response the access_token field (e.g., jq -r .access_token)
Then call the userinfo as follows:
curl -X GET http://127.0.0.1:8080/auth/realms/test/protocol/openid-connect/userinfo \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $ACCESS_TOKEN"
With Postman:
For a setup with Realm Name = "test", client_id = "test", client_secret = "63b61af0-5a99-41d7-8f9b-4e3059b8b9ab" and using client_credentials grant_type.
Getting the token:
and getting the userinfo:
EDIT
The approach below works with Keycloak 10.0.x, and 11.0.x, but gets exactly the same issues as OP's for the version Keycloak 12.0.x (including the latest release Keycloak 12.0.2).
This seams to be regression added with Keycloak 12.0.0 follow this issue for update information.
Introduction:
Hello everyone, I'm trying to use the REST API of Airflow to active a DAG with external trigger, like:
POST: http://{{url}}:{{port}}/api/experimental/dags/MY_DAG_ID/dag_runs
headers = {
'Content-Type': 'application/json',
'Cache-Control': 'no-cache',
}
Problem:
It's work very well (Answer: Status 200), but I need some security because its not can open for public, so I read on API Authentication, that I can be set auth_backend on airflow.cfg that will worked very similar like Password Authentication used for the Web Interface.
[api]
auth_backend = airflow.contrib.auth.backends.password_auth
But now, the Answer is (401 - Unauthorized) and I don't know how to configure the REST API to use my external trigger with this security.
Is it necessary to pass my user and password on header to work?
How I can do this?
Let's assume that exist a user: admin, pass: admin and permission: Admin
Links:
https://airflow.apache.org/docs/stable/api.html#authentication
You have to pass an authorization header with a base 64 encoded header with the string user:pass
You can check how it happens here: https://github.com/apache/airflow/blob/029c84e5527b6db6bdbdbe026f455da325bedef3/airflow/contrib/auth/backends/password_auth.py#L205
header = request.headers.get("Authorization")
if header:
userpass = ''.join(header.split()[1:])
username, password = base64.b64decode(userpass).decode("utf-8").split(":", 1)
Example usage:
https://github.com/apache/airflow/blob/7cba83333c5227ce37967c65d189a5e994898c68/tests/www/api/experimental/test_password_endpoints.py
response = c.post(
url_template.format('example_bash_operator'),
data=json.dumps(dict(run_id='my_run' + datetime.now().isoformat())),
content_type="application/json",
headers={'Authorization': 'Basic aGVsbG86d29ybGQ='} # hello:world
)
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.