Inject secrets into the services (#3652)

This is a reworking of #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 #3393
This commit is contained in:
Paul Melnikow
2019-07-09 23:14:36 -04:00
committed by GitHub
parent 3324a4a162
commit ce0ddf93fc
53 changed files with 1143 additions and 951 deletions

View File

@@ -1,7 +1,6 @@
'use strict'
const Joi = require('@hapi/joi')
const serverSecrets = require('../../lib/server-secrets')
const { optionalUrl } = require('../validators')
const { isDependencyMap } = require('../package-json-helpers')
const { BaseJsonService, InvalidResponse, NotFound } = require('..')
@@ -38,6 +37,10 @@ const queryParamSchema = Joi.object({
// Abstract class for NPM badges which display data about the latest version
// of a package.
module.exports = class NpmBase extends BaseJsonService {
static get auth() {
return { passKey: 'npm_token' }
}
static buildRoute(base, { withTag } = {}) {
if (withTag) {
return {
@@ -74,15 +77,16 @@ module.exports = class NpmBase extends BaseJsonService {
}
async _requestJson(data) {
// Use a custom Accept header because of this bug:
// <https://github.com/npm/npmjs.org/issues/163>
const headers = { Accept: '*/*' }
if (serverSecrets.npm_token) {
headers.Authorization = `Bearer ${serverSecrets.npm_token}`
}
return super._requestJson({
...data,
options: { headers },
options: {
headers: {
// Use a custom Accept header because of this bug:
// <https://github.com/npm/npmjs.org/issues/163>
Accept: '*/*',
...this.authHelper.bearerAuthHeader,
},
},
})
}