feat: support OIDC id_token

- generate JWT id_token in token exchange
- store optional nonce in authorization object
- switch to RS256 algorithm for JWT signature
- add JWKs endpoint to provide OIDC clients with public keys
This commit is contained in:
Matthieu Bessat 2024-12-09 09:38:39 +01:00
parent 4763915812
commit 02e16a7e74
32 changed files with 469 additions and 103 deletions

View file

@ -0,0 +1,58 @@
signing_key = "tmp/secrets/signing.key"
[instance]
base_uri = "http://localhost:8086"
name = "Example org"
logo_uri = "https://example.org/logo.png"
[[applications]]
slug = "demo_app"
name = "Demo app"
description = "A super application where you can do everything you want."
client_id = "00000001-0000-0000-0000-000000000001"
client_secret = "dummy_client_secret"
login_uri = "https://localhost:9876"
allowed_redirect_uris = [
"http://localhost:9090/callback",
"http://localhost:9876/callback"
]
visibility = "Internal"
authorize_flow = "Implicit"
[[applications]]
slug = "wiki"
name = "Wiki app"
description = "The knowledge base of the exemple org."
client_id = "f9de1885-448d-44bb-8c48-7e985486a8c6"
client_secret = "49c6c16a-0a8a-4981-a60d-5cb96582cc1a"
login_uri = "https://wiki.example.org/login"
allowed_redirect_uris = [
"https://wiki.example.org/oauth2/callback"
]
visibility = "Public"
authorize_flow = "Implicit"
[[applications]]
slug = "private_app"
name = "Demo app"
description = "Private app you should never discover"
client_id = "c8a08783-2342-4ce3-a3cb-9dc89b6bdf"
client_secret = "this_is_the_secret"
login_uri = "https://private-app.org"
allowed_redirect_uris = [
"http://localhost:9091/authorize",
]
visibility = "Private"
authorize_flow = "Implicit"
[[roles]]
slug = "basic"
name = "Basic"
description = "Basic user"
default = true
[[roles]]
slug = "admin"
name = "Administrator"
description = "Full power on organization instance"

View file

@ -0,0 +1,11 @@
#!/usr/bin/bash
password_hash="$(echo -n "root" | argon2 salt_06cGGWYDJCZ -e)"
echo $password_hash
SQL=$(cat <<EOF
INSERT INTO users
(id, handle, email, roles, status, password_hash, created_at)
VALUES
('$(uuid)', 'john.doe', 'john.doe@example.org', '[]', 'Active', '$password_hash', '2024-11-30T00:00:00Z');
EOF)
echo $SQL | sqlite3 $DB_PATH

View file

@ -0,0 +1,41 @@
POST {{ base_url }}/login
[FormParams]
login: john.doe
password: root
HTTP 303
[Captures]
user_jwt: cookie "minauthator_jwt"
# OAuth2 implicit flow (pre-granted app)
GET {{ base_url }}/authorize
[QueryStringParams]
client_id: 00000001-0000-0000-0000-000000000001
response_type: code
redirect_uri: http://localhost:9090/callback
state: Afk4kf6pbZkms78jM
scope: openid profile email
HTTP 302
[Captures]
authorization_code: header "Location" regex "\\?code=(.*)&"
# OIDC Token exchange
POST {{ base_url }}/api/token
[BasicAuth]
00000001-0000-0000-0000-000000000001: dummy_client_secret
[FormParams]
code: {{ authorization_code }}
scope: user_read_basic
redirect_uri: http://localhost:9090/callback
grant_type: authorization_code
HTTP 200
Content-Type: application/json
[Asserts]
jsonpath "$.access_token" exists
jsonpath "$.id_token" exists
jsonpath "$.id_token" matches "eyJ[[:alpha:]0-9].[[:alpha:]0-9].[[:alpha:]0-9]"
[Captures]
id_token: jsonpath "$.id_token"
# TODO: assert id_token JWT claims fields
# TODO: contribute to hurl to add JWT extraction and assertion
# See. https://github.com/Orange-OpenSource/hurl/issues/2223

View file

@ -1,3 +1,5 @@
signing_key = "tmp/secrets/signing.key"
[instance]
base_uri = "http://localhost:8086"
name = "Example org"

View file

@ -27,7 +27,7 @@ handle: root
email: root@johndoe.net
full_name: John Doe
website: https://johndoe.net
picture: file,john_doe_profile_pic.jpg; image/jpeg
avatar: file,john_doe_profile_pic.jpg; image/jpeg
HTTP 200
GET {{ base_url }}/me/authorizations

View file

@ -1,3 +1,4 @@
signing_key = "tmp/secrets/signing.key"
applications = []
roles = []