Skip to content

Commit 5dec17f

Browse files
authored
Merge pull request #6 from felixheck/release/2.0.2
Release/2.0.2
2 parents 3ffe224 + b355667 commit 5dec17f

13 files changed

+363
-359
lines changed

README.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -107,27 +107,25 @@ server.route([
107107
## API
108108
#### Plugin Options
109109

110-
> **Hint**: By default, the Keycloak server has built-in two ways to authenticate the client: client ID and client secret, or with a signed JWT. This plugin supports both. Check the description of `secret` and `publicKey` for further information.
111-
>
112-
> If the signed JWTs are used as online strategy, ensure that the identifier of the related realm key (`kid`) is included in their header.
110+
> By default, the Keycloak server has built-in [two ways to authenticate][client-auth] the client: client ID and client secret, or with a signed JWT. This plugin supports both. Check the description of `secret` and `publicKey` for further information. If the signed JWTs are used as online strategy, ensure that the identifier of the related realm key is included in their header as `kid`.
113111
>
114112
> | Strategy | Online | Option |
115113
> |:------------|:------:|:------------|
116114
> | ID + Secret | x | `secret` |
117115
> | Signed JWT | x | |
118116
> | Signed JWT | | `publicKey` |
119117
120-
- `realmUrl {string}`: The absolute uri of the Keycloak realm.<br/>
118+
- `realmUrl {string}` The absolute uri of the Keycloak realm.<br/>
121119
Required. Example: `https://localhost:8080/auth/realms/testme`<br/>
122120

123-
- `clientId {string}` The identifier of the Keycloak client/application.<br/>
121+
- `clientId {string}` The identifier of the Keycloak client/application.<br/>
124122
Required. Example: `foobar`<br/>
125123

126-
- `secret {string}` The related secret of the Keycloak client/application.<br/>
124+
- `secret {string}` The related secret of the Keycloak client/application.<br/>
127125
Defining this option enables the traditional method described in the OAuth2 specification. To perform an almost offline validation enable the cache — a simple offline verfication with symmetric keys is not provided for security reasons.<br/>
128126
Optional. Example: `1234-bar-4321-foo`<br/>
129127

130-
- `publicKey {string}` The related public key of the Keycloak client/application.<br/>
128+
- `publicKey {string}` The related public key of the Keycloak client/application.<br/>
131129
Defining this option enables the offline validation using signed JWTs. The public key has to be in [PEM][pem] or [JWK][jwk] format. If you define neither `secret` nor `public` key, the plugin assumes that a signed JWT has to be validated – it retrieves the public key itself from `{realmUrl}/protocol/openid-connect/certs`. The offline strategy its performance is higher but the online strategy is the most flexible one.<br/>
132130
Optional.
133131

@@ -242,3 +240,4 @@ For further information read the [contributing guideline](CONTRIBUTING.md).
242240
[hapi-route-options]: https://hapijs.com/api#route-options
243241
[jwk]: https://tools.ietf.org/html/rfc7517
244242
[pem]: https://tools.ietf.org/html/rfc1421
243+
[client-auth]: https://keycloak.gitbooks.io/documentation/securing_apps/topics/oidc/java/client-authentication.html

src/cache.js

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,15 @@
1-
let instance
2-
31
/**
42
* @function
53
* @public
64
*
7-
* Initiate a cache singleton
5+
* Initiate a cache
86
*
97
* @param {Hapi.Server} server The created server instance
108
* @param {Object|boolean} opts The instance its options
11-
* @returns {Object} The cache instance
9+
* @returns {Object|false} The cache instance
1210
*/
13-
function init (server, opts) {
14-
if (instance === undefined) {
15-
if (opts === false) {
16-
instance = false
17-
} else {
18-
instance = server.cache(opts === true ? {} : opts)
19-
}
20-
}
21-
22-
return instance
11+
function create (server, opts) {
12+
return opts ? server.cache(opts === true ? {} : opts) : false
2313
}
2414

2515
/**
@@ -29,11 +19,12 @@ function init (server, opts) {
2919
* Get value out of cache by key.
3020
* Just if cache is initiated.
3121
*
22+
* @param {Object} The cache instance
3223
* @param {*} key The key to be searched
3324
* @param {Function} done The callback handler
3425
*/
35-
function get (key, done) {
36-
instance ? instance.get(key, done) : done(null, false)
26+
function get (cache, key, done) {
27+
cache ? cache.get(key, done) : done(null, false)
3728
}
3829

3930
/**
@@ -43,29 +34,18 @@ function get (key, done) {
4334
* Set value specified by key in cache.
4435
* Just if cache is initiated.
4536
*
37+
* @param {Object} The cache instance
4638
* @param {*} key The key to be indexed
4739
* @param {*} value The value to be stored
4840
* @param {number} ttl The time to live
4941
* @param {Function} done The callback handler
5042
*/
51-
function set (key, value, ttl, done) {
52-
instance && instance.set(key, value, ttl, done)
53-
}
54-
55-
/**
56-
* @function
57-
* @public
58-
*
59-
* Reset the current cache instance
60-
*
61-
*/
62-
function reset () {
63-
instance = undefined
43+
function set (cache, key, value, ttl, done) {
44+
cache && cache.set(key, value, ttl, done)
6445
}
6546

6647
module.exports = {
67-
init,
48+
create,
6849
get,
69-
set,
70-
reset
50+
set
7151
}

src/index.js

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
const { GrantManager } = require('keycloak-auth-utils')
2-
const Token = require('keycloak-auth-utils/lib/token')
2+
const KeycloakToken = require('keycloak-auth-utils/lib/token')
33
const cache = require('./cache')
44
const token = require('./token')
55
const { error, fakeReply, verify } = require('./utils')
@@ -9,10 +9,11 @@ const pkg = require('../package.json')
99
* @type {Object|GrantManager}
1010
* @private
1111
*
12-
* The plugin related options and GrantManager instance.
12+
* The plugin related options and instances.
1313
*/
1414
let options
1515
let manager
16+
let store
1617

1718
/**
1819
* @function
@@ -22,11 +23,12 @@ let manager
2223
* public key or online with help of the Keycloak server and
2324
* JWKS. Resolve if the verification succeeded.
2425
*
25-
* @param {string} token The token to be validated
26+
* @param {string} tkn The token to be validated
2627
* @returns {Promise} The error-handled promise
2728
*/
28-
function validateSignedJwt (token) {
29-
return manager.validateToken(new Token(token, options.clientId))
29+
function validateSignedJwt (tkn) {
30+
const kcTkn = new KeycloakToken(tkn, options.clientId)
31+
return manager.validateToken(kcTkn)
3032
}
3133

3234
/**
@@ -37,16 +39,16 @@ function validateSignedJwt (token) {
3739
* Keycloak server, the client identifier and its secret.
3840
* Resolve if the request succeeded and token is valid.
3941
*
40-
* @param {string} token The token to be validated
42+
* @param {string} tkn The token to be validated
4143
* @returns {Promise} The error-handled promise
4244
*/
43-
function validateSecret (token) {
44-
return manager.validateAccessToken(token).then((res) => {
45+
function validateSecret (tkn) {
46+
return manager.validateAccessToken(tkn).then((res) => {
4547
if (res === false) {
4648
throw Error(error.msg.invalid)
4749
}
4850

49-
return token
51+
return tkn
5052
})
5153
}
5254

@@ -64,11 +66,11 @@ function validateSecret (token) {
6466
function handleKeycloakValidation (tkn, reply) {
6567
const validateFn = options.secret ? validateSecret : validateSignedJwt
6668

67-
validateFn(tkn.get()).then(() => {
68-
const { expiresIn, credentials } = tkn.getData(options.userInfo)
69+
validateFn(tkn).then(() => {
70+
const { expiresIn, credentials } = token.getData(tkn, options.userInfo)
6971
const userData = { credentials }
7072

71-
cache.set(tkn.get(), userData, expiresIn)
73+
cache.set(store, tkn, userData, expiresIn)
7274
reply.continue(userData)
7375
}).catch((err) => {
7476
reply(error('unauthorized', err, error.msg.invalid))
@@ -83,18 +85,18 @@ function handleKeycloakValidation (tkn, reply) {
8385
* If yes, return cached user data. Otherwise
8486
* handle validation with help of Keycloak.
8587
*
86-
* @param {string} field The authorization field, e.g. the value of `Authorization`
87-
* @param {Function} reply The callback handler
88+
* @param {string} d The authorization field, e.g. the value of `Authorization`
89+
* @param {Function} done The callback handler
8890
*/
89-
function validate (field, reply) {
90-
const tkn = token(field)
91-
fakeReply(reply)
91+
function validate (field, done) {
92+
const tkn = token.create(field)
93+
const reply = fakeReply(done)
9294

9395
if (!tkn) {
9496
return reply(error('unauthorized', error.msg.missing))
9597
}
9698

97-
cache.get(tkn.get(), (err, cached) => {
99+
cache.get(store, tkn, (err, cached) => {
98100
const isCached = cached && !err
99101
isCached ? reply.continue(cached) : handleKeycloakValidation(tkn, reply)
100102
})
@@ -115,10 +117,7 @@ function validate (field, reply) {
115117
function strategy (server) {
116118
return {
117119
authenticate (request, reply) {
118-
return server.kjwt.validate(
119-
request.raw.req.headers.authorization,
120-
reply
121-
)
120+
return validate(request.raw.req.headers.authorization, reply)
122121
}
123122
}
124123
}
@@ -138,8 +137,7 @@ function strategy (server) {
138137
function plugin (server, opts, next) {
139138
options = verify(opts)
140139
manager = new GrantManager(options)
141-
142-
cache.init(server, options.cache)
140+
store = cache.create(server, options.cache)
143141

144142
server.auth.scheme('keycloak-jwt', strategy)
145143
server.decorate('server', 'kjwt', { validate })

0 commit comments

Comments
 (0)