Skip to content

Commit f55622c

Browse files
authored
Merge pull request #1 from felixheck/release/0.1.1
Release/0.1.1
2 parents 4986f77 + e369bd6 commit f55622c

File tree

8 files changed

+195
-371
lines changed

8 files changed

+195
-371
lines changed

src/index.js

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,49 @@
1+
const { GrantManager } = require('keycloak-auth-utils')
12
const cache = require('./cache')
2-
const manager = require('./manager')
33
const token = require('./token')
44
const { error, fakeReply, verify } = require('./utils')
55
const pkg = require('../package.json')
66

7+
let manager
8+
9+
/**
10+
* @function
11+
* @public
12+
*
13+
* Get user information based on token with help of Keycloak.
14+
* If all validations and requests are successful, save the
15+
* token and its user data in memory cache.
16+
*
17+
* @param {string} token The token to be validated
18+
* @param {Function} reply The callback handler
19+
*/
20+
function handleKeycloakUserInfo (tkn, reply) {
21+
manager.userInfo(tkn.get()).then((userInfo) => {
22+
const { scope, expiresIn } = tkn.getData()
23+
const userData = { credentials: Object.assign({ scope }, userInfo) }
24+
25+
cache.set(tkn.get(), userData, expiresIn)
26+
reply.continue(userData)
27+
}).catch((err) => {
28+
reply(error('unauthorized', err))
29+
})
30+
}
31+
732
/**
833
* @function
934
* @public
1035
*
1136
* Validate a token with help of Keycloak.
12-
* If all validations and requests are successful,
13-
* save the token and its user data in memory cache.
1437
*
1538
* @param {string} token The token to be validated
1639
* @param {Function} reply The callback handler
1740
*/
1841
function handleKeycloakValidation (tkn, reply) {
19-
const rawTkn = tkn.get()
42+
const invalidate = (err) => reply(error('unauthorized', err, error.msg.invalid))
2043

21-
manager.validateAccessToken(rawTkn, reply, () => {
22-
manager.userInfo(rawTkn, reply, (userInfo) => {
23-
const { scope, expiresIn } = tkn.getData()
24-
const userData = { credentials: Object.assign({ scope }, userInfo) }
25-
cache.set(tkn.get(), userData, expiresIn)
26-
27-
return reply.continue(userData)
28-
})
29-
})
44+
manager.validateAccessToken(tkn.get()).then((res) => {
45+
res ? handleKeycloakUserInfo(tkn, reply) : invalidate()
46+
}).catch(invalidate)
3047
}
3148

3249
/**
@@ -49,11 +66,8 @@ function validate (field, reply) {
4966
}
5067

5168
cache.get(tkn.get(), (err, cached) => {
52-
if (cached && !err) {
53-
return reply.continue(cached)
54-
}
55-
56-
return handleKeycloakValidation(tkn, reply)
69+
const isCached = cached && !err
70+
isCached ? reply.continue(cached) : handleKeycloakValidation(tkn, reply)
5771
})
5872
}
5973

@@ -94,7 +108,7 @@ function strategy (server) {
94108
*/
95109
function plugin (server, opts, next) {
96110
opts = verify(opts)
97-
manager.init(opts.client)
111+
manager = new GrantManager(opts.client)
98112
cache.init(server, opts.cache)
99113

100114
server.auth.scheme('keycloak-jwt', strategy)

src/manager.js

Lines changed: 0 additions & 81 deletions
This file was deleted.

src/token.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,13 @@ function token (field) {
1717
* @private
1818
*
1919
* Extract bearer token out of header.
20+
* https://tools.ietf.org/html/rfc7519
2021
*
2122
* @param {string} header The header to be scanned
2223
* @returns {string} The extracted header
2324
*/
2425
function extractToken (header) {
25-
return /^(?:bearer) ([A-Za-z0-9-_=]+\.[A-Za-z0-9-_=]+\.?[A-Za-z0-9-_.+/=]*)$/i.exec(header)
26+
return /^(?:bearer) ([a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?)$/i.exec(header)
2627
}
2728

2829
/**

test/_helpers.js

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
const hapi = require('hapi')
2+
const _ = require('lodash')
3+
const { GrantManager } = require('keycloak-auth-utils')
24
const authKeycloak = require('../src')
35
const fixtures = require('./_fixtures')
46

7+
const GrantManagerClone = {}
8+
59
/**
610
* @type Object
711
* @private
@@ -13,6 +17,27 @@ const defaults = {
1317
cache: false
1418
}
1519

20+
/**
21+
* @type Object.<Function>
22+
* @public
23+
*
24+
* Provide several functions to clone, reset and
25+
* stub methods of `GrantManager`.
26+
*/
27+
const prototypes = {
28+
clone () {
29+
GrantManagerClone.prototype = _.cloneDeep(GrantManager.prototype)
30+
},
31+
reset () {
32+
GrantManager.prototype = GrantManagerClone.prototype
33+
},
34+
stub (name, value, type = 'resolve') {
35+
GrantManager.prototype[name] = function () {
36+
return Promise[type](value)
37+
}
38+
}
39+
}
40+
1641
/**
1742
* @function
1843
* @private
@@ -36,6 +61,21 @@ function registerRoutes (server) {
3661
{
3762
method: 'GET',
3863
path: '/role',
64+
config: {
65+
auth: {
66+
strategies: ['keycloak-jwt'],
67+
access: {
68+
scope: ['editor']
69+
}
70+
},
71+
handler (req, reply) {
72+
reply({ foo: 42 })
73+
}
74+
}
75+
},
76+
{
77+
method: 'GET',
78+
path: '/role/guest',
3979
config: {
4080
auth: {
4181
strategies: ['keycloak-jwt'],
@@ -84,17 +124,7 @@ function registerPlugin (server, options = defaults, done = () => {}) {
84124
function getServer (options, done) {
85125
const server = new hapi.Server()
86126

87-
server.connection({
88-
host: '127.0.0.1',
89-
port: 1337
90-
})
91-
92-
process.on('SIGINT', () => {
93-
server.stop({ timeout: 10000 }).then((err) => {
94-
process.exit((err) ? 1 : 0)
95-
})
96-
})
97-
127+
server.connection()
98128
server.initialize((err) => {
99129
if (err) throw err
100130

@@ -108,5 +138,6 @@ function getServer (options, done) {
108138

109139
module.exports = {
110140
getServer,
111-
registerPlugin
141+
registerPlugin,
142+
prototypes
112143
}

test/cache.spec.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
const test = require('ava')
2-
const helpers = require('./_helpers')
2+
const { getServer } = require('./_helpers')
33
const cache = require('../src/cache')
44

55
test.afterEach('reset cache', () => {
66
cache.reset()
77
})
88

99
test.cb.serial('just create one instance – object', (t) => {
10-
helpers.getServer(false, (server) => {
10+
getServer(false, (server) => {
1111
const cch1 = cache.init(server, { segment: 'foo' })
1212
const cch2 = cache.init(server, { segment: 'foo' })
1313

@@ -19,7 +19,7 @@ test.cb.serial('just create one instance – object', (t) => {
1919
})
2020

2121
test.cb.serial('just create one instance – boolean', (t) => {
22-
helpers.getServer(false, (server) => {
22+
getServer(false, (server) => {
2323
const cch1 = cache.init(server, false)
2424
const cch2 = cache.init(server, false)
2525

@@ -31,7 +31,7 @@ test.cb.serial('just create one instance – boolean', (t) => {
3131
})
3232

3333
test.cb.serial('set and get value', (t) => {
34-
helpers.getServer(false, (server) => {
34+
getServer(false, (server) => {
3535
cache.init(server, { segment: 'foo' })
3636
cache.set('bar', 42, 10000)
3737

@@ -44,7 +44,7 @@ test.cb.serial('set and get value', (t) => {
4444
})
4545

4646
test.cb.serial('set and get value – no cache', (t) => {
47-
helpers.getServer(false, (server) => {
47+
getServer(false, (server) => {
4848
cache.init(server, false)
4949
cache.set('bar', 42, 10000)
5050

@@ -57,7 +57,7 @@ test.cb.serial('set and get value – no cache', (t) => {
5757
})
5858

5959
test.cb.serial('set and get value – expired', (t) => {
60-
helpers.getServer(false, (server) => {
60+
getServer(false, (server) => {
6161
cache.init(server, { segment: 'foo' })
6262
cache.set('bar', 42, 100)
6363

0 commit comments

Comments
 (0)