From 8043439113019df29bf2764753eff5fe249e9029 Mon Sep 17 00:00:00 2001 From: Mitchell Herrijgers Date: Sun, 19 May 2019 08:34:20 +0200 Subject: [PATCH] Add sample Keycloak Authentication hook --- docs/securing-unleash.md | 1 + examples/keycloak-auth-hook.js | 90 +++++++++++++++++++++++++++++++ examples/keycloak-auth-unleash.js | 19 +++++++ 3 files changed, 110 insertions(+) create mode 100644 examples/keycloak-auth-hook.js create mode 100644 examples/keycloak-auth-unleash.js diff --git a/docs/securing-unleash.md b/docs/securing-unleash.md index 7203102847..1c5e7a845e 100644 --- a/docs/securing-unleash.md +++ b/docs/securing-unleash.md @@ -44,6 +44,7 @@ Examples of custom authentication hooks: - [google-auth-hook.js](https://github.com/Unleash/unleash/blob/master/examples/google-auth-hook.js) - [basic-auth-hook.js](https://github.com/Unleash/unleash/blob/master/examples/basic-auth-hook.js) +- [keycloak-auth-hook.js](https://github.com/Unleash/unleash/blob/master/examples/keycloak-auth-hook.js) We also have a version of Unleash deployed on Heroku which uses Google OAuth 2.0: https://secure-unleash.herokuapp.com diff --git a/examples/keycloak-auth-hook.js b/examples/keycloak-auth-hook.js new file mode 100644 index 0000000000..d01168c946 --- /dev/null +++ b/examples/keycloak-auth-hook.js @@ -0,0 +1,90 @@ +'use strict'; + +/** + * Keycloak hook for securing an Unleash server + * + * This example assumes that all users authenticating via + * keycloak should have access. You would probably limit access + * to users you trust. + * + * The implementation assumes the following environement variables: + * + * - AUTH_HOST + * - AUTH_REALM + * - AUTH_CLIENT_ID + */ + +// const { User, AuthenticationRequired } = require('unleash-server'); +const { User, AuthenticationRequired } = require('../lib/server-impl.js'); + + +const KeycloakStrategy = require("@exlinc/keycloak-passport"); +const passport = require('passport'); + +const kcConfig = { + host: "http://" + process.env.AUTH_HOST, + realm: process.env.AUTH_REALM, + clientId: process.env.AUTH_CLIENT_ID, + contextPath: '', // Use when Unleash is hosted on an url like /unleash/ + clientSecret: "", +}; + +passport.use( + "keycloak", + new KeycloakStrategy( + { + host: kcConfig.host, + realm: kcConfig.realm, + clientID: kcConfig.clientId, + clientSecret: "We don't need that, but is required", + callbackURL: `${kcConfig.contextPath}/api/auth/callback`, + authorizationURL: `${kcConfig.host}/auth/realms/hamis/protocol/openid-connect/auth`, + tokenURL: `${kcConfig.host}/auth/realms/hamis/protocol/openid-connect/token`, + userInfoURL: `${kcConfig.host}/auth/realms/hamis/protocol/openid-connect/userinfo` + }, + + (accessToken, refreshToken, profile, done) => { + done( + null, + new User({ + name: profile.fullName, + email: profile.email, + }) + ); + } + ) +); + +function enableKeycloakOauth(app) { + app.use(passport.initialize()); + app.use(passport.session()); + + passport.serializeUser((user, done) => done(null, user)); + passport.deserializeUser((user, done) => done(null, user)); + app.get('/api/admin/login', passport.authenticate('keycloak')); + + app.get('/api/auth/callback', passport.authenticate('keycloak'), (req, res, next) => { + res.redirect(`${kcConfig.contextPath}/`); + }); + + app.use('/api/admin/', (req, res, next) => { + if (req.user) { + next(); + } else { + // Instruct unleash-frontend to pop-up auth dialog + return res + .status('401') + .json( + new AuthenticationRequired({ + path: `${kcConfig.contextPath}/api/admin/login`, + type: 'custom', + message: `You have to identify yourself in order to use Unleash. + Click the button and follow the instructions.`, + }) + ) + .end(); + } + }); +} + +module.exports = enableKeycloakOauth; diff --git a/examples/keycloak-auth-unleash.js b/examples/keycloak-auth-unleash.js new file mode 100644 index 0000000000..7b0e2a26da --- /dev/null +++ b/examples/keycloak-auth-unleash.js @@ -0,0 +1,19 @@ +'use strict'; + +// const unleash = require('unleash-server'); +const unleash = require('../lib/server-impl.js'); + +const enableGoogleOauth = require('./google-auth-hook'); + +unleash + .start({ + databaseUrl: 'postgres://unleash_user:passord@localhost:5432/unleash', + secret: 'super-duper-secret', + adminAuthentication: 'custom', + preRouterHook: enableGoogleOauth, + }) + .then(server => { + console.log( + `Unleash started on http://localhost:${server.app.get('port')}` + ); + });