Created
November 4, 2016 18:10
-
-
Save renegr/0dbc9b05efc4d7305fd1764770e3059d to your computer and use it in GitHub Desktop.
OpenID Connect Client in Eve
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# OpenID Connect - Client | |
OpenID Connect is a protocol used for authentication and authorization. | |
We are going to implement a reusable "component" to interact with | |
an OpenID Provider. Our OpenID Provider will be Keycloak, therefore | |
many implementation Details are Keycloak specific. | |
Therefore you'll find two parts: | |
- 0. -> Using the OpenID Connect Component | |
- 1. -> Implementation Details for the OpenID Connect Protocol & Keycloak | |
## 0. Usage | |
### 0.1 Configuration | |
We start by adding an configuration record. | |
The implementation (in Section 1.) will do the rest. | |
``` | |
commit | |
[#oidc-configuration base-url: "http://localhost:4100/auth/realms/master" | |
redirect-uri: "http://localhost:8080/#/examples/oidc_client.eve" | |
client-id: "eve" | |
scope: "offline_access openid"] | |
``` | |
As we can see, we are expecting a running Keycloak instance on localhost:4100. | |
### 0.2 Sending & Receiving authorized JSON requests | |
(WIP) Sending an authorized request should be as simple as this: | |
``` | |
search | |
config = [#oidc-configuration current-user] | |
commit @oidc | |
[#authorized-request #fetch-user-info method: "POST" using: config url: "http://localhost:4100/auth/master/some/fancy/request"] | |
``` | |
We expect a **current-user** on our #oidc-configuration record, to send an authorized-request. | |
(WIP) Receiving the result of this request: | |
``` | |
search @oidc | |
[#authorized-request #fetch-user-info response] | |
commit @browser | |
[#div text: "We have now received an authorized result and can display the response"] | |
``` | |
### 0.3 Rendering the status | |
(WIP) Showing some user Details. | |
``` | |
search @session | |
session = [#oidc-configuration current-user] | |
bind @browser | |
[#div text: "The current user {{session}} is logged in."] | |
``` | |
(Debug) Show infos about the available access_token & refresh tokens | |
``` | |
search | |
[#oidc-configuration tokens: [access_token refresh_token]] | |
bind @browser | |
[#div text: "The Access Token is {{access_token}}"] | |
``` | |
The following block will show the Login link. Only available, when not logged in: | |
``` | |
search @session | |
not([#oidc-configuration current-user]) | |
[#oidc-configuration domain: [login-url]] | |
bind @browser | |
[#a href: "{{login-url}}" text: "Click here to login"] | |
``` | |
## 1. Keycloak OIDC Implementation Details | |
These are the implementation details for a proper OpenID Connect client, like ours: | |
### 1.1 Autocomplete a #oidc-configuration | |
For the time being, we will configure the login-url. | |
```eve | |
search | |
config = [#oidc-configuration base-url client-id redirect-uri scope state] | |
not(config.domain) | |
redirect-uri-encoded = urlencode[text: "{{redirect-uri}}"] | |
bind | |
config <- [domain: [login-url: "{{config.base-url}}/protocol/openid-connect/auth?response_type=code&client_id={{config.client-id}}&scope={{scope}}&state={{state}}&redirect_uri={{redirect-uri-encoded}}"]] | |
``` | |
### 1.2 Set or Restore the "STATE" | |
The state is a random hash-value, that will be used in the initial handshake between client and provider. | |
The first step in the handshake, will redirect the browser to the OpenID Provider - thus leaving | |
our application. Therefore we have to store our state in a way, we can retrieve later, when our browser | |
points to our application again (e.g.: Cookies, LocalStorage). | |
At the moment, we lack this feature in **Eve** (afaik), so we will fake it, and use some constant for our state: | |
Setting the store | |
``` | |
search | |
config = [#oidc-configuration] | |
not(config.state) | |
bind | |
config <- [state: "SOMERANDOMSTATE"] | |
``` | |
Restoring the store | |
**WIP** As mentioned above, we should try to restore our state from local cache, when the OpenID Provider | |
returns to our application successfully. | |
### 1.4 Reacting to the OIDC Handshake | |
The OpenID Provider returned to our application, but added two Query parameters: **code** and **state**. | |
**state** needs to match our **state** (the one we have set - or restored - in 1.2). | |
When we have a match, then it we can request our actual **Tokens** (access_token, refresh_token), that | |
we can use to send authorized requests to some API (like the one of keycloak, or any other secured API that | |
uses the same Keycloak instance for authentication). | |
To do so, we send the **code** to some API endpoint, asking kindly for the tokens: | |
```eve | |
search @event @session | |
qstate = if [#url-change query-param: [key:"state" value] ] then value | |
qcode = if [#url-change query-param: [key:"code" value] ] then value | |
oidc-config = [#oidc-configuration state base-url client-id redirect-uri] | |
commit @http | |
[#request #oidc-token method: "POST" url: "{{base-url}}/protocol/openid-connect/token" body:"code={{qcode}}&client_id={{client-id}}&redirect_uri={{redirect-uri}}&grant_type=authorization_code" headers: [Content-Type: "application/x-www-form-urlencoded"] oidc-config] | |
``` | |
When keycloak is happy with the request, we can extract the **access_token** and **refresh_token** from | |
the response and store it in our #oidc-configuration: | |
**(WIP)**: To finalize this step, we need to extract the information about the currently signed in user. | |
For that we have to parse the JSON Web Token (access_token, id_token, refresh_token). -> Missing Feature in Eve. | |
``` | |
search @http @session | |
[#request #oidc-token response: [json] oidc-config] | |
lookup[record: json, value:[access_token expires_in refresh_token id_token token_type]] | |
commit | |
oidc-config <- [tokens: [access_token expires_in refresh_token]] | |
``` | |
## Todos | |
This example needs some more tweaks to work like a proper "Keycloak client". Here is a list of missing parts: | |
- create a random string for **state** > missing String function in Eve | |
- setting the current-user (by decoding jwt, and extracting the information) > missing JWT parsing function in Eve | |
- Implement the #authorized-request functionality > I guess Eve provides all features, to implement this. This is a two-step request: (a) refresh the access_token - when needed (b) send the actual request with the new (or old) access_token | |
- When keycloak redirects to our application, we no longer have **oidc_client.eve** loaded in the IDE, instead we have "Eve Quick Start Tutorial" -> ATM you have to navigate to the oidc_client.eve manually. Might be a keycloak problem? Stripping of the hash in the location? Needs some more investigation. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment