forked from Seneca-CDOT/telescope
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for generating a service token
- Loading branch information
Showing
5 changed files
with
118 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
const jwt = require('jsonwebtoken'); | ||
|
||
const { JWT_ISSUER, JWT_AUDIENCE, SECRET } = process.env; | ||
|
||
/** | ||
* Create a short-lived service-to-service JWT, useful for authorizing | ||
* one Telescope microservice with another. The receiving service has | ||
* to opt into this by allowing the 'service' role. | ||
* @returns JWT service token | ||
*/ | ||
function createServiceToken() { | ||
const payload = { | ||
iss: JWT_ISSUER, | ||
aud: JWT_AUDIENCE, | ||
sub: 'telescope-service', | ||
roles: ['service'], | ||
}; | ||
|
||
return jwt.sign(payload, SECRET, { expiresIn: '5m' }); | ||
} | ||
|
||
module.exports = createServiceToken; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,7 @@ const { | |
logger, | ||
hash, | ||
createError, | ||
createServiceToken, | ||
} = require('./src'); | ||
const { JWT_EXPIRES_IN, JWT_ISSUER, JWT_AUDIENCE, SECRET } = process.env; | ||
|
||
|
@@ -427,7 +428,6 @@ describe('Satellite()', () => { | |
isAuthorized({ | ||
authorizeUser: (user) => { | ||
expect(user).toEqual(decoded); | ||
console.log({ user, decoded }); | ||
return user.sub === '[email protected]'; | ||
}, | ||
}), | ||
|
@@ -457,6 +457,53 @@ describe('Satellite()', () => { | |
}); | ||
}); | ||
|
||
test('isAuthenticated() + isAuthorized() for service token and role should work on a specific route', (done) => { | ||
const service = createSatelliteInstance({ | ||
name: 'test', | ||
}); | ||
const token = createServiceToken(); | ||
|
||
const router = service.router; | ||
router.get('/public', (req, res) => res.json({ hello: 'public' })); | ||
router.get( | ||
'/protected', | ||
isAuthenticated(), | ||
isAuthorized({ roles: ['service'] }), | ||
(req, res) => { | ||
// Make sure an admin user payload was added to req | ||
expect(req.user.sub).toEqual('telescope-service'); | ||
expect(Array.isArray(req.user.roles)).toBe(true); | ||
expect(req.user.roles).toContain('service'); | ||
res.json({ hello: 'protected' }); | ||
} | ||
); | ||
|
||
service.start(port, async () => { | ||
// Public should need no bearer token | ||
let res = await fetch(`${url}/public`); | ||
expect(res.ok).toBe(true); | ||
let body = await res.json(); | ||
expect(body).toEqual({ hello: 'public' }); | ||
|
||
// Protected should fail without authorization header | ||
res = await fetch(`${url}/protected`); | ||
expect(res.ok).toBe(false); | ||
expect(res.status).toEqual(401); | ||
|
||
// Protected should work with authorization header | ||
res = await fetch(`${url}/protected`, { | ||
headers: { | ||
Authorization: `bearer ${token}`, | ||
}, | ||
}); | ||
expect(res.ok).toBe(true); | ||
body = await res.json(); | ||
expect(body).toEqual({ hello: 'protected' }); | ||
|
||
service.stop(done); | ||
}); | ||
}); | ||
|
||
test('isAuthenticated() + isAuthorized() for admin role should work on a specific route', (done) => { | ||
const service = createSatelliteInstance({ | ||
name: 'test', | ||
|
@@ -821,3 +868,17 @@ describe('Create Error tests for Satellite', () => { | |
expect(testError.message).toBe('Satellite Test for Errors'); | ||
}); | ||
}); | ||
|
||
describe('createServiceToken()', () => { | ||
test('should create a service token', () => { | ||
const token = createServiceToken(); | ||
const decoded = jwt.verify(token, SECRET); | ||
|
||
expect(decoded.sub).toEqual('telescope-service'); | ||
expect(Array.isArray(decoded.roles)).toBe(true); | ||
expect(decoded.roles).toContain('service'); | ||
|
||
const currentDateSeconds = Date.now() / 1000; | ||
expect(decoded.exp).toBeGreaterThan(currentDateSeconds); | ||
}); | ||
}); |