Skip to content

Repository files navigation

What is Kong OIDC plugin

Join the chat at https://gitter.im/nokia/kong-oidc

Continuous Integration:Build StatusCoverage Status

kong-oidc is a plugin for Kong implementing the OpenID Connect Relying Party (RP) functionality.

It authenticates users against an OpenID Connect Provider using OpenID Connect Discovery and the Basic Client Profile (i.e. the Authorization Code flow).

It maintains sessions for authenticated users by leveraging lua-resty-openidc thus offering a configurable choice between storing the session state in a client-side browser cookie or use in of the server-side storage mechanisms shared-memory|memcache|redis.

Note: at the moment, there is an issue using memcached/redis, probably due to session locking: the sessions freeze. Help to debug this is appreciated. I am currently using shared memory to store sessions.

It supports server-wide caching of resolved Discovery documents and validated Access Tokens.

It can be used as a reverse proxy terminating OAuth/OpenID Connect in front of an origin server so that the origin server/services can be protected with the relevant standards without implementing those on the server itself.

The introspection functionality adds capability for already authenticated users and/or applications that already possess access token to go through kong. The actual token verification is then done by Resource Server.

How does it work

The diagram below shows the message exchange between the involved parties.

alt Kong OIDC flow

The X-Userinfo header contains the payload from the Userinfo Endpoint

X-Userinfo: {"preferred_username":"alice","id":"60f65308-3510-40ca-83f0-e9c0151cc680","sub":"60f65308-3510-40ca-83f0-e9c0151cc680"}

The plugin also sets the ngx.ctx.authenticated_credential variable, which can be using in other Kong plugins:

ngx.ctx.authenticated_credential= {
id="60f65308-3510-40ca-83f0-e9c0151cc680", -- sub field from Userinfousername="alice" -- preferred_username from Userinfo
}

For successfully authenticated request, possible (anonymous) consumer identity set by higher priority plugin is cleared as part of setting the credentials.

The plugin will try to retrieve the user's groups from a field in the token (default groups) and set kong.ctx.shared.authenticated_groups so that Kong authorization plugins can make decisions based on the user's group membership.

Dependencies

kong-oidc depends on the following package:

Installation

If you're using luarocks execute the following:

 luarocks install kong-oidc

[Kong >= 0.14] Since KONG_CUSTOM_PLUGINS has been removed, you also need to set the KONG_PLUGINS environment variable to include besides the bundled ones, oidc

 export KONG_PLUGINS=bundled,oidc

Usage

Parameters

ParameterDefaultRequireddescription
nametrueplugin name, has to be oidc
config.client_idtrueOIDC Client ID
config.client_secrettrueOIDC Client secret
config.discoveryhttps://.well-known/openid-configurationfalseOIDC Discovery Endpoint (/.well-known/openid-configuration)
config.scopeopenidfalseOAuth2 Token scope. To use OIDC it has to contains the openid scope
config.ssl_verifyfalsefalseEnable SSL verification to OIDC Provider
config.session_secretfalseAdditional parameter, which is used to encrypt the session cookie. Needs to be random
config.introspection_endpointfalseToken introspection endpoint
config.timeoutfalseOIDC endpoint calls timeout
config.introspection_endpoint_auth_methodclient_secret_basicfalseToken introspection authentication method. resty-openidc supports client_secret_(basic|post)
config.bearer_onlynofalseOnly introspect tokens without redirecting
config.realmkongfalseRealm used in WWW-Authenticate response header
config.logout_path/logoutfalseAbsolute path used to logout from the OIDC RP
config.unauth_actionauthfalseWhat action to take when unauthenticated
- auth to redirect to the login page and attempt (re)authenticatation,
- deny to stop with 401
config.recovery_page_pathfalsePath of a recovery page to redirect the user when error occurs (except 401). To not show any error, you can use '/' to redirect immediately home. The error will be logged server side.
config.ignore_auth_filtersfalseA comma-separated list of endpoints to bypass authentication for
config.redirect_urifalseA relative or absolute URI the OP will redirect to after successful authentication
config.userinfo_header_nameX-UserinfofalseThe name of the HTTP header to use when passing the UserInfo to the upstream server
config.id_token_header_nameX-ID-TokenfalseThe name of the HTTP header to use when passing the ID Token to the upstream server
config.access_token_header_nameX-Access-TokenfalseThe name of the HTTP header to use when passing the Access Token to the upstream server
config.access_token_as_bearernofalseWhether or not the access token should be passed as a Bearer token
config.disable_userinfo_headernofalseDisable passing the Userinfo to the upstream server
config.disable_id_token_headernofalseDisable passing the ID Token to the upstream server
config.disable_access_token_headernofalseDisable passing the Access Token to the upstream server
config.groups_claimgroupsfalseName of the claim in the token to get groups from
config.skip_already_auth_requestsnofalseIgnore requests where credentials have already been set by a higher priority plugin such as basic-auth
config.bearer_jwt_auth_enablenofalseAuthenticate based on JWT (ID) token provided in Authorization (Bearer) header. Checks iss, sub, aud, exp, iat (as in ID token). config.discovery must be defined to discover JWKS
config.bearer_jwt_auth_allowed_audsfalseList of JWT token aud values allowed when validating JWT token in Authorization header. If not provided, uses value from config.client_id
config.bearer_jwt_auth_signing_algs[ 'RS256' ]falseList of allowed signing algorithms for Authorization header JWT token validation. Must match to OIDC provider and resty-openidc supported algorithms
config.header_namesfalseList of custom upstream HTTP headers to be added based on claims. Must have same number of elements as config.header_claims. Example: [ 'x-oidc-email', 'x-oidc-email-verified' ]
config.header_claimsfalseList of claims to be used as source for custom upstream headers. Claims are sourced from Userinfo, ID Token, Bearer JWT, Introspection, depending on auth method. Use only claims containing simple string values. Example: [ 'email', 'email_verified'
config.http_proxyfalsehttp proxy url
config.https_proxyfalsehttps proxy url (only supports url format http://proxy and not https://proxy)

Enabling kong-oidc

To enable the plugin only for one API:

POST /apis/<api_id>/plugins/ HTTP/1.1Host: localhost:8001Content-Type: application/x-www-form-urlencodedCache-Control: no-cachename=oidc&config.client_id=kong-oidc&config.client_secret=29d98bf7-168c-4874-b8e9-9ba5e7382fa0&config.discovery=https%3A%2F%2F<oidc_provider>%2F.well-known%2Fopenid-configuration

To enable the plugin globally:

POST /plugins HTTP/1.1Host: localhost:8001Content-Type: application/x-www-form-urlencodedCache-Control: no-cachename=oidc&config.client_id=kong-oidc&config.client_secret=29d98bf7-168c-4874-b8e9-9ba5e7382fa0&config.discovery=https%3A%2F%2F<oidc_provider>%2F.well-known%2Fopenid-configuration

A successful response:

HTTP/1.1 201 CreatedDate: Tue, 24 Oct 2017 19:37:38 GMTContent-Type: application/json; charset=utf-8Transfer-Encoding: chunkedConnection: keep-aliveAccess-Control-Allow-Origin: *Server: kong/0.11.0
{
"created_at": 1508871239797,
"config": {
"response_type": "code",
"client_id": "kong-oidc",
"discovery": "https://<oidc_provider>/.well-known/openid-configuration",
"scope": "openid",
"ssl_verify": "no",
"client_secret": "29d98bf7-168c-4874-b8e9-9ba5e7382fa0",
"token_endpoint_auth_method": "client_secret_post"
},
"id": "58cc119b-e5d0-4908-8929-7d6ed73cb7de",
"enabled": true,
"name": "oidc",
"api_id": "32625081-c712-4c46-b16a-5d6d9081f85f"
}

Upstream API request

For successfully authenticated request, the plugin will set upstream header X-Credential-Identifier to contain sub claim from user info, ID token or introspection result. Header X-Anonymous-Consumer is cleared.

The plugin adds a additional X-Userinfo, X-Access-Token and X-Id-Token headers to the upstream request, which can be consumer by upstream server. All of them are base64 encoded:

GET / HTTP/1.1Host: netcat:9000Connection: keep-aliveX-Forwarded-For: 172.19.0.1X-Forwarded-Proto: httpX-Forwarded-Host: localhostX-Forwarded-Port: 8000X-Real-IP: 172.19.0.1Cache-Control: max-age=0User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36Upgrade-Insecure-Requests: 1Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8Accept-Encoding: gzip, deflateAccept-Language: pl-PL,pl;q=0.8,en-US;q=0.6,en;q=0.4Cookie: session=KOn1am4mhQLKazlCA.....X-Userinfo: eyJnaXZlbl9uYW1lIjoixITEmMWaw5PFgcW7xbnEhiIsInN1YiI6ImM4NThiYzAxLTBiM2ItNDQzNy1hMGVlLWE1ZTY0ODkwMDE5ZCIsInByZWZlcnJlZF91c2VybmFtZSI6ImFkbWluIiwibmFtZSI6IsSExJjFmsOTxYHFu8W5xIYiLCJ1c2VybmFtZSI6ImFkbWluIiwiaWQiOiJjODU4YmMwMS0wYjNiLTQ0MzctYTBlZS1hNWU2NDg5MDAxOWQifQ==
X-Access-Token: eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJGenFSY0N1Ry13dzlrQUJBVng1ZG9sT2ZwTFhBNWZiRGFlVDRiemtnSzZRIn0.eyJqdGkiOiIxYjhmYzlkMC1jMjlmLTQwY2ItYWM4OC1kNzMyY2FkODcxY2IiLCJleHAiOjE1NDg1MTA4MjksIm5iZiI6MCwiaWF0IjoxNTQ4NTEwNzY5LCJpc3MiOiJodHRwOi8vMTkyLjE2OC4wLjk6ODA4MC9hdXRoL3JlYWxtcy9tYXN0ZXIiLCJhdWQiOlsibWFzdGVyLXJlYWxtIiwiYWNjb3VudCJdLCJzdWIiOiJhNmE3OGQ5MS01NDk0LTRjZTMtOTU1NS04NzhhMTg1Y2E0YjkiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJrb25nIiwibm9uY2UiOiJmNGRkNDU2YzBjZTY4ZmFmYWJmNGY4ZDA3YjQ0YWE4NiIsImF1dGhfdGltZSI6…IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiJ9.GWuguFjSEDGxw_vbD04UMKxtai15BE2lwBO0YkSzp-NKZ2SxAzl0nyhZxpP0VTzk712nQ8f_If5-mQBf_rqEVnOraDmX5NOXP0B8AoaS1jsdq4EomrhZGqlWmuaV71Cnqrw66iaouBR_6Q0s8bgc1FpCPyACM4VWs57CBdTrAZ2iv8dau5ODkbEvSgIgoLgBbUvjRKz1H0KyeBcXlVSgHJ_2zB9q2HvidBsQEIwTP8sWc6er-5AltLbV8ceBg5OaZ4xHoramMoz2xW-ttjIujS382QQn3iekNByb62O2cssTP3UYC747ehXReCrNZmDA6ecdnv8vOfIem3xNEnEmQw
X-Id-Token: eyJuYmYiOjAsImF6cCI6ImtvbmciLCJpYXQiOjE1NDg1MTA3NjksImlzcyI6Imh0dHA6XC9cLzE5Mi4xNjguMC45OjgwODBcL2F1dGhcL3JlYWxtc1wvbWFzdGVyIiwiYXVkIjoia29uZyIsIm5vbmNlIjoiZjRkZDQ1NmMwY2U2OGZhZmFiZjRmOGQwN2I0NGFhODYiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiIsImF1dGhfdGltZSI6MTU0ODUxMDY5NywiYWNyIjoiMSIsInNlc3Npb25fc3RhdGUiOiJiNDZmODU2Ny0zODA3LTQ0YmMtYmU1Mi1iMTNiNWQzODI5MTQiLCJleHAiOjE1NDg1MTA4MjksImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwianRpIjoiMjI1ZDRhNDItM2Y3ZC00Y2I2LTkxMmMtOGNkYzM0Y2JiNTk2Iiwic3ViIjoiYTZhNzhkOTEtNTQ5NC00Y2UzLTk1NTUtODc4YTE4NWNhNGI5IiwidHlwIjoiSUQifQ==

Standard OpenID Connect Scopes and Claims

The OpenID Connect Core 1.0 profile specifies the following standard scopes and claims:

ScopeClaim(s)
openidsub. In an ID Token, iss, aud, exp, iat will also be provided.
profileTypically claims like name, family_name, given_name, middle_name, preferred_username, nickname, picture and updated_at
emailemail and email_verified (boolean) indicating if the email address has been verified by the user

Note that the openid scope is a mandatory designator scope.

Description of the standard claims

ClaimTypeDescription
issURIThe Uniform Resource Identifier uniquely identifying the OpenID Connect Provider (OP)
audstring / arrayThe intended audiences. For ID tokens, the identity token is one or more clients. For Access tokens, the audience is typically one or more Resource Servers
nbfintegerNot before timestamp in Unix Epoch time*. May be omitted or set to 0 to indicate that the audience can disregard the claim
expintegerExpires timestamp in Unix Epoch time*
namestringPreferred display name. Ex. John Doe
family_namestringLast name. Ex. Doe
given_namestringFirst name. Ex. John
middle_namestringMiddle name. Ex. Donald
nicknamestringNick name. Ex. Johnny
preferred_usernamestringPreferred user name. Ex. johdoe
picturebase64A Base-64 encoded picture (typically PNG or JPEG) of the subject
updated_atintegerA timestamp in Unix Epoch time*

* (Seconds since January 1st 1970).

Passing the Access token as a normal Bearer token

To pass the access token to the upstream server as a normal Bearer token, configure the plugin as follows:

KeyValue
config.access_token_header_nameAuthorization
config.access_token_as_beareryes

Development

Running Unit Tests

To run unit tests, run the following command:

./bin/run-unit-tests.sh

This may take a while for the first run, as the docker image will need to be built, but subsequent runs will be quick.

Building the Integration Test Environment

To build the integration environment (Kong with the oidc plugin enabled, and Keycloak as the OIDC Provider), you will first need to find your computer's IP, and assign that to the environment variable IP. Finally, you will run the ./bin/build-env.sh command. Here's an example:

export IP=192.168.0.1
./bin/build-env.sh

To tear the environment down:

./bin/teardown-env.sh

About

OIDC plugin for Kong

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages