UNPKG

5.74 kBJavaScriptView Raw
1const hapi = require('@hapi/hapi')
2const nock = require('nock')
3const authKeycloak = require('../src')
4const fixtures = require('./fixtures')
5
6/**
7 * @type Object
8 * @private
9 *
10 * The default plugin configuration
11 */
12const defaults = {
13 schemeName: 'keycloak-jwt',
14 decoratorName: 'kjwt',
15 realmUrl: fixtures.common.realmUrl,
16 clientId: fixtures.common.clientId
17}
18
19/**
20 * @function
21 * @public
22 *
23 * Get overridden valid default options with customs.
24 *
25 * @param {Object} customs The options to be changed
26 * @returns {Object} The customized options
27 */
28function getOptions (customs) {
29 return Object.assign({}, defaults, customs)
30}
31
32/**
33 * @function
34 * @public
35 *
36 * Mock introspect request to the Keycloak server.
37 *
38 * @param {number} code The status code to be returned
39 * @param {Object} data The response object to be returned
40 * @param {boolean} [isError=false] Whether to reply with an error
41 */
42function mockIntrospect (code, data, isError = false) {
43 const base = nock(fixtures.common.baseUrl)
44 .post(`${fixtures.common.realmPath}${fixtures.common.introspectPath}`)
45
46 isError ? base.replyWithError(data) : base.reply(code, data)
47}
48
49/**
50 * @function
51 * @public
52 *
53 * Mock entitlement request to the Keycloak server.
54 *
55 * @param {number} code The status code to be returned
56 * @param {Object} data The response object to be returned
57 * @param {boolean} [isError=false] Whether to reply with an error
58 */
59function mockEntitlement (code, data, isError = false) {
60 const base = nock(fixtures.common.baseUrl)
61 .get(`${fixtures.common.realmPath}${fixtures.common.entitlementPath}`)
62
63 isError ? base.replyWithError(data) : base.reply(code, data)
64}
65
66/**
67 * @function
68 * @public
69 *
70 * Mock request to the api key service.
71 *
72 * @param {number} code The status code to be returned
73 * @param {Object} data The response object to be returned
74 */
75function mockApiKey (code, data) {
76 nock('http://barfoo.com').get('/foo/bar').reply(code, data)
77}
78
79/**
80 * @function
81 * @public
82 *
83 * Mock request object to be injected.
84 *
85 * @param {string} field The `authorization` header its value
86 * @param {string} [url] The url of the request
87 * @returns {Object} The composed request object
88 */
89function mockRequest (field, url = '/') {
90 return {
91 method: 'GET',
92 url,
93 headers: {
94 authorization: field
95 }
96 }
97}
98
99/**
100 * @function
101 * @public
102 *
103 * Log the option name with the asserted value.
104 *
105 * @param {string} option The name of the option
106 * @param {*} value The value to be asserted
107 * @returns {string} The aggregated log message
108 */
109function log (option, value) {
110 return `${option}: ${value && value.toString()}`
111}
112
113/**
114 * @function
115 * @private
116 *
117 * Register protected routes.
118 *
119 * @param {Hapi.Server} server The server to be decorated
120 */
121function registerRoutes (server) {
122 server.route([
123 {
124 method: 'GET',
125 path: '/',
126 options: {
127 auth: 'keycloak-jwt',
128 handler (req) {
129 return req.auth.credentials.scope
130 }
131 }
132 },
133 {
134 method: 'GET',
135 path: '/role',
136 options: {
137 auth: {
138 strategies: ['keycloak-jwt'],
139 access: {
140 scope: ['editor']
141 }
142 },
143 handler (req) {
144 return req.auth.credentials.scope
145 }
146 }
147 },
148 {
149 method: 'GET',
150 path: '/role/guest',
151 options: {
152 auth: {
153 strategies: ['keycloak-jwt'],
154 access: {
155 scope: ['guest']
156 }
157 },
158 handler (req) {
159 return req.auth.credentials.scope
160 }
161 }
162 },
163 {
164 method: 'GET',
165 path: '/role/rpt',
166 options: {
167 auth: {
168 strategies: ['keycloak-jwt'],
169 access: {
170 scope: ['scope:foo.READ']
171 }
172 },
173 handler (req) {
174 return req.auth.credentials.scope
175 }
176 }
177 },
178 {
179 method: 'GET',
180 path: '/proxy',
181 options: {
182 handler (req) {
183 return {
184 headers: req.headers,
185 query: req.query
186 }
187 }
188 }
189 },
190 {
191 method: 'GET',
192 path: '/mode-optional',
193 options: {
194 auth: { strategy: 'keycloak-jwt', mode: 'optional' },
195 handler (req) {
196 return {
197 headers: req.headers,
198 query: req.query
199 }
200 }
201 }
202 },
203 {
204 method: 'GET',
205 path: '/mode-try',
206 options: {
207 auth: { strategy: 'keycloak-jwt', mode: 'try' },
208 handler (req) {
209 return {
210 headers: req.headers,
211 query: req.query
212 }
213 }
214 }
215 }
216 ])
217}
218
219/**
220 * @function
221 * @public
222 *
223 * Register the plugin with passed options
224 *
225 * @param {Hapi.Server} server The server to be decorated
226 * @param {Object} opts The plugin related options
227 * @param {boolean} skipRoutes Whether to skip route definition
228 */
229async function registerPlugin (server, opts = {}, skipRoutes = false) {
230 const options = { ...defaults, ...opts }
231
232 await server.register({
233 plugin: authKeycloak,
234 options
235 })
236
237 server.auth.strategy(options.schemeName, options.schemeName)
238
239 if (!skipRoutes) {
240 registerRoutes(server)
241 }
242
243 return server
244}
245
246/**
247 * @function
248 * @public
249 *
250 * Create server with routes, plugin and error handler
251 *
252 * @param {Object|false} options The plugin related options
253 */
254async function getServer (options) {
255 const server = hapi.server()
256
257 await server.initialize()
258
259 if (options === false) {
260 registerRoutes(server)
261 return server
262 }
263
264 return registerPlugin(server, options)
265}
266
267module.exports = {
268 getOptions,
269 mockIntrospect,
270 mockEntitlement,
271 mockRequest,
272 mockApiKey,
273 log,
274 getServer,
275 registerPlugin
276}