diff --git a/packages/cli/config/index.ts b/packages/cli/config/index.ts index 32dec2438f..5d66a1b3bb 100644 --- a/packages/cli/config/index.ts +++ b/packages/cli/config/index.ts @@ -319,6 +319,12 @@ const config = convict({ env: 'N8N_BASIC_AUTH_PASSWORD', doc: 'The password of the basic auth user' }, + hash: { + format: 'Boolean', + default: false, + env: 'N8N_BASIC_AUTH_HASH', + doc: 'If password for basic auth is hashed' + } }, jwtAuth: { active: { diff --git a/packages/cli/package.json b/packages/cli/package.json index 6f7bb04e7a..1caed60c0b 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -54,6 +54,7 @@ "devDependencies": { "@oclif/dev-cli": "^1.22.2", "@types/basic-auth": "^1.1.2", + "@types/bcrypt": "^3.0.0", "@types/compression": "1.0.1", "@types/connect-history-api-fallback": "^1.3.1", "@types/convict": "^4.2.1", @@ -72,15 +73,16 @@ "p-cancelable": "^2.0.0", "run-script-os": "^1.0.7", "ts-jest": "^25.4.0", + "ts-node": "^8.9.1", "tslint": "^6.1.2", - "typescript": "~3.7.4", - "ts-node": "^8.9.1" + "typescript": "~3.7.4" }, "dependencies": { "@oclif/command": "^1.5.18", "@oclif/errors": "^1.2.2", "@types/jsonwebtoken": "^8.3.4", "basic-auth": "^2.0.1", + "bcrypt": "^5.0.0", "body-parser": "^1.18.3", "body-parser-xml": "^1.1.0", "client-oauth2": "^4.2.5", diff --git a/packages/cli/src/Server.ts b/packages/cli/src/Server.ts index 46a2351a96..4f23a624c5 100644 --- a/packages/cli/src/Server.ts +++ b/packages/cli/src/Server.ts @@ -20,6 +20,7 @@ import { RequestOptions } from 'oauth-1.0a'; import * as csrf from 'csrf'; import * as requestPromise from 'request-promise-native'; import { createHmac } from 'crypto'; +import { compareSync } from 'bcrypt'; import { ActiveExecutions, @@ -186,6 +187,8 @@ class App { throw new Error('Basic auth is activated but no password got defined. Please set one!'); } + const basicAuthHashEnabled = await GenericHelpers.getConfigValue('security.basicAuth.hash') as boolean; + this.app.use((req: express.Request, res: express.Response, next: express.NextFunction) => { if (req.url.match(authIgnoreRegex)) { return next(); @@ -198,7 +201,7 @@ class App { return ResponseHelper.basicAuthAuthorizationError(res, realm, 'Authorization is required!'); } - if (basicAuthData.name !== basicAuthUser || basicAuthData.pass !== basicAuthPassword) { + if (basicAuthData.name !== basicAuthUser || (!basicAuthHashEnabled && basicAuthData.pass !== basicAuthPassword) || (basicAuthHashEnabled && compareSync(basicAuthData.pass, basicAuthPassword) === false)) { // Provided authentication data is wrong return ResponseHelper.basicAuthAuthorizationError(res, realm, 'Authorization data is wrong!'); }