hapi-inferred-scopes
Advanced tools
Comparing version 1.2.0 to 3.0.0
@@ -11,2 +11,3 @@ module.exports = { | ||
"sourceType": "script", | ||
"ecmaVersion": 2018, | ||
"ecmaFeatures": { | ||
@@ -18,2 +19,5 @@ "modules": false, | ||
rules: { | ||
"strict": [2, "global"], | ||
"indent": ["error", 2], | ||
"linebreak-style": 0, | ||
"max-len": [2, 120, 2, { | ||
@@ -25,7 +29,10 @@ ignoreUrls: true, | ||
"no-restricted-syntax": [0], | ||
"no-multi-assign": 0, | ||
"no-return-assign": 0, | ||
"strict": [2, "global"], | ||
"global-require": 0, | ||
"padded-blocks": 0, | ||
"no-underscore-dangle": 0 | ||
"no-underscore-dangle": 0, | ||
"no-param-reassign": 0 | ||
} | ||
}; |
@@ -11,5 +11,13 @@ { | ||
"name": "Debug Tests", | ||
"program": "${workspaceRoot}/test/inferredScope.spec.js" | ||
"program": "${workspaceRoot}/node_modules/@hapi/lab/bin/lab", | ||
"args": ["test"], | ||
"skipFiles": [ | ||
"<node_internals>/**/*.js" | ||
], | ||
"cwd": "${workspaceRoot}", | ||
"runtimeExecutable": null, | ||
"outputCapture": "std", | ||
"protocol": "inspector" | ||
} | ||
] | ||
} |
119
lib/index.js
'use strict'; | ||
const deep = require('deep-get-set'); | ||
const Boom = require('boom'); | ||
const Joi = require('joi'); | ||
const Boom = require('@hapi/boom'); | ||
const Joi = require('@hapi/joi'); | ||
@@ -11,8 +11,8 @@ const internals = {}; | ||
scopeDelimiter: Joi.string().default(':'), | ||
scopeAccessor: Joi.func().default(request => request.auth.credentials.scope) | ||
scopeAccessor: Joi.function() | ||
}); | ||
internals.isSegMatchAll = s => s === '*'; | ||
internals.isSegMatchAll = (s) => s === '*'; | ||
internals.isSegRegex = s => s.startsWith('/') && s.endsWith('/'); | ||
internals.isSegRegex = (s) => s.startsWith('/') && s.endsWith('/'); | ||
@@ -22,10 +22,10 @@ internals.segmentProcessingCommands = { | ||
test: internals.isSegRegex, | ||
process: seg => seg | ||
process: (seg) => seg | ||
}, | ||
isMatchAll: { | ||
test: internals.isSegMatchAll, | ||
process: seg => seg | ||
process: (seg) => seg | ||
}, | ||
isComputable: { | ||
test: seg => !(internals.isSegRegex(seg) || internals.isSegMatchAll(seg)), | ||
test: (seg) => !(internals.isSegRegex(seg) || internals.isSegMatchAll(seg)), | ||
process: (seg, request) => { | ||
@@ -60,5 +60,5 @@ const matches = seg.match(/{(.*)}/g) || []; | ||
const match = zip.filter(z => { | ||
const match = zip.filter((z) => { | ||
const seg2Exists = z[1]; | ||
const defferedSegsAreEqual = () => ( | ||
const deferredSegsAreEqual = () => ( | ||
internals.isSegRegex(z[0]) | ||
@@ -68,6 +68,6 @@ ? new RegExp(z[0].slice(1, -1)).test(z[1]) | ||
); | ||
return seg2Exists && defferedSegsAreEqual(); | ||
return seg2Exists && deferredSegsAreEqual(); | ||
}); | ||
return match.map(m => m[1]).join(delimiter) === effectiveScope2; | ||
return match.map((m) => m[1]).join(delimiter) === effectiveScope2; | ||
}; | ||
@@ -77,4 +77,4 @@ | ||
const effectiveScopes = scopes.reduce((es, s1) => { | ||
const inferredExists = scopes.some(s2 => | ||
s1 !== s2 && internals.isScope2Inferred(s1, s2, settings.scopeDelimiter) | ||
const inferredExists = scopes.some( | ||
(s2) => s1 !== s2 && internals.isScope2Inferred(s1, s2, settings.scopeDelimiter) | ||
); | ||
@@ -97,11 +97,12 @@ | ||
const filters = { | ||
required: rScopes.filter(r => r.startsWith('+')).map(s => s.slice(1)), | ||
forbidden: rScopes.filter(r => r.startsWith('!')).map(s => s.slice(1)), | ||
optional: rScopes.filter(r => !(r.startsWith('+') || r.startsWith('!'))) | ||
required: rScopes.filter((r) => r.startsWith('+')).map((s) => s.slice(1)), | ||
forbidden: rScopes.filter((r) => r.startsWith('!')).map((s) => s.slice(1)), | ||
optional: rScopes.filter((r) => !(r.startsWith('+') || r.startsWith('!'))) | ||
}; | ||
const ensureOnlyOneMatchAll = segs => { | ||
const ensureOnlyOneMatchAll = (segs) => { | ||
if (!segs.some(internals.isSegMatchAll)) { | ||
return segs; | ||
} | ||
const firstMatchAll = segs.find(internals.isSegMatchAll); | ||
@@ -112,15 +113,13 @@ return segs.filter((_, i) => i <= segs.indexOf(firstMatchAll)); | ||
Object.keys(filters).forEach((type) => ( | ||
filters[type] = filters[type].map((rs) => | ||
ensureOnlyOneMatchAll(rs.split(delimiter)) | ||
.map(seg => { | ||
filters[type] = filters[type].map((rs) => ensureOnlyOneMatchAll(rs.split(delimiter)) | ||
.map((seg) => { | ||
const commands = internals.segmentProcessingCommands; | ||
const command = Object.keys(commands).find(key => commands[key].test(seg)); | ||
const command = Object.keys(commands).find((key) => commands[key].test(seg)); | ||
return commands[command].process(seg, request); | ||
}) | ||
.join(delimiter) | ||
) | ||
.join(delimiter)) | ||
)); | ||
const scopesEqualOrInferred = s1 => effectiveScopes.some(s2 => | ||
s1 === s2 || internals.isScope2Inferred(s1, s2, settings.scopeDelimiter) | ||
const scopesEqualOrInferred = (s1) => effectiveScopes.some( | ||
(s2) => s1 === s2 || internals.isScope2Inferred(s1, s2, settings.scopeDelimiter) | ||
); | ||
@@ -149,2 +148,3 @@ | ||
} | ||
const prev = s.shift(); | ||
@@ -163,49 +163,42 @@ map(s, o[prev]); | ||
internals.inferredScope = (settings) => | ||
(request, reply) => { | ||
const inferredScopeConfig = request.route.settings.plugins.inferredScope; | ||
internals.inferredScope = (settings) => (request, h) => { | ||
const inferredScopeConfig = request.route.settings.plugins.inferredScope; | ||
if (!inferredScopeConfig) { | ||
return reply.continue(); | ||
} | ||
if (!inferredScopeConfig) { | ||
return h.continue; | ||
} | ||
const scope = settings.scopeAccessor(request); | ||
if (!scope) { | ||
return reply(Boom.forbidden('Insufficient scope')); | ||
} | ||
const scope = settings.scopeAccessor(request); | ||
if (!scope) { | ||
return Boom.forbidden('Insufficient scope'); | ||
} | ||
if (!(inferredScopeConfig instanceof Array)) { | ||
return reply(Boom.forbidden('Unknown scopes')); | ||
} | ||
if (!(inferredScopeConfig instanceof Array)) { | ||
return Boom.forbidden('Unknown scopes'); | ||
} | ||
const effectiveScopes = internals.getEffectiveScopes(scope, settings); | ||
const effectiveScopes = internals.getEffectiveScopes(scope, settings); | ||
// eslint-disable-next-line no-param-reassign | ||
request.auth.artifacts = request.auth.artifacts || {}; | ||
// eslint-disable-next-line no-param-reassign | ||
request.auth.artifacts.scopeContext = internals.createScopeContext( | ||
effectiveScopes, | ||
settings | ||
); | ||
request.auth.artifacts = request.auth.artifacts || {}; | ||
request.auth.artifacts.scopeContext = internals.createScopeContext( | ||
effectiveScopes, | ||
settings | ||
); | ||
if (!internals.hasInferredScope(request, effectiveScopes, settings)) { | ||
return reply(Boom.forbidden('Insufficient scope')); | ||
} | ||
return reply.continue(); | ||
}; | ||
exports.register = (plugin, options, next) => { | ||
const results = Joi.validate(options, internals.schema); | ||
if (results.error) { | ||
return next(results.error); | ||
if (!internals.hasInferredScope(request, effectiveScopes, settings)) { | ||
return Boom.forbidden('Insufficient scope'); | ||
} | ||
plugin.ext('onPostAuth', internals.inferredScope(results.value)); | ||
return next(); | ||
return h.continue; | ||
}; | ||
exports.register.attributes = { | ||
name: 'hapi-inferred-scopes', | ||
version: '1.0.0' | ||
exports.plugin = { | ||
register: (server, options) => { | ||
const validatedOptions = Joi.attempt(options, internals.schema); | ||
if (!validatedOptions.scopeAccessor) { | ||
validatedOptions.scopeAccessor = (request) => request.auth.credentials.scope; | ||
} | ||
server.ext('onPostAuth', internals.inferredScope(validatedOptions)); | ||
}, | ||
pkg: require('../package.json') | ||
}; |
{ | ||
"name": "hapi-inferred-scopes", | ||
"version": "1.2.0", | ||
"version": "3.0.0", | ||
"description": "infer route access from grouped scopes", | ||
"main": "lib/index.js", | ||
"scripts": { | ||
"test": "test/inferredScope.spec.js" | ||
"coverage": "lab -C --reporter html test > coverage.html", | ||
"lint": "node ./node_modules/.bin/eslint lib", | ||
"test": "node ./node_modules/@hapi/lab/bin/lab test" | ||
}, | ||
@@ -16,11 +18,26 @@ "repository": { | ||
], | ||
"author": "daniel ross", | ||
"author": { | ||
"name": "Daniel Ross", | ||
"email": "danielglennross@gmail.com" | ||
}, | ||
"contributors": [ | ||
{ | ||
"name": "Matthew Bates", | ||
"email": "matthew.bates.117@gmail.com" | ||
} | ||
], | ||
"license": "ISC", | ||
"devDependencies": { | ||
"code": "^4.0.0", | ||
"eslint": "^2.9.0", | ||
"eslint-config-airbnb": "^9.0.1", | ||
"eslint-plugin-import": "^1.7.0", | ||
"hapi": "^16.1.0", | ||
"lab": "^13.0.1" | ||
"@hapi/code": "^7.0.0", | ||
"@hapi/eslint-config-hapi": "^12.3.0", | ||
"@hapi/eslint-plugin-hapi": "^4.3.4", | ||
"@hapi/hapi": "^18.0.0", | ||
"@hapi/lab": "^21.0.0", | ||
"eslint": "^6.1.0", | ||
"eslint-config-airbnb": "^18.0.1", | ||
"eslint-config-airbnb-base": "^14.0.0", | ||
"eslint-plugin-import": "^2.18.2", | ||
"eslint-plugin-jsx-a11y": "^6.2.3", | ||
"eslint-plugin-react": "^7.14.3", | ||
"eslint-plugin-react-hooks": "^1.7.0" | ||
}, | ||
@@ -32,6 +49,6 @@ "bugs": { | ||
"dependencies": { | ||
"boom": "^4.2.0", | ||
"deep-get-set": "^1.1.0", | ||
"joi": "^10.2.2" | ||
"@hapi/boom": "^8.0.0", | ||
"@hapi/joi": "^16.0.0", | ||
"deep-get-set": "^1.1.0" | ||
} | ||
} |
# hapi-inferred-scopes | ||
Hapi out-the-box scopes are powerful, but what if we wanted to manage scopes like resources which have sub-resources and infer whether a request is permitted? | ||
@@ -6,5 +7,7 @@ `hapi-inferred-scopes` allows us to mark routes with finely grained scopes, however still permit access for credentials that infer parent scopes. | ||
## Install | ||
`npm install --save hapi-inferred-scopes` | ||
## Usage | ||
```javascript | ||
@@ -19,20 +22,18 @@ // the following option values are the defaults | ||
server.register({ | ||
register: require('hapi-inferred-scopes'), | ||
await server.register({ | ||
plugin: require('hapi-inferred-scopes'), | ||
options | ||
}, (err) => { | ||
server.route({ | ||
method: 'GET', | ||
path: '/user/email', | ||
config: { | ||
auth: 'session', | ||
plugins: { | ||
inferredScope: ['user:email'] // make this as granular as possible | ||
}, | ||
handler: (request, reply) => | ||
reply(request.auth.artifacts.scopeContext).code(200) | ||
} | ||
}); | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/user/email', | ||
options: { | ||
auth: 'session', | ||
plugins: { | ||
inferredScope: ['user:email'] // make this as granular as possible | ||
}, | ||
handler: (request, h) => | ||
h.response(request.auth.artifacts.scopeContext).code(200) | ||
} | ||
}); | ||
@@ -42,2 +43,3 @@ ``` | ||
## Example | ||
Say within our app we identify the following scope groups: | ||
@@ -48,3 +50,3 @@ | ||
We can now guard a route with the most specific scope we'd like a request auth credentials to have. | ||
We can now guard a route with the most specific scope we'd like a request auth credentials to have. | ||
For example, a route which accesses a user's account we can guard with `user:account`. | ||
@@ -60,7 +62,7 @@ An auth credential that has scope `user:account` is allowed to access this route, along with any credential that has the parent scope `user` - this is inferred. | ||
For dynamic expressions, surround the expression in `{...}` like so: | ||
For dynamic expressions, surround the expression in `{...}` like so: | ||
- `{params.username` | ||
- `user-{params.username}` | ||
- `user:{params.accountType}`(child scope is a dynaimc expression) | ||
- `user:{params.accountType}`(child scope is a dynamic expression) | ||
@@ -73,4 +75,4 @@ For regular expressions, surround the expression in `/.../` like so: | ||
A wild card operator: match all `*` is supported. | ||
This operator will match any scope or subsequent subscopes, including absent ones. For example, `user:*` will match: | ||
A wild card operator: match all `*` is supported. | ||
This operator will match any scope or subsequent sub-scopes, including absent ones. For example, `user:*` will match: | ||
@@ -81,3 +83,3 @@ - `user` | ||
In addition, a `scopeContext` is created and accessible on `request.auth.arifacts.scopeContext`. This is an object representing the hierarchy of grouped scopes. | ||
In addition, a `scopeContext` is created and accessible on `request.auth.artifacts.scopeContext`. This is an object representing the hierarchy of grouped scopes. | ||
`scopeContext` can be inspected to make any further decisions regarding scopes during a request's life-cycle. | ||
@@ -84,0 +86,0 @@ For example a credential with scopes: `['user:account:read', 'user:profile', 'admin']` will have the following `scopeContext`: |
'use strict'; | ||
const Code = require('code'); | ||
const Hapi = require('hapi'); | ||
const Lab = require('lab'); | ||
const Hapi = require('@hapi/hapi'); | ||
const expect = Code.expect; | ||
const lab = Lab.script(); | ||
const describe = lab.describe; | ||
const it = lab.it; | ||
const { expect } = require('@hapi/code'); | ||
const setAuthSchemeWithScope = (scope) => | ||
() => ({ | ||
authenticate(request, reply) { | ||
return reply.continue({ credentials: { scope } }); | ||
} | ||
}); | ||
const { describe, it } = exports.lab = require('@hapi/lab').script(); | ||
const setAuthSchemeWithScope = (scope) => () => ({ | ||
authenticate(request, h) { | ||
return h.authenticated({ credentials: { scope } }); | ||
} | ||
}); | ||
describe('explicit scope', () => { | ||
it('assigns scopeContext to auth artifacts', (done) => { | ||
it('assigns scopeContext to auth artifacts', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -28,27 +23,23 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope([])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/artifacts', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: [] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/artifacts', | ||
options: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: [] | ||
}, | ||
handler: (request) => request.auth.artifacts | ||
} | ||
}); | ||
server.inject('/artifacts', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/artifacts'); | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
}); | ||
it('builds scopeContext object', (done) => { | ||
it('builds scopeContext object', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -58,29 +49,25 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope1', 'scope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/artifacts', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: [] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/artifacts', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: [] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/artifacts', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope1).to.exist(); | ||
expect(res.result.scopeContext.scope2).to.exist(); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/artifacts'); | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope1).to.exist(); | ||
expect(res.result.scopeContext.scope2).to.exist(); | ||
}); | ||
it('authenticates on matching an explicit single scope', (done) => { | ||
it('authenticates on matching an explicit single scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -90,26 +77,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/singlescope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/singlescope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/singlescope', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/singlescope'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('authenticates on matching explicit multiple scopes', (done) => { | ||
it('authenticates on matching explicit multiple scopes', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -119,26 +102,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope1', 'scope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/multiplescopes', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope1', 'scope2'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/multiplescopes', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope1', 'scope2'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/multiplescopes', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/multiplescopes'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('authenticates on matching at least one explicit scope', (done) => { | ||
it('authenticates on matching at least one explicit scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -148,26 +127,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope1', 'scope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/eitherscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope2'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/eitherscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope2'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/eitherscope', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/eitherscope'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('authenticates when the route is configured with no scopes (empty array)', (done) => { | ||
it('authenticates when the route is configured with no scopes (empty array)', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -177,26 +152,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope1', 'scope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/emptyscopes', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: [] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/emptyscopes', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: [] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/emptyscopes', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/emptyscopes'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('authenticates a required scope', (done) => { | ||
it('authenticates a required scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -206,26 +177,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope1', 'scope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/requiredscope', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/requiredscope'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('fails to authenticates when a required scope is missing', (done) => { | ||
it('fails to authenticates when a required scope is missing', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -235,26 +202,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/requiredscope', (res) => { | ||
expect(res.statusCode).to.equal(403); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/requiredscope'); | ||
expect(res.statusCode).to.equal(403); | ||
}); | ||
it('authenticates a missing forbidden scope', (done) => { | ||
it('authenticates a missing forbidden scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -264,26 +227,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope1', 'scope2'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope1', 'scope2'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/forbiddenscope', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/forbiddenscope'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('fails to authenticates when a forbidden scope exists', (done) => { | ||
it('fails to authenticates when a forbidden scope exists', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -293,26 +252,23 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope1', 'scope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope2'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope2'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/forbiddenscope', (res) => { | ||
expect(res.statusCode).to.equal(403); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/forbiddenscope'); | ||
expect(res.statusCode).to.equal(403); | ||
}); | ||
it('dynamically binds request data to scopes', (done) => { | ||
it('dynamically binds request data to scopes', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -322,25 +278,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/groupedscope/{scope}', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['{params.scope}'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/groupedscope/{scope}', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['{params.scope}'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/groupedscope/scope', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope).to.exist(); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/groupedscope/scope'); | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope).to.exist(); | ||
}); | ||
}); |
'use strict'; | ||
const Code = require('code'); | ||
const Hapi = require('hapi'); | ||
const Lab = require('lab'); | ||
const Hapi = require('@hapi/hapi'); | ||
const expect = Code.expect; | ||
const lab = Lab.script(); | ||
const describe = lab.describe; | ||
const it = lab.it; | ||
const { expect } = require('@hapi/code'); | ||
const setAuthSchemeWithScope = (scope) => | ||
() => ({ | ||
authenticate(request, reply) { | ||
return reply.continue({ credentials: { scope } }); | ||
} | ||
}); | ||
const { describe, it } = exports.lab = require('@hapi/lab').script(); | ||
const setAuthSchemeWithScope = (scope) => () => ({ | ||
authenticate(request, h) { | ||
return h.authenticated({ credentials: { scope } }); | ||
} | ||
}); | ||
describe('inferred scope', () => { | ||
it('authenticates on matching a grouped scope', (done) => { | ||
it('authenticates on matching a grouped scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -28,26 +23,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/groupedscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/groupedscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/groupedscope', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/groupedscope'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('authenticates on matching a grouped scope and explicit scopes exist', (done) => { | ||
it('authenticates on matching a grouped scope and explicit scopes exist', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -57,26 +48,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope', 'scope1'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/inferredexplicit', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/inferredexplicit', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/inferredexplicit', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/inferredexplicit'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('authenticates on matching a single inferred scope', (done) => { | ||
it('authenticates on matching a single inferred scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -86,26 +73,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/singleinferred', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/singleinferred', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/singleinferred', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/singleinferred'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('builds scopeContext on matching a single inferred scope', (done) => { | ||
it('builds scopeContext on matching a single inferred scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -115,28 +98,24 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/scopecontext', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/scopecontext', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/scopecontext', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope).to.exist(); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/scopecontext'); | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope).to.exist(); | ||
}); | ||
it('authenticates and reduces extraneous scopes to common inferred scope', (done) => { | ||
it('authenticates and reduces extraneous scopes to common inferred scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -146,29 +125,25 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope', 'scope:subscope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/reduces', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/reduces', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/reduces', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope).to.not.exist(); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/reduces'); | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope).to.not.exist(); | ||
}); | ||
it('authenticates on matching a twice nested inferred scope', (done) => { | ||
it('authenticates on matching a twice nested inferred scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -178,26 +153,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope1'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/twicenested', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope1:subscope2'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/twicenested', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope1:subscope2'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/twicenested', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/twicenested'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('builds scopeContext on matching a twice nested inferred scope', (done) => { | ||
it('builds scopeContext on matching a twice nested inferred scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -207,28 +178,24 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope1'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/twicenested', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope1:subscope2'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/twicenested', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope1:subscope2'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/twicenested', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope1).to.exist(); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/twicenested'); | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope1).to.exist(); | ||
}); | ||
it('authenticates on matching a grouped scope on a twice nested inferred scope', (done) => { | ||
it('authenticates on matching a grouped scope on a twice nested inferred scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -238,26 +205,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope1:subscope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/twicenested', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope1:subscope2'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/twicenested', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope1:subscope2'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/twicenested', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/twicenested'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('builds scopeContext on matching a 3x nested inferred scope', (done) => { | ||
it('builds scopeContext on matching a 3x nested inferred scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -267,29 +230,25 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope1:subscope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/threetimesnested', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope1:subscope2'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/threetimesnested', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope1:subscope2'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/threetimesnested', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope1).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope1.subscope2).to.exist(); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/threetimesnested'); | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope1).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope1.subscope2).to.exist(); | ||
}); | ||
it('authenticates and reduces extraneous 3x grouped scopes to common inferred scope', (done) => { | ||
it('authenticates and reduces extraneous 3x grouped scopes to common inferred scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -299,30 +258,26 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope1', 'scope:subscope1:subscope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/threetimesnested', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope1'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/threetimesnested', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope1'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/threetimesnested', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope1).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope1.subscope2).to.not.exist(); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/threetimesnested'); | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope1).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope1.subscope2).to.not.exist(); | ||
}); | ||
it('builds scopeContext on inferred and explicit scopes', (done) => { | ||
it('builds scopeContext on inferred and explicit scopes', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -332,67 +287,59 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope1:subscope1', 'scope1:subscope2', 'scope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/mixed', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope1:subscope1'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/mixed', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope1:subscope1'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/mixed', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope1).to.exist(); | ||
expect(res.result.scopeContext.scope1.subscope1).to.exist(); | ||
expect(res.result.scopeContext.scope1.subscope2).to.exist(); | ||
expect(res.result.scopeContext.scope2).to.exist(); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/mixed'); | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope1).to.exist(); | ||
expect(res.result.scopeContext.scope1.subscope1).to.exist(); | ||
expect(res.result.scopeContext.scope1.subscope2).to.exist(); | ||
expect(res.result.scopeContext.scope2).to.exist(); | ||
}); | ||
it('builds scopeContext on inferred and explicit reduced scopes', (done) => { | ||
it('builds scopeContext on inferred and explicit reduced scopes', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
server.auth.scheme('scopeTest', setAuthSchemeWithScope( | ||
['scope1:subscope1', 'scope1:subscope2', 'scope2', 'scope2:subscope2']) | ||
); | ||
['scope1:subscope1', 'scope1:subscope2', 'scope2', 'scope2:subscope2'] | ||
)); | ||
server.auth.strategy('scope', 'scopeTest'); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/mixed', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope1:subscope1'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/mixed', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope1:subscope1'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/mixed', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope1).to.exist(); | ||
expect(res.result.scopeContext.scope1.subscope1).to.exist(); | ||
expect(res.result.scopeContext.scope1.subscope2).to.exist(); | ||
expect(res.result.scopeContext.scope2).to.exist(); | ||
expect(res.result.scopeContext.scope2.subscope2).to.not.exist(); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/mixed'); | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope1).to.exist(); | ||
expect(res.result.scopeContext.scope1.subscope1).to.exist(); | ||
expect(res.result.scopeContext.scope1.subscope2).to.exist(); | ||
expect(res.result.scopeContext.scope2).to.exist(); | ||
expect(res.result.scopeContext.scope2.subscope2).to.not.exist(); | ||
}); | ||
it('fails to authenticate when single group scope is too granular', (done) => { | ||
it('fails to authenticate when single group scope is too granular', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -402,26 +349,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope1'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/invalidscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/invalidscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/invalidscope', (res) => { | ||
expect(res.statusCode).to.equal(403); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/invalidscope'); | ||
expect(res.statusCode).to.equal(403); | ||
}); | ||
it('fails to authenticate when multiple group scope is too granular', (done) => { | ||
it('fails to authenticate when multiple group scope is too granular', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -431,26 +374,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope1:subscope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/invalidscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope1'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/invalidscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:subscope1'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/invalidscope', (res) => { | ||
expect(res.statusCode).to.equal(403); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/invalidscope'); | ||
expect(res.statusCode).to.equal(403); | ||
}); | ||
it('authenticates a required scope', (done) => { | ||
it('authenticates a required scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -460,26 +399,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/requiredscope', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/requiredscope'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('fails to authenticates when a required scope is missing', (done) => { | ||
it('fails to authenticates when a required scope is missing', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -489,26 +424,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope([])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/requiredscope', (res) => { | ||
expect(res.statusCode).to.equal(403); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/requiredscope'); | ||
expect(res.statusCode).to.equal(403); | ||
}); | ||
it('authenticates a required nested scope', (done) => { | ||
it('authenticates a required nested scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -518,26 +449,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope1:subscope1'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1:subscope1'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1:subscope1'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/requiredscope', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/requiredscope'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('fails to authenticates when a required nested scope is missing', (done) => { | ||
it('fails to authenticates when a required nested scope is missing', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -547,26 +474,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope([])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1:subscope1'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1:subscope1'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/requiredscope', (res) => { | ||
expect(res.statusCode).to.equal(403); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/requiredscope'); | ||
expect(res.statusCode).to.equal(403); | ||
}); | ||
it('authenticates a missing forbidden scope', (done) => { | ||
it('authenticates a missing forbidden scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -576,26 +499,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope([])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/forbiddenscope', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/forbiddenscope'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('fails to authenticates when a forbidden scope exists', (done) => { | ||
it('fails to authenticates when a forbidden scope exists', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -605,26 +524,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/forbiddenscope', (res) => { | ||
expect(res.statusCode).to.equal(403); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/forbiddenscope'); | ||
expect(res.statusCode).to.equal(403); | ||
}); | ||
it('authenticates a missing forbidden nested scope', (done) => { | ||
it('authenticates a missing forbidden nested scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -634,26 +549,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope([])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope:subscope'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope:subscope'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/forbiddenscope', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/forbiddenscope'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('fails to authenticates when a forbidden nested scope exists', (done) => { | ||
it('fails to authenticates when a forbidden nested scope exists', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -663,26 +574,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope:subscope'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope:subscope'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/forbiddenscope', (res) => { | ||
expect(res.statusCode).to.equal(403); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/forbiddenscope'); | ||
expect(res.statusCode).to.equal(403); | ||
}); | ||
it('fails to authenticate an inferred scope where the route specifies a nested forbidden scope', (done) => { | ||
it('fails to authenticate an inferred scope where the route specifies a nested forbidden scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -692,26 +599,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope:subscope'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope:subscope'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/forbiddenscope', (res) => { | ||
expect(res.statusCode).to.equal(403); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/forbiddenscope'); | ||
expect(res.statusCode).to.equal(403); | ||
}); | ||
it('authenticates an inferred scope where the route specifies a nested required scope', (done) => { | ||
it('authenticates an inferred scope where the route specifies a nested required scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -721,26 +624,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope:subscope'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope:subscope'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/requiredscope', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/requiredscope'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('fails to authenticate an inferred scope where the route specifies a twice nested forbidden scope', (done) => { | ||
it('fails to authenticate an inferred scope where the route specifies a twice nested forbidden scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -750,26 +649,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope1'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope:subscope1:subscope2'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/forbiddenscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['!scope:subscope1:subscope2'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/forbiddenscope', (res) => { | ||
expect(res.statusCode).to.equal(403); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/forbiddenscope'); | ||
expect(res.statusCode).to.equal(403); | ||
}); | ||
it('authenticates an inferred scope where the route specifies a twice nested required scope', (done) => { | ||
it('authenticates an inferred scope where the route specifies a twice nested required scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -779,26 +674,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope1'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope:subscope1:subscope2'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/requiredscope', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope:subscope1:subscope2'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/requiredscope', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/requiredscope'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('authenticates with a requied scope and a missing forbidden scope', (done) => { | ||
it('authenticates with a required scope and a missing forbidden scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -808,26 +699,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope1:subscope1'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/mixture', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1:subscope1', '!scope2:subscope2'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/mixture', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1:subscope1', '!scope2:subscope2'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/mixture', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/mixture'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('fails to authenticates with an inferred required scope and a forbidden scope', (done) => { | ||
it('fails to authenticates with an inferred required scope and a forbidden scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -837,26 +724,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope1', 'scope2:subscope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/mixture', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1:subscope1', '!scope2:subscope2'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/mixture', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1:subscope1', '!scope2:subscope2'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/mixture', (res) => { | ||
expect(res.statusCode).to.equal(403); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/mixture'); | ||
expect(res.statusCode).to.equal(403); | ||
}); | ||
it('fails to authenticates with a required scope and an inferred forbidden scope', (done) => { | ||
it('fails to authenticates with a required scope and an inferred forbidden scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -866,26 +749,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope1:subscope1', 'scope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/mixture', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1:subscope1', '!scope2:subscope2'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/mixture', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1:subscope1', '!scope2:subscope2'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/mixture', (res) => { | ||
expect(res.statusCode).to.equal(403); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/mixture'); | ||
expect(res.statusCode).to.equal(403); | ||
}); | ||
it('authenticates with a required scope and a forbidden scope missing', (done) => { | ||
it('authenticates with a required scope and a forbidden scope missing', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -895,26 +774,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope1:subscope1', 'scope2:subscope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/mixture', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1:subscope1', '!scope2:subscope3'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/mixture', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['+scope1:subscope1', '!scope2:subscope3'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/mixture', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/mixture'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('dynamically binds request data to grouped scopes', (done) => { | ||
it('dynamically binds request data to grouped scopes', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -924,29 +799,25 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/groupedscope/{scope}/{subscope}', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['{params.scope}:{params.subscope}'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/groupedscope/{scope}/{subscope}', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['{params.scope}:{params.subscope}'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/groupedscope/scope/subscope', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope).to.exist(); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/groupedscope/scope/subscope'); | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope).to.exist(); | ||
}); | ||
it('authenticates with a regex scope', (done) => { | ||
it('authenticates with a regex scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -956,26 +827,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/regex', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['/.*/'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/regex', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['/.*/'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/regex', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/regex'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('authenticates with a partial regex nested scope', (done) => { | ||
it('authenticates with a partial regex nested scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -985,26 +852,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope1'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/regex', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:/sub.*/'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/regex', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:/sub.*/'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/regex', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/regex'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('authenticates with a regex nested scope', (done) => { | ||
it('authenticates with a regex nested scope', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -1014,26 +877,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope1'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/regex', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['/.*/:/.*/'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/regex', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['/.*/:/.*/'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/regex', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/regex'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('fails to authenticate when a nested scope is missing', (done) => { | ||
it('fails to authenticate when a nested scope is missing', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -1043,26 +902,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope1'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/regex', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['/.*/'] | ||
}, | ||
handler: (request, reply) => reply().code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/regex', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['/.*/'] | ||
}, | ||
handler: (request, h) => h.response().code(200) | ||
} | ||
}); | ||
server.inject('/regex', (res) => { | ||
expect(res.statusCode).to.equal(403); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/regex'); | ||
expect(res.statusCode).to.equal(403); | ||
}); | ||
it('authenticates using regex and dynamic scopes', (done) => { | ||
it('authenticates using regex and dynamic scopes', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -1072,30 +927,26 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope1:subscope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/groupedscope/{scope}/{subscope1}', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['{params.scope}:{params.subscope1}:/sub.*/'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/groupedscope/{scope}/{subscope1}', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['{params.scope}:{params.subscope1}:/sub.*/'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/groupedscope/scope/subscope1', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope1).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope1.subscope2).to.exist(); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/groupedscope/scope/subscope1'); | ||
expect(res.statusCode).to.equal(200); | ||
expect(res.result.scopeContext).to.exist(); | ||
expect(res.result.scopeContext.scope).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope1).to.exist(); | ||
expect(res.result.scopeContext.scope.subscope1.subscope2).to.exist(); | ||
}); | ||
it('authenticates using a match all operator', (done) => { | ||
it('authenticates using a match all operator', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -1105,26 +956,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/matchall', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['*'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/matchall', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['*'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/matchall', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/matchall'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('authenticates using a match all operator when a subscope doesn\'t exist', (done) => { | ||
it('authenticates using a match all operator when a subscope doesn\'t exist', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -1134,26 +981,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/matchall', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:*'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/matchall', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:*'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/matchall', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/matchall'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('authenticates using a nested match all operator', (done) => { | ||
it('authenticates using a nested match all operator', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -1163,26 +1006,23 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/matchall', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:*'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/matchall', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:*'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/matchall', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/matchall'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('authenticates using a twice nested match all operator', (done) => { | ||
it('authenticates using a twice nested match all operator', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -1192,26 +1032,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope1:subscope2'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/matchall', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:*'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/matchall', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:*'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/matchall', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/matchall'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('authenticates using the first match all operator discovered', (done) => { | ||
it('authenticates using the first match all operator discovered', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -1221,26 +1057,22 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope:subscope1'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/matchall', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:*:*'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/matchall', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['scope:*:*'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/matchall', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/matchall'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
it('authenticates and ignores any scopes after the match all operator', (done) => { | ||
it('authenticates and ignores any scopes after the match all operator', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -1250,23 +1082,19 @@ server.auth.scheme('scopeTest', setAuthSchemeWithScope(['scope'])); | ||
server.register(require('../'), () => { | ||
await server.register(require('../')); | ||
server.route({ | ||
method: 'GET', | ||
path: '/matchall', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['*:scope'] | ||
}, | ||
handler: (request, reply) => reply(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.route({ | ||
method: 'GET', | ||
path: '/matchall', | ||
config: { | ||
auth: 'scope', | ||
plugins: { | ||
inferredScope: ['*:scope'] | ||
}, | ||
handler: (request, h) => h.response(request.auth.artifacts).code(200) | ||
} | ||
}); | ||
server.inject('/matchall', (res) => { | ||
expect(res.statusCode).to.equal(200); | ||
done(); | ||
}); | ||
}); | ||
const res = await server.inject('/matchall'); | ||
expect(res.statusCode).to.equal(200); | ||
}); | ||
}); |
'use strict'; | ||
const Code = require('code'); | ||
const Hapi = require('hapi'); | ||
const Lab = require('lab'); | ||
const Hapi = require('@hapi/hapi'); | ||
const expect = Code.expect; | ||
const lab = Lab.script(); | ||
const describe = lab.describe; | ||
const it = lab.it; | ||
const { expect } = require('@hapi/code'); | ||
const { describe, it } = exports.lab = require('@hapi/lab').script(); | ||
describe('register', () => { | ||
it('passes with default options', (done) => { | ||
it('passes with default options', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
let exception = null; | ||
server.register(require('../'), (err) => { | ||
expect(err).to.not.exist(); | ||
done(); | ||
}); | ||
try { | ||
await server.register(require('../')); | ||
} catch (e) { | ||
exception = e; | ||
} | ||
expect(exception).to.be.null(); | ||
}); | ||
it('passes with configured options', (done) => { | ||
it('passes with configured options', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
const options = { | ||
scopeDelimiter: ';', | ||
scopeAccessor: request => request.auth.credentials.scope | ||
scopeAccessor: (request) => request.auth.credentials.scope | ||
}; | ||
server.register({ | ||
register: require('../'), | ||
options | ||
}, (err) => { | ||
expect(err).to.not.exist(); | ||
done(); | ||
}); | ||
let exception = null; | ||
try { | ||
await server.register({ | ||
plugin: require('../'), | ||
options | ||
}); | ||
} catch (e) { | ||
exception = e; | ||
} | ||
expect(exception).to.be.null(); | ||
}); | ||
it('fails with invalid options', (done) => { | ||
it('fails with invalid options', async () => { | ||
const server = new Hapi.Server(); | ||
server.connection(); | ||
@@ -50,11 +51,15 @@ const options = { | ||
server.register({ | ||
register: require('../'), | ||
options | ||
}, (err) => { | ||
expect(err).to.exist(); | ||
done(); | ||
}); | ||
let exception = null; | ||
try { | ||
await server.register({ | ||
plugin: require('../'), | ||
options | ||
}); | ||
} catch (e) { | ||
exception = e; | ||
} | ||
expect(exception).to.not.be.null(); | ||
expect(exception.message).to.equal('"invalidProperty" is not allowed'); | ||
}); | ||
}); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
96
52640
12
8
1329
+ Added@hapi/boom@^8.0.0
+ Added@hapi/joi@^16.0.0
+ Added@hapi/address@2.1.4(transitive)
+ Added@hapi/boom@8.0.1(transitive)
+ Added@hapi/formula@1.2.0(transitive)
+ Added@hapi/hoek@8.5.1(transitive)
+ Added@hapi/joi@16.1.8(transitive)
+ Added@hapi/pinpoint@1.0.2(transitive)
+ Added@hapi/topo@3.1.6(transitive)
- Removedboom@^4.2.0
- Removedjoi@^10.2.2
- Removedboom@4.3.1(transitive)
- Removedhoek@4.3.1(transitive)
- Removedisemail@2.2.1(transitive)
- Removeditems@2.2.1(transitive)
- Removedjoi@10.6.0(transitive)
- Removedtopo@2.1.1(transitive)