Small express based integration between the Kong API gateway and any Passenger supported authentcation solution. This provides the following features:
- Authorization URL supporting Authorization Code grants that provisions OAuth tokens via Kong's authorization endpoint.
- Authentication via Passport with pluggable authentication strategies.
- Currently only CAS is implemented, but they're fairly trivial. See below.
- Simple introspection endpoint that, when setup behind Kong, returns user and consumer information as JSON. Compatible with the Kong Userinfo Plugin.
- Impersonation of OAuth 2.0 users using the Kong OAuth Impersonation Plugin.
Note: The user consent prompt is not implemented so the
enableConsent
flag must always be false in the configuration. This should be implemented shortly.
This is designed to implement the flow specified in Kon's OAuth 2.0 plugin API as documented in Kong's documentation
This app implements the two boxes at the top, steps 2 - 7. Rather than providing
a login screen of it's own, it delegates authentication to a third party system
via Passenger. Currently only the CAS strategy is implemented using the CAS 3.0
protocol. Once the third party system authenticates the user, this app will prompt
for user consent and send a POST
request to Kong to provision the access token
and, if all goes well, redirect the user back to their application with the
authorization code it can use to retrieve it's token from Kong.
Note that the app will need to have access to the Kong API to retrieve client credentials to properly provision access tokens.
You'll first have to create a config/default.yaml
or an environment specific
configuration file (see config for details).
A short sample is provided and detailed documentation about the options is available
below. Then, simply start the server and point your application at the configured
endpoints.
The configuration file must be well formed YAML or JSON and be of the following form:
server:
host: "0.0.0.0" # IP/Host on which to listen
port: 3000 # Port on which to listen
publicUrl: https://api.mydomain.com # Publicly accessible URL for this service. Used for the SSO redirect URL.
routes:
authorize: oauth/authorize # URL on which to accept authorize calls
introspection: oauth/validate # URL on which to respond to profile/validate requests
logout: oauth/logout # URL on which to respond to logout requests
impersonation: oauth/impersonate # URL with which we can impersonate other users
defaultApi: auth # Default Kong API to reference for all requests, see below.
kong:
api: http://kong:8001 # Base URL the Kong API
gateway: https://kong:8443 # Base URL to the Kong gateway
provisionKey: anf7n329fn # Provision key provided by Kong
insecureSSL: true # Whether to validate Kong's SSL certificate
enableConsent: false # Enable the user consent prompt, see below
introspection:
headers:
name: x-userinfo-displayname # HTTP Header containing the user's name
groups: x-userinfo-memberof # HTTP header containing the user's groups
ui:
theme: default # The UI theme to use, see below.
authentication:
strategy: cas # Authenticate strategy to use, see below.
url: https://sso.mydomain.com # URL at which the SSO system resides
See the config module for more details about format and features regarding how configuration is parsed.
Since OAuth is implemented as an API plugin in Kong, there isn't a "global" endpoint
for OAuth. However, it may be undesirable to force clients to specify a Kong API to
which to authenticate. For this reason, the defaultApi
may be used to prepend all
Kong requests with the specified value.
Note: Access Tokens can be global in Kong by checking the "Global Credentials" flag when adding OAuth to an API and should be used if
defaultApi
is used.
For example, if defaultApi
is set to auth
and https://api.mydomain.com/oauth
is
proxied to this integration component, then requests to
https://api.mydomain.com/oauth/authorize
will be cause requests to be sent to
/auth/oauth2/authorize
in Kong.
In some cases a consent screen is not desirable. If the owner of the data, the API,
and the application are all the same entity, it's hardly desriable to demand the
user approve access. In this case, the enableConsent
flag can be set to false
to disable the consent screen.
Note: Currently, this is the only supported behavior. Flipping
enableConsent
totrue
will result in undefined behavior. Additionally, this is currently a global setting. In the future, it should be possible to define consent on a per client and per API basis.
This integration uses Handlebars templates and Express
views to implement various responses. To change the way responses are formatted,
simply copy the views/default
directory into another directory in views
and set
the ui.theme
property in the config to match the directory name.
Since this integration uses Passport to implement authentication, adding an additonal
strategy is trivial. Simply create a new module in the lib/strategies
directory
named after your strategy and return a complete Password strategy as the module.
See the included lib/strategies/cas.js
for a simple example.
While Kong will provide user and consumer details as HTTP headers to APIs behind Kong, it does not include an exposed endpoint that an external application, that is, one not behind Kong, can use to determine who is logged in to which client. This server implements such an endpoint. For this to work, the introspection endpoint (as defined in the configuration) should be proxied by Kong. It will use the HTTP headers sent by Kong to generate a JSON representation as a response. In this scenario, this application's authorize endpoint would be publicly exposed while it's introspection endpoint would be behind Kong, requiring OAuth 2.0 authentication.
If enabled, an endpoint is provided to allow a user to be impersonated. This will provision impersonation to the OAuth Impersonation Plugin. Currently, not authorization is done prior to impersonation although that will likely be coming. At this time, you'll need to implement your own which can be done by putting the introspection endpoint behind Kong itself.
One of the easiest ways to run this is through Docker. The standard nodejs
Docker
image should be used and can be invoked in the following way:
docker run -ti node -w /usr/src/app -v "$(pwd)":/usr/src/app -p 3000:3000 "node server.js"
All part of the configuration can be specified on the environment as a JSON object, for example:
docker run -ti node -w /usr/src/app -v "$(pwd)":/usr/src/app -p 3000:3000 -e 'NODE_CONFIG={"server": {"publicUrl": "https://api.mydomain.com"}}' "node server.js"
The debug
module is used for more detailed output. Add the DEBUG=*
environment
variable to see more output. See
debug's documentation for more details.