From 5a86b2251be00038bc2115636b87bcc2280ded99 Mon Sep 17 00:00:00 2001 From: Ashish Pandey Date: Thu, 18 Jul 2024 13:44:54 +0530 Subject: [PATCH] Noobaa Account: Replace bcrypt password hashing by argon2 As bcrypt is not under active maintenance, we need to replace it with argon2 hashing module. Signed-off-by: Ashish Pandey --- package.json | 1 + src/server/common_services/auth_server.js | 20 ++++++++++++++++- src/server/system_services/account_server.js | 22 ++++++++++++++----- .../system_services/schemas/account_schema.js | 2 +- src/tools/bcrypt_cli.js | 15 ------------- 5 files changed, 37 insertions(+), 23 deletions(-) delete mode 100644 src/tools/bcrypt_cli.js diff --git a/package.json b/package.json index e32115521c..277e8f4aa2 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ "ajv": "8.17.1", "aws-sdk": "2.1659.0", "bcrypt": "5.1.1", + "argon2": "0.40.3", "big-integer": "1.6.52", "bindings": "1.5.0", "bufferutil": "4.0.8", diff --git a/src/server/common_services/auth_server.js b/src/server/common_services/auth_server.js index 76cfa58012..7d39778154 100644 --- a/src/server/common_services/auth_server.js +++ b/src/server/common_services/auth_server.js @@ -3,6 +3,7 @@ const _ = require('lodash'); const bcrypt = require('bcrypt'); +const argon2 = require('argon2'); const ip_module = require('ip'); const P = require('../../util/promise'); @@ -66,7 +67,7 @@ function create_auth(req) { if (!password) return; return P.resolve() - .then(() => bcrypt.compare(password.unwrap(), target_account.password.unwrap())) + .then(() => compare_password_hash(password, target_account)) .then(match => { if (!match) { dbg.log0('password mismatch', email, system_name); @@ -157,6 +158,23 @@ function create_auth(req) { }); } +/** + * This function is verifying the password given by user + * with saved hash, either bcrypt or argon2 + */ +async function compare_password_hash(password, target_account) { + const isBcrypt = await bcrypt.compare(password.unwrap(), target_account.password.unwrap()); + if (isBcrypt) { + return true; + } + + const isArgon = await argon2.verify(target_account.password.unwrap(), password.unwrap()); + if (isArgon) { + return true; + } + return false; +} + /** * * CREATE_K8S_AUTH diff --git a/src/server/system_services/account_server.js b/src/server/system_services/account_server.js index 98a5d6be4d..c413bb3595 100644 --- a/src/server/system_services/account_server.js +++ b/src/server/system_services/account_server.js @@ -7,6 +7,7 @@ const net = require('net'); const chance = require('chance')(); const GoogleStorage = require('../../util/google_storage_wrap'); const bcrypt = require('bcrypt'); +const argon2 = require('argon2'); const server_rpc = require('../server_rpc'); const config = require('../../../config'); @@ -79,7 +80,7 @@ async function create_account(req) { if (req.rpc_params.has_login) { account.password = req.rpc_params.password; - const password_hash = await bcrypt_password(account.password.unwrap()); + const password_hash = await argon2_password(account.password.unwrap()); account.password = password_hash; } @@ -574,7 +575,7 @@ async function reset_password(req) { const params = req.rpc_params; - const password = await bcrypt_password(params.password.unwrap()); + const password = await argon2_password(params.password.unwrap()); const changes = { password: new SensitiveString(password), @@ -1334,7 +1335,7 @@ function ensure_support_account() { } console.log('CREATING SUPPORT ACCOUNT...'); - return bcrypt_password(system_store.get_server_secret()) + return argon2_password(system_store.get_server_secret()) .then(password => { const support_account = { _id: system_store.new_system_store_id(), @@ -1358,9 +1359,9 @@ function ensure_support_account() { }); } -function bcrypt_password(password) { +function argon2_password(password) { return P.resolve() - .then(() => password && bcrypt.hash(password, 10)); + .then(() => password && argon2.hash(password)); } function is_support_or_admin_or_me(system, account, target_account) { @@ -1454,7 +1455,16 @@ async function verify_authorized_account(req) { if (req.role === 'operator') { return true; } - return bcrypt.compare(req.rpc_params.verification_password.unwrap(), req.account.password.unwrap()); + // We are moving to argon2. However, if some users still have password in bcrypt hash they should be + // verified. + if (bcrypt.compare(req.rpc_params.verification_password.unwrap(), req.account.password.unwrap())) { + return true; + } + if (argon2.verify(req.account.password.unwrap(), req.rpc_params.verification_password.unwrap())) { + return true; + } + + return false; } function _list_connection_usage(account, credentials) { diff --git a/src/server/system_services/schemas/account_schema.js b/src/server/system_services/schemas/account_schema.js index 3f3a7c94d3..c6341daec5 100644 --- a/src/server/system_services/schemas/account_schema.js +++ b/src/server/system_services/schemas/account_schema.js @@ -25,7 +25,7 @@ module.exports = { // password login has_login: { type: 'boolean' }, - password: { wrapper: SensitiveString }, // bcrypted password + password: { wrapper: SensitiveString }, // bcrypted or argon2 password next_password_change: { date: true }, // default policy for new buckets diff --git a/src/tools/bcrypt_cli.js b/src/tools/bcrypt_cli.js deleted file mode 100644 index fa01f8b1d7..0000000000 --- a/src/tools/bcrypt_cli.js +++ /dev/null @@ -1,15 +0,0 @@ -/* Copyright (C) 2016 NooBaa */ -'use strict'; - -const bcrypt = require('bcrypt'); - -// This is to support shell scripts -// It is used in order to bcrypt support account password in mongo_upgrade -const password = process.argv[2] || ''; -const hash = process.argv[3] || ''; - -if (hash) { - console.log(bcrypt.compareSync(password, hash)); -} else { - console.log(bcrypt.hashSync(password, 10)); -}