forked from badges/shields
-
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.
Inject secrets into the services (badges#3652)
This is a reworking of badges#3410 based on some feedback @calebcartwright left on that PR. The goals of injecting the secrets are threefold: 1. Simplify testing 2. Be consistent with all of the other config (which is injected) 3. Encapsulate the sensitive auth-related code in one place so it can be studied and tested thoroughly - Rather than add more code to BaseService to handle authorization logic, it delegates that to an AuthHelper class. - When the server starts, it fetches the credentials from `config` and injects them into `BaseService.register()` which passes them to `invoke()`. - In `invoke()` the service's auth configuration is checked (`static get auth()`, much like `static get route()`). - If the auth config is present, an AuthHelper instance is created and attached to the new instance. - Then within the service, the password, basic auth config, or bearer authentication can be accessed via e.g. `this.authHelper.basicAuth` and passed to `this._requestJson()` and friends. - Everything is being done very explicitly, so it should be very clear where and how the configured secrets are being used. - Testing different configurations of services can now be done by injecting the config into `invoke()` in `.spec` files instead of mocking global state in the service tests as was done before. See the new Jira spec files for a good example of this. Ref badges#3393
- Loading branch information
1 parent
3324a4a
commit ce0ddf9
Showing
53 changed files
with
1,143 additions
and
951 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
'use strict' | ||
|
||
class AuthHelper { | ||
constructor({ userKey, passKey, isRequired = false }, privateConfig) { | ||
if (!userKey && !passKey) { | ||
throw Error('Expected userKey or passKey to be set') | ||
} | ||
|
||
this._userKey = userKey | ||
this._passKey = passKey | ||
this.user = userKey ? privateConfig[userKey] : undefined | ||
this.pass = passKey ? privateConfig[passKey] : undefined | ||
this.isRequired = isRequired | ||
} | ||
|
||
get isConfigured() { | ||
return ( | ||
(this._userKey ? Boolean(this.user) : true) && | ||
(this._passKey ? Boolean(this.pass) : true) | ||
) | ||
} | ||
|
||
get isValid() { | ||
if (this.isRequired) { | ||
return this.isConfigured | ||
} else { | ||
const configIsEmpty = !this.user && !this.pass | ||
return this.isConfigured || configIsEmpty | ||
} | ||
} | ||
|
||
get basicAuth() { | ||
const { user, pass } = this | ||
return this.isConfigured ? { user, pass } : undefined | ||
} | ||
|
||
get bearerAuthHeader() { | ||
const { pass } = this | ||
return this.isConfigured ? { Authorization: `Bearer ${pass}` } : undefined | ||
} | ||
} | ||
|
||
module.exports = { AuthHelper } |
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,96 @@ | ||
'use strict' | ||
|
||
const { expect } = require('chai') | ||
const { test, given, forCases } = require('sazerac') | ||
const { AuthHelper } = require('./auth-helper') | ||
|
||
describe('AuthHelper', function() { | ||
it('throws without userKey or passKey', function() { | ||
expect(() => new AuthHelper({}, {})).to.throw( | ||
Error, | ||
'Expected userKey or passKey to be set' | ||
) | ||
}) | ||
|
||
describe('isValid', function() { | ||
function validate(config, privateConfig) { | ||
return new AuthHelper(config, privateConfig).isValid | ||
} | ||
test(validate, () => { | ||
forCases([ | ||
// Fully configured user + pass. | ||
given( | ||
{ userKey: 'myci_user', passKey: 'myci_pass', isRequired: true }, | ||
{ myci_user: 'admin', myci_pass: 'abc123' } | ||
), | ||
given( | ||
{ userKey: 'myci_user', passKey: 'myci_pass' }, | ||
{ myci_user: 'admin', myci_pass: 'abc123' } | ||
), | ||
// Fully configured user or pass. | ||
given( | ||
{ userKey: 'myci_user', isRequired: true }, | ||
{ myci_user: 'admin' } | ||
), | ||
given( | ||
{ passKey: 'myci_pass', isRequired: true }, | ||
{ myci_pass: 'abc123' } | ||
), | ||
given({ userKey: 'myci_user' }, { myci_user: 'admin' }), | ||
given({ passKey: 'myci_pass' }, { myci_pass: 'abc123' }), | ||
// Empty config. | ||
given({ userKey: 'myci_user', passKey: 'myci_pass' }, {}), | ||
given({ userKey: 'myci_user' }, {}), | ||
given({ passKey: 'myci_pass' }, {}), | ||
]).expect(true) | ||
|
||
forCases([ | ||
// Partly configured. | ||
given( | ||
{ userKey: 'myci_user', passKey: 'myci_pass', isRequired: true }, | ||
{ myci_user: 'admin' } | ||
), | ||
given( | ||
{ userKey: 'myci_user', passKey: 'myci_pass' }, | ||
{ myci_user: 'admin' } | ||
), | ||
// Missing required config. | ||
given( | ||
{ userKey: 'myci_user', passKey: 'myci_pass', isRequired: true }, | ||
{} | ||
), | ||
given({ userKey: 'myci_user', isRequired: true }, {}), | ||
given({ passKey: 'myci_pass', isRequired: true }, {}), | ||
]).expect(false) | ||
}) | ||
}) | ||
|
||
describe('basicAuth', function() { | ||
function validate(config, privateConfig) { | ||
return new AuthHelper(config, privateConfig).basicAuth | ||
} | ||
test(validate, () => { | ||
forCases([ | ||
given( | ||
{ userKey: 'myci_user', passKey: 'myci_pass', isRequired: true }, | ||
{ myci_user: 'admin', myci_pass: 'abc123' } | ||
), | ||
given( | ||
{ userKey: 'myci_user', passKey: 'myci_pass' }, | ||
{ myci_user: 'admin', myci_pass: 'abc123' } | ||
), | ||
]).expect({ user: 'admin', pass: 'abc123' }) | ||
given({ userKey: 'myci_user' }, { myci_user: 'admin' }).expect({ | ||
user: 'admin', | ||
pass: undefined, | ||
}) | ||
given({ passKey: 'myci_pass' }, { myci_pass: 'abc123' }).expect({ | ||
user: undefined, | ||
pass: 'abc123', | ||
}) | ||
given({ userKey: 'myci_user', passKey: 'myci_pass' }, {}).expect( | ||
undefined | ||
) | ||
}) | ||
}) | ||
}) |
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
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
Oops, something went wrong.