Skip to content

Commit

Permalink
fix: complies access scope validation to RFC8693
Browse files Browse the repository at this point in the history
scope validation should support space separated values in credentials
see https://datatracker.ietf.org/doc/html/rfc8693#name-scope-scopes-claim

Co-authored-by: Vincent Hardouin <[email protected]>
  • Loading branch information
nlepage and VincentHardouin committed Feb 14, 2025
1 parent 9aa775f commit eb7e81c
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 4 deletions.
7 changes: 4 additions & 3 deletions lib/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -555,9 +555,10 @@ internals.validateScope = function (credentials, scope, type) {
return true;
}

const count = typeof credentials.scope === 'string' ?
scope[type].indexOf(credentials.scope) !== -1 ? 1 : 0 :
Hoek.intersect(scope[type], credentials.scope).length;
const count = Hoek.intersect(
scope[type],
(typeof credentials.scope === 'string') ? credentials.scope.split(' ') : credentials.scope
).length;

if (type === 'forbidden') {
return count === 0;
Expand Down
45 changes: 44 additions & 1 deletion test/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,27 @@ describe('authentication', () => {
expect(res.statusCode).to.equal(204);
});

it('matches scope (space separated to array)', async () => {

const server = Hapi.server();
server.auth.scheme('custom', internals.implementation);
server.auth.strategy('default', 'custom', { users: { steve: { scope: 'one two' } } });
server.auth.default('default');
server.route({
method: 'GET',
path: '/',
options: {
handler: (request) => request.auth.credentials.user,
auth: {
scope: ['one', 'three']
}
}
});

const res = await server.inject({ url: '/', headers: { authorization: 'Custom steve' } });
expect(res.statusCode).to.equal(204);
});

it('matches scope (single to single)', async () => {

const server = Hapi.server();
Expand Down Expand Up @@ -1036,7 +1057,7 @@ describe('authentication', () => {
expect(res5.result.message).to.equal('Insufficient scope');
});

it('errors on missing scope using arrays', async () => {
it('errors on missing scope using (array to array )', async () => {

const server = Hapi.server();
server.auth.scheme('custom', internals.implementation);
Expand All @@ -1058,6 +1079,28 @@ describe('authentication', () => {
expect(res.result.message).to.equal('Insufficient scope');
});

it('errors on missing scope using (space separated to array )', async () => {

const server = Hapi.server();
server.auth.scheme('custom', internals.implementation);
server.auth.strategy('default', 'custom', { users: { steve: { scope: 'a b' } } });
server.auth.default('default');
server.route({
method: 'GET',
path: '/',
options: {
handler: (request) => request.auth.credentials.user,
auth: {
scope: ['c', 'd']
}
}
});

const res = await server.inject({ url: '/', headers: { authorization: 'Custom steve' } });
expect(res.statusCode).to.equal(403);
expect(res.result.message).to.equal('Insufficient scope');
});

it('uses default scope when no scope override is set', async () => {

const server = Hapi.server();
Expand Down

0 comments on commit eb7e81c

Please sign in to comment.