diff --git a/config.js b/config.js
index 63cc9d58ab..8c743efb8c 100644
--- a/config.js
+++ b/config.js
@@ -890,6 +890,8 @@ config.NC_MASTER_KEYS_MANAGER_REFRESH_THRESHOLD = -1; // currently we want to di
config.MASTER_KEYS_EXEC_MAX_RETRIES = 3;
config.NC_DISABLE_ACCESS_CHECK = false;
+config.NC_DISABLE_HEALTH_ACCESS_CHECK = false;
+config.NC_DISABLE_POSIX_MODE_ACCESS_CHECK = true;
config.NC_DISABLE_SCHEMA_CHECK = false;
////////// GPFS //////////
diff --git a/docs/NooBaaNonContainerized/ConfigFileCustomizations.md b/docs/NooBaaNonContainerized/ConfigFileCustomizations.md
index 0e363c9319..54598f4057 100644
--- a/docs/NooBaaNonContainerized/ConfigFileCustomizations.md
+++ b/docs/NooBaaNonContainerized/ConfigFileCustomizations.md
@@ -356,14 +356,16 @@ Warning: After setting this configuration, NooBaa will skip schema validations a
```
-### 25. Disable Read/Write accessibility check -
+### 25. Disable Read accessibility check -
* Key: `NC_DISABLE_ACCESS_CHECK`
* Type: Boolean
* Default: false
-* Description: This flag will disable Read/Write accessibility validations in the following flows -
- 1. Bucket creation/update - NooBaa will not validate that the bucket owner has read/write permissions to the bucket's path.
- 2. Account creation/update - NooBaa will not validate that the account owner has read/write permissions to the account's new_buckets_path.
- Warning - setting this configuration to true might result with unexpected behavior.
+* Description: Setting this flag to true will disable Read accessibility validations in the following flows -
+ 1. Bucket creation/update - NooBaa will not validate that the bucket owner has read permissions to the bucket's path.
+ 2. Account creation/update - NooBaa will not validate that the account owner has read permissions to the account's new_buckets_path.
+ 3. Health buckets and accounts accessibility check.
+ Warning - setting this configuration to true might result with unexpected behavior.
+
* Steps:
```
1. Open /path/to/config_dir/config.json file.
@@ -372,6 +374,38 @@ Warning: After setting this configuration, NooBaa will skip schema validations a
"NC_DISABLE_ACCESS_CHECK": true
```
+### 26. Disable Read accessibility check on the Health CLI -
+* Key: `NC_DISABLE_HEALTH_ACCESS_CHECK`
+* Type: Boolean
+* Default: false
+* Description: This flag will disable Read accessibility validations in Health check of buckets and accounts.
+
+* Steps:
+ ```
+ 1. Open /path/to/config_dir/config.json file.
+ 2. Set the config key -
+ Example:
+ "NC_DISABLE_HEALTH_ACCESS_CHECK": true
+ ```
+
+### 27. Disable Read/Write POSIX mode bits check -
+* Key: `NC_DISABLE_POSIX_MODE_ACCESS_CHECK`
+* Type: Boolean
+* Default: true
+* Description: Setting this flag to false will enable Read/Write mode bits accessibility validations by in the following flows -
+ 1. Bucket creation/update - NooBaa will validate that the bucket owner has read/write permissions to the bucket's path.
+ 2. Account creation/update - NooBaa will validate that the account owner has read/write permissions to the account's new_buckets_path.
+ 3. Health buckets and accounts accessibility check.
+ Warning - This configuration is disabled by default because it's not supporting ACLs, setting this configuration to false won't support a check of the ACLs and be based only on mode bits check.
+
+* Steps:
+ ```
+ 1. Open /path/to/config_dir/config.json file.
+ 2. Set the config key -
+ Example:
+ "NC_DISABLE_POSIX_MODE_ACCESS_CHECK": false
+ ```
+
### 26. Set Endpoint process title -
* Key: `ENDPOINT_PROCESS_TITLE`
diff --git a/src/manage_nsfs/health.js b/src/manage_nsfs/health.js
index be053ee9f3..efd3fb1af1 100644
--- a/src/manage_nsfs/health.js
+++ b/src/manage_nsfs/health.js
@@ -474,12 +474,14 @@ async function is_new_buckets_path_valid(config_file_path, config_data, new_buck
}
try {
- await nb_native().fs.stat(account_fs_context, new_buckets_path);
- const accessible = await native_fs_utils.is_dir_rw_accessible(account_fs_context, new_buckets_path);
- if (!accessible) {
- const new_err = new Error('ACCESS DENIED');
- new_err.code = 'EACCES';
- throw new_err;
+ if (!_should_skip_health_access_check()) {
+ await nb_native().fs.stat(account_fs_context, new_buckets_path);
+ const accessible = await native_fs_utils.is_dir_accessible(account_fs_context, new_buckets_path);
+ if (!accessible) {
+ const new_err = new Error('ACCESS DENIED');
+ new_err.code = 'EACCES';
+ throw new_err;
+ }
}
res_obj = get_valid_object(config_data.name, undefined, new_buckets_path);
} catch (err) {
@@ -505,7 +507,9 @@ async function is_new_buckets_path_valid(config_file_path, config_data, new_buck
async function is_bucket_storage_path_exists(fs_context, config_data, storage_path) {
let res_obj;
try {
- await nb_native().fs.stat(fs_context, storage_path);
+ if (!_should_skip_health_access_check()) {
+ await nb_native().fs.stat(fs_context, storage_path);
+ }
res_obj = get_valid_object(config_data.name, undefined, storage_path);
} catch (err) {
let err_code;
@@ -556,5 +560,13 @@ function get_invalid_object(name, config_path, storage_path, err_code) {
};
}
+/**
+ * _should_skip_access_check returns true if the health CLI should skip access check
+ * @returns {Boolean}
+ */
+function _should_skip_health_access_check() {
+ return config.NC_DISABLE_HEALTH_ACCESS_CHECK || config.NC_DISABLE_ACCESS_CHECK;
+}
+
exports.get_health_status = get_health_status;
exports.NSFSHealth = NSFSHealth;
diff --git a/src/manage_nsfs/manage_nsfs_validations.js b/src/manage_nsfs/manage_nsfs_validations.js
index 563e62cc39..3f86bc6c0c 100644
--- a/src/manage_nsfs/manage_nsfs_validations.js
+++ b/src/manage_nsfs/manage_nsfs_validations.js
@@ -359,9 +359,11 @@ async function validate_bucket_args(config_fs, data, action) {
await check_new_name_exists(TYPES.BUCKET, config_fs, action, data);
// in case we have the fs_backend it changes the fs_context that we use for the path
const fs_context_fs_backend = native_fs_utils.get_process_fs_context(data.fs_backend);
- const exists = await native_fs_utils.is_path_exists(fs_context_fs_backend, data.path);
- if (!exists) {
- throw_cli_error(ManageCLIError.InvalidStoragePath, data.path);
+ if (!config.NC_DISABLE_ACCESS_CHECK) {
+ const exists = await native_fs_utils.is_path_exists(fs_context_fs_backend, data.path);
+ if (!exists) {
+ throw_cli_error(ManageCLIError.InvalidStoragePath, data.path);
+ }
}
// bucket owner account validations
@@ -369,7 +371,7 @@ async function validate_bucket_args(config_fs, data, action) {
const account_fs_context = await native_fs_utils.get_fs_context(owner_account_data.nsfs_account_config,
owner_account_data.nsfs_account_config.fs_backend);
if (!config.NC_DISABLE_ACCESS_CHECK) {
- const accessible = await native_fs_utils.is_dir_rw_accessible(account_fs_context, data.path);
+ const accessible = await native_fs_utils.is_dir_accessible(account_fs_context, data.path);
if (!accessible) {
throw_cli_error(ManageCLIError.InaccessibleStoragePath, data.path);
}
@@ -454,13 +456,15 @@ async function validate_account_args(config_fs, data, action, is_flag_iam_operat
}
// in case we have the fs_backend it changes the fs_context that we use for the new_buckets_path
const fs_context_fs_backend = native_fs_utils.get_process_fs_context(data.fs_backend);
- const exists = await native_fs_utils.is_path_exists(fs_context_fs_backend, data.nsfs_account_config.new_buckets_path);
- if (!exists) {
- throw_cli_error(ManageCLIError.InvalidAccountNewBucketsPath, data.nsfs_account_config.new_buckets_path);
+ if (!config.NC_DISABLE_ACCESS_CHECK) {
+ const exists = await native_fs_utils.is_path_exists(fs_context_fs_backend, data.nsfs_account_config.new_buckets_path);
+ if (!exists) {
+ throw_cli_error(ManageCLIError.InvalidAccountNewBucketsPath, data.nsfs_account_config.new_buckets_path);
+ }
}
if (!config.NC_DISABLE_ACCESS_CHECK) {
const account_fs_context = await native_fs_utils.get_fs_context(data.nsfs_account_config, data.fs_backend);
- const accessible = await native_fs_utils.is_dir_rw_accessible(account_fs_context, data.nsfs_account_config.new_buckets_path);
+ const accessible = await native_fs_utils.is_dir_accessible(account_fs_context, data.nsfs_account_config.new_buckets_path);
if (!accessible) {
throw_cli_error(ManageCLIError.InaccessibleAccountNewBucketsPath, data.nsfs_account_config.new_buckets_path);
}
diff --git a/src/sdk/config_fs.js b/src/sdk/config_fs.js
index ee3901be80..adb3dff848 100644
--- a/src/sdk/config_fs.js
+++ b/src/sdk/config_fs.js
@@ -161,7 +161,7 @@ class ConfigFS {
}
/**
- * create_config_json_file created the config.json file with the configuration data
+ * create_config_json_file creates the config.json file with the configuration data
* @param {object} data
* @returns {Promise}
*/
@@ -178,6 +178,13 @@ class ConfigFS {
await native_fs_utils.update_config_file(this.fs_context, this.config_root, this.config_json_path, data);
}
+ /**
+ * delete_config_json_file deletes the config.json file
+ * @returns {Promise}
+ */
+ async delete_config_json_file() {
+ await native_fs_utils.delete_config_file(this.fs_context, this.config_root, this.config_json_path);
+ }
/**
* get_config_data reads a config file and returns its content
diff --git a/src/server/system_services/schemas/nsfs_config_schema.js b/src/server/system_services/schemas/nsfs_config_schema.js
index aaaa9ab7fa..a0613685e8 100644
--- a/src/server/system_services/schemas/nsfs_config_schema.js
+++ b/src/server/system_services/schemas/nsfs_config_schema.js
@@ -124,7 +124,15 @@ const nsfs_node_config_schema = {
},
NC_DISABLE_ACCESS_CHECK: {
type: 'boolean',
- doc: 'indicate whether read/write access will be validated on bucket/account creation/update.'
+ doc: 'indicate whether read access will be validated on bucket/account creation/update and on the health check.'
+ },
+ NC_DISABLE_HEALTH_ACCESS_CHECK: {
+ type: 'boolean',
+ doc: 'indicate whether read access will be validated on bucket/account health check.'
+ },
+ NC_DISABLE_POSIX_MODE_ACCESS_CHECK: {
+ type: 'boolean',
+ doc: 'indicate whether posix mode read/write access will be validated on bucket/account creation/update and health check.'
},
ENDPOINT_PROCESS_TITLE: {
type: 'string',
diff --git a/src/test/unit_tests/jest_tests/test_nc_nsfs_account_cli.test.js b/src/test/unit_tests/jest_tests/test_nc_nsfs_account_cli.test.js
index 179d5ea8b8..4ddeaf30c2 100644
--- a/src/test/unit_tests/jest_tests/test_nc_nsfs_account_cli.test.js
+++ b/src/test/unit_tests/jest_tests/test_nc_nsfs_account_cli.test.js
@@ -1773,7 +1773,9 @@ describe('manage nsfs cli account flow', () => {
describe('cli account flow distinguished_name - permissions', function() {
const type = TYPES.ACCOUNT;
const config_root = path.join(tmp_fs_path, 'config_root_manage_dn');
+ const config_fs = new ConfigFS(config_root);
const new_buckets_path = path.join(tmp_fs_path, 'new_buckets_path_user_dn_test/');
+
const accounts = {
root: {
cli_options: {
@@ -1903,32 +1905,34 @@ describe('cli account flow distinguished_name - permissions', function() {
}, timeout);
it('cli account update - should fail - no permissions to new_buckets_path', async function() {
- const no_permissions_new_buckets_path = `${tmp_fs_path}/new_buckets_path_no_perm_to_owner/`;
+ const no_permissions_new_buckets_path = `${tmp_fs_path}/new_buckets_path_no_perm_to_owner1/`;
await fs_utils.create_fresh_path(no_permissions_new_buckets_path);
await fs_utils.file_must_exist(no_permissions_new_buckets_path);
- await set_path_permissions_and_owner(new_buckets_path, accounts.accessible_user.fs_options, 0o077);
+ await set_path_permissions_and_owner(no_permissions_new_buckets_path, accounts.accessible_user.fs_options, 0o000);
const action = ACTIONS.UPDATE;
const update_options = {
config_root,
- name: accounts.root.cli_options.name,
+ ...accounts.accessible_user.cli_options,
new_buckets_path: no_permissions_new_buckets_path,
};
const res = await exec_manage_cli(type, action, update_options);
expect(JSON.parse(res.stdout).error.code).toBe(ManageCLIError.InaccessibleAccountNewBucketsPath.code);
}, timeout);
- it('cli account update - should fail - no write permissions of new_buckets_path', async function() {
+ it('cli account update - should fail - posix mode write permissions of new_buckets_path', async function() {
const no_permissions_new_buckets_path = `${tmp_fs_path}/new_buckets_path_no_r_perm_to_owner/`;
await fs_utils.create_fresh_path(no_permissions_new_buckets_path);
await fs_utils.file_must_exist(no_permissions_new_buckets_path);
- await set_path_permissions_and_owner(new_buckets_path, accounts.accessible_user.fs_options, 0o477);
+ await set_path_permissions_and_owner(no_permissions_new_buckets_path, accounts.accessible_user.fs_options, 0o477);
const action = ACTIONS.UPDATE;
const update_options = {
config_root,
- name: accounts.root.cli_options.name,
+ ...accounts.accessible_user.cli_options,
new_buckets_path: no_permissions_new_buckets_path,
};
+ await config_fs.create_config_json_file(JSON.stringify({ NC_DISABLE_POSIX_MODE_ACCESS_CHECK: false }));
const res = await exec_manage_cli(type, action, update_options);
+ await config_fs.delete_config_json_file();
expect(JSON.parse(res.stdout).error.code).toBe(ManageCLIError.InaccessibleAccountNewBucketsPath.code);
}, timeout);
@@ -1936,23 +1940,42 @@ describe('cli account flow distinguished_name - permissions', function() {
const no_permissions_new_buckets_path = `${tmp_fs_path}/new_buckets_path_no_w_perm_to_owner/`;
await fs_utils.create_fresh_path(no_permissions_new_buckets_path);
await fs_utils.file_must_exist(no_permissions_new_buckets_path);
- await set_path_permissions_and_owner(new_buckets_path, accounts.accessible_user.fs_options, 0o277);
+ await set_path_permissions_and_owner(no_permissions_new_buckets_path, accounts.accessible_user.fs_options, 0o000);
const action = ACTIONS.UPDATE;
const update_options = {
config_root,
- name: accounts.root.cli_options.name,
+ ...accounts.accessible_user.cli_options,
new_buckets_path: no_permissions_new_buckets_path,
};
const res = await exec_manage_cli(type, action, update_options);
expect(JSON.parse(res.stdout).error.code).toBe(ManageCLIError.InaccessibleAccountNewBucketsPath.code);
});
+ it('cli account update - should succeed - no read permissions of new_buckets_path - NC_DISABLE_ACCESS_CHECK: true', async function() {
+ const no_permissions_new_buckets_path = `${tmp_fs_path}/new_buckets_path_no_w_perm_to_owner/`;
+ await fs_utils.create_fresh_path(no_permissions_new_buckets_path);
+ await fs_utils.file_must_exist(no_permissions_new_buckets_path);
+
+ await set_path_permissions_and_owner(no_permissions_new_buckets_path, accounts.accessible_user.fs_options, 0o000);
+ const action = ACTIONS.UPDATE;
+ const update_options = {
+ config_root,
+ ...accounts.accessible_user.cli_options,
+ new_buckets_path: no_permissions_new_buckets_path,
+ };
+ await config_fs.create_config_json_file(JSON.stringify({ NC_DISABLE_ACCESS_CHECK: true }));
+ const res = await exec_manage_cli(type, action, update_options);
+ await config_fs.delete_config_json_file();
+ assert_account(JSON.parse(res).response.reply, update_options, false);
+ });
+
it('cli account create - account cant access new_bucket_path - NC_DISABLE_ACCESS_CHECK = true', async function() {
let action = ACTIONS.ADD;
config.NC_DISABLE_ACCESS_CHECK = true;
set_nc_config_dir_in_config(config_root);
- await fs.promises.writeFile(path.join(config_root, 'config.json'), JSON.stringify({ NC_DISABLE_ACCESS_CHECK: true }));
+ await config_fs.create_config_json_file(JSON.stringify({ NC_DISABLE_ACCESS_CHECK: true }));
const res = await exec_manage_cli(type, action, accounts.inaccessible_user.cli_options);
+ await config_fs.delete_config_json_file();
expect(JSON.parse(res).response.code).toEqual(ManageCLIResponse.AccountCreated.code);
assert_account(JSON.parse(res).response.reply, { ...accounts.inaccessible_user.cli_options }, false);
action = ACTIONS.DELETE;
diff --git a/src/test/unit_tests/jest_tests/test_nc_nsfs_bucket_cli.test.js b/src/test/unit_tests/jest_tests/test_nc_nsfs_bucket_cli.test.js
index 024cb1b719..1a4cfb0818 100644
--- a/src/test/unit_tests/jest_tests/test_nc_nsfs_bucket_cli.test.js
+++ b/src/test/unit_tests/jest_tests/test_nc_nsfs_bucket_cli.test.js
@@ -113,13 +113,15 @@ describe('manage nsfs cli bucket flow', () => {
expect(JSON.parse(res.stdout).error.code).toBe(ManageCLIError.InaccessibleStoragePath.code);
});
- it('should fail - cli create bucket - owner does not have write permission to path', async () => {
+ it('should fail - cli create bucket - owner does not have posix write permission to path', async () => {
const action = ACTIONS.ADD;
const bucket_options = { config_root, ...bucket_defaults};
await fs_utils.create_fresh_path(bucket_options.path);
await fs_utils.file_must_exist(bucket_options.path);
await set_path_permissions_and_owner(bucket_options.path, account_defaults, 0o477);
+ await config_fs.create_config_json_file(JSON.stringify({ NC_DISABLE_POSIX_MODE_ACCESS_CHECK: false }));
const res = await exec_manage_cli(TYPES.BUCKET, action, bucket_options);
+ await config_fs.delete_config_json_file();
expect(JSON.parse(res.stdout).error.code).toBe(ManageCLIError.InaccessibleStoragePath.code);
});
@@ -150,9 +152,10 @@ describe('manage nsfs cli bucket flow', () => {
await fs_utils.create_fresh_path(bucket_options.path);
await fs_utils.file_must_exist(bucket_options.path);
set_nc_config_dir_in_config(config_root);
- await config_fs.create_config_json_file(JSON.stringify({ NC_DISABLE_ACCESS_CHECK: true }));
await set_path_permissions_and_owner(bucket_options.path, account_defaults, 0o000);
+ await config_fs.create_config_json_file(JSON.stringify({ NC_DISABLE_ACCESS_CHECK: true }));
const res = await exec_manage_cli(TYPES.BUCKET, action, bucket_options);
+ await config_fs.delete_config_json_file();
expect(JSON.parse(res).response.code).toEqual(ManageCLIResponse.BucketCreated.code);
});
@@ -532,7 +535,9 @@ describe('manage nsfs cli bucket flow', () => {
await fs_utils.create_fresh_path(bucket_defaults.path);
await fs_utils.file_must_exist(bucket_defaults.path);
await set_path_permissions_and_owner(bucket_defaults.path, account_defaults2, 0o477);
+ await config_fs.create_config_json_file(JSON.stringify({ NC_DISABLE_POSIX_MODE_ACCESS_CHECK: false }));
const res = await exec_manage_cli(TYPES.BUCKET, action, bucket_options);
+ await config_fs.delete_config_json_file();
expect(JSON.parse(res.stdout).error.code).toBe(ManageCLIError.InaccessibleStoragePath.code);
});
@@ -546,6 +551,18 @@ describe('manage nsfs cli bucket flow', () => {
expect(JSON.parse(res.stdout).error.code).toBe(ManageCLIError.InaccessibleStoragePath.code);
});
+ it('cli update bucket owner - owner does not have read permission to path - NC_DISABLE_ACCESS_CHECK: true', async () => {
+ const action = ACTIONS.UPDATE;
+ const bucket_options = { config_root, name: bucket_defaults.name, owner: account_defaults2.name};
+ await fs_utils.create_fresh_path(bucket_defaults.path);
+ await fs_utils.file_must_exist(bucket_defaults.path);
+ await set_path_permissions_and_owner(bucket_defaults.path, account_defaults2, 0o000);
+ await config_fs.create_config_json_file(JSON.stringify({ NC_DISABLE_ACCESS_CHECK: true }));
+ const res = await exec_manage_cli(TYPES.BUCKET, action, bucket_options);
+ await config_fs.delete_config_json_file();
+ expect(JSON.parse(res).response.code).toEqual(ManageCLIResponse.BucketUpdated.code);
+ });
+
it('cli update bucket owner - account can access path', async () => {
const action = ACTIONS.UPDATE;
const bucket_options = { config_root, name: bucket_defaults.name, owner: account_defaults2.name};
diff --git a/src/test/unit_tests/jest_tests/test_nc_nsfs_config_schema_validation.test.js b/src/test/unit_tests/jest_tests/test_nc_nsfs_config_schema_validation.test.js
index e0e8c3fffe..3e6916399c 100644
--- a/src/test/unit_tests/jest_tests/test_nc_nsfs_config_schema_validation.test.js
+++ b/src/test/unit_tests/jest_tests/test_nc_nsfs_config_schema_validation.test.js
@@ -180,6 +180,47 @@ describe('schema validation NC NSFS config', () => {
assert_validation(config_data, reason, message);
});
+ it('nsfs_config valid config disable access check', () => {
+ const config_data = { NC_DISABLE_ACCESS_CHECK: true };
+ nsfs_schema_utils.validate_nsfs_config_schema(config_data);
+ });
+
+ it('nsfs_config invalid config disable access check', () => {
+ const config_data = { NC_DISABLE_ACCESS_CHECK: 'bla' }; // string instead of boolean
+ const reason = 'Test should have failed because of wrong type ' +
+ 'NC_DISABLE_ACCESS_CHECK with string (instead of boolean)';
+ const message = 'must be boolean';
+ assert_validation(config_data, reason, message);
+ });
+
+ it('nsfs_config valid config disable health access check', () => {
+ const config_data = { NC_DISABLE_HEALTH_ACCESS_CHECK: true };
+ nsfs_schema_utils.validate_nsfs_config_schema(config_data);
+ });
+
+ it('nsfs_config invalid config disable health access check', () => {
+ const config_data = { NC_DISABLE_HEALTH_ACCESS_CHECK: 'bla' }; // string instead of boolean
+ const reason = 'Test should have failed because of wrong type ' +
+ 'NC_DISABLE_HEALTH_ACCESS_CHECK with string (instead of boolean)';
+ const message = 'must be boolean';
+ assert_validation(config_data, reason, message);
+ });
+
+ it('nsfs_config valid config disable posix access check', () => {
+ const config_data = { NC_DISABLE_POSIX_MODE_ACCESS_CHECK: false };
+ nsfs_schema_utils.validate_nsfs_config_schema(config_data);
+ });
+
+ it('nsfs_config invalid config disable posix access check', () => {
+ const config_data = {
+ NC_DISABLE_POSIX_MODE_ACCESS_CHECK: 'bla'// string instead of boolean
+ };
+ const reason = 'Test should have failed because of wrong type ' +
+ 'NC_DISABLE_POSIX_MODE_ACCESS_CHECK with string (instead of boolean)';
+ const message = 'must be boolean';
+ assert_validation(config_data, reason, message);
+ });
+
it('nsfs_config valid config virtual hosts', () => {
const config_data = {
VIRTUAL_HOSTS: 'my.virtual.domain1 my.virtual.domain2'
diff --git a/src/test/unit_tests/jest_tests/test_nc_nsfs_new_buckets_path_validation.test.js b/src/test/unit_tests/jest_tests/test_nc_nsfs_new_buckets_path_validation.test.js
index 50f5caecfd..01013beb45 100644
--- a/src/test/unit_tests/jest_tests/test_nc_nsfs_new_buckets_path_validation.test.js
+++ b/src/test/unit_tests/jest_tests/test_nc_nsfs_new_buckets_path_validation.test.js
@@ -6,9 +6,10 @@ process.env.DISABLE_INIT_RANDOM_SEED = "true";
const fs = require('fs');
const path = require('path');
+const config = require('../../../../config');
const fs_utils = require('../../../util/fs_utils');
const test_utils = require('../../system_tests/test_utils');
-const { get_fs_context, is_dir_rw_accessible } = require('../../../util/native_fs_utils');
+const { get_fs_context, is_dir_accessible } = require('../../../util/native_fs_utils');
const MAC_PLATFORM = 'darwin';
let tmp_fs_path = '/tmp/test_nc_nsfs_new_buckets_path_validation';
@@ -17,8 +18,9 @@ if (process.platform === MAC_PLATFORM) {
}
const timeout = 50000;
-describe('new_buckets_path access validation account', () => {
+describe('new_buckets_path posix mode access validation account', () => {
const new_buckets_path = path.join(tmp_fs_path, 'new_buckets_path');
+ config.NC_DISABLE_POSIX_MODE_ACCESS_CHECK = false;
const owner_user = 'owner_user';
const group_user = 'group_user';
const other_user = 'other_user';
@@ -237,7 +239,7 @@ async function set_path_permissions(path_to_change, new_path_mode) {
*/
async function path_accessible_to_account(path_to_check, account_data, is_accessible) {
const fs_context = await get_fs_context(account_data);
- const accessible = await is_dir_rw_accessible(fs_context, path_to_check);
+ const accessible = await is_dir_accessible(fs_context, path_to_check);
if (is_accessible) {
expect(accessible).toBe(true);
} else {
diff --git a/src/test/unit_tests/test_nc_nsfs_health.js b/src/test/unit_tests/test_nc_nsfs_health.js
index 9c6aca62d9..a708e515c8 100644
--- a/src/test/unit_tests/test_nc_nsfs_health.js
+++ b/src/test/unit_tests/test_nc_nsfs_health.js
@@ -7,6 +7,7 @@ const path = require('path');
const mocha = require('mocha');
const sinon = require('sinon');
const assert = require('assert');
+const config = require('../../../config');
const fs_utils = require('../../util/fs_utils');
const nb_native = require('../../util/nb_native');
const { ConfigFS } = require('../../sdk/config_fs');
@@ -326,7 +327,8 @@ mocha.describe('nsfs nc health', function() {
mocha.it('Account with inaccessible path - uid gid', async function() {
await config_fs.create_config_json_file(JSON.stringify({ NC_DISABLE_ACCESS_CHECK: true }));
- await exec_manage_cli(TYPES.ACCOUNT, ACTIONS.ADD, { config_root, ...account_inaccessible_options});
+ await exec_manage_cli(TYPES.ACCOUNT, ACTIONS.ADD, { config_root, ...account_inaccessible_options });
+ await config_fs.delete_config_json_file();
Health.get_service_state.restore();
Health.get_endpoint_response.restore();
Health.all_account_details = true;
@@ -345,6 +347,56 @@ mocha.describe('nsfs nc health', function() {
await exec_manage_cli(TYPES.ACCOUNT, ACTIONS.DELETE, { config_root, name: account_inaccessible_options.name});
});
+ mocha.it('Account with inaccessible path - uid gid - NC_DISABLE_ACCESS_CHECK: true - should be valid', async function() {
+ await config_fs.create_config_json_file(JSON.stringify({ NC_DISABLE_ACCESS_CHECK: true }));
+ await exec_manage_cli(TYPES.ACCOUNT, ACTIONS.ADD, { config_root, debug: 5, ...account_inaccessible_options});
+ await config_fs.delete_config_json_file();
+ Health.get_service_state.restore();
+ Health.get_endpoint_response.restore();
+ Health.all_account_details = true;
+ Health.all_bucket_details = true;
+ const get_service_state = sinon.stub(Health, "get_service_state");
+ get_service_state.onFirstCall().returns(Promise.resolve({ service_status: 'active', pid: 1000 }))
+ .onSecondCall().returns(Promise.resolve({ service_status: 'active', pid: 2000 }));
+ const get_endpoint_response = sinon.stub(Health, "get_endpoint_response");
+ get_endpoint_response.onFirstCall().returns(Promise.resolve({response: {response_code: 'RUNNING', total_fork_count: 0}}));
+ config.NC_DISABLE_ACCESS_CHECK = true;
+ const health_status = await Health.nc_nsfs_health();
+ config.NC_DISABLE_ACCESS_CHECK = false;
+ await exec_manage_cli(TYPES.ACCOUNT, ACTIONS.DELETE, { config_root, name: account_inaccessible_options.name});
+ assert.strictEqual(health_status.checks.buckets_status.valid_buckets.length, 1);
+ assert.strictEqual(health_status.checks.accounts_status.valid_accounts.length, 2);
+ assert.strictEqual(health_status.checks.accounts_status.invalid_accounts.length, 0);
+ const inaccessible_is_valid = health_status.checks.accounts_status.valid_accounts.find(account =>
+ account.name === account_inaccessible_options.name);
+ assert.strictEqual(inaccessible_is_valid.storage_path, account_inaccessible_options.new_buckets_path);
+ });
+
+ mocha.it('Account with inaccessible path - uid gid - NC_DISABLE_HEALTH_ACCESS_CHECK: true - should be valid', async function() {
+ await config_fs.create_config_json_file(JSON.stringify({ NC_DISABLE_ACCESS_CHECK: true }));
+ await exec_manage_cli(TYPES.ACCOUNT, ACTIONS.ADD, { config_root, ...account_inaccessible_options });
+ await config_fs.delete_config_json_file();
+ Health.get_service_state.restore();
+ Health.get_endpoint_response.restore();
+ Health.all_account_details = true;
+ Health.all_bucket_details = true;
+ const get_service_state = sinon.stub(Health, "get_service_state");
+ get_service_state.onFirstCall().returns(Promise.resolve({ service_status: 'active', pid: 1000 }))
+ .onSecondCall().returns(Promise.resolve({ service_status: 'active', pid: 2000 }));
+ const get_endpoint_response = sinon.stub(Health, "get_endpoint_response");
+ get_endpoint_response.onFirstCall().returns(Promise.resolve({response: {response_code: 'RUNNING', total_fork_count: 0}}));
+ config.NC_DISABLE_HEALTH_ACCESS_CHECK = true;
+ const health_status = await Health.nc_nsfs_health();
+ config.NC_DISABLE_HEALTH_ACCESS_CHECK = false;
+ await exec_manage_cli(TYPES.ACCOUNT, ACTIONS.DELETE, { config_root, name: account_inaccessible_options.name });
+ assert.strictEqual(health_status.checks.buckets_status.valid_buckets.length, 1);
+ assert.strictEqual(health_status.checks.accounts_status.valid_accounts.length, 2);
+ assert.strictEqual(health_status.checks.accounts_status.invalid_accounts.length, 0);
+ const inaccessible_is_valid = health_status.checks.accounts_status.valid_accounts.find(account =>
+ account.name === account_inaccessible_options.name);
+ assert.strictEqual(inaccessible_is_valid.storage_path, account_inaccessible_options.new_buckets_path);
+ });
+
mocha.it('Account with inaccessible path - dn', async function() {
await config_fs.create_config_json_file(JSON.stringify({ NC_DISABLE_ACCESS_CHECK: true }));
await exec_manage_cli(TYPES.ACCOUNT, ACTIONS.ADD, { config_root, ...account_inaccessible_dn_options });
@@ -358,12 +410,60 @@ mocha.describe('nsfs nc health', function() {
const get_endpoint_response = sinon.stub(Health, "get_endpoint_response");
get_endpoint_response.onFirstCall().returns(Promise.resolve({response: {response_code: 'RUNNING', total_fork_count: 0}}));
const health_status = await Health.nc_nsfs_health();
+ await exec_manage_cli(TYPES.ACCOUNT, ACTIONS.DELETE, { config_root, name: account_inaccessible_dn_options.name });
assert.strictEqual(health_status.checks.buckets_status.valid_buckets.length, 1);
assert.strictEqual(health_status.checks.accounts_status.valid_accounts.length, 1);
assert.strictEqual(health_status.checks.accounts_status.invalid_accounts.length, 1);
assert.strictEqual(health_status.checks.accounts_status.invalid_accounts[0].code, "ACCESS_DENIED");
assert.strictEqual(health_status.checks.accounts_status.invalid_accounts[0].name, account_inaccessible_dn_options.name);
+ });
+
+ mocha.it('Account with inaccessible path - dn - NC_DISABLE_ACCESS_CHECK: true - should be valid', async function() {
+ await config_fs.create_config_json_file(JSON.stringify({ NC_DISABLE_ACCESS_CHECK: true }));
+ await exec_manage_cli(TYPES.ACCOUNT, ACTIONS.ADD, { config_root, ...account_inaccessible_dn_options });
+ Health.get_service_state.restore();
+ Health.get_endpoint_response.restore();
+ Health.all_account_details = true;
+ Health.all_bucket_details = true;
+ const get_service_state = sinon.stub(Health, "get_service_state");
+ get_service_state.onFirstCall().returns(Promise.resolve({ service_status: 'active', pid: 1000 }))
+ .onSecondCall().returns(Promise.resolve({ service_status: 'active', pid: 2000 }));
+ const get_endpoint_response = sinon.stub(Health, "get_endpoint_response");
+ get_endpoint_response.onFirstCall().returns(Promise.resolve({ response: { response_code: 'RUNNING', total_fork_count: 0 } }));
+ config.NC_DISABLE_ACCESS_CHECK = true;
+ const health_status = await Health.nc_nsfs_health();
+ config.NC_DISABLE_ACCESS_CHECK = false;
+ await exec_manage_cli(TYPES.ACCOUNT, ACTIONS.DELETE, { config_root, name: account_inaccessible_dn_options.name });
+ assert.strictEqual(health_status.checks.buckets_status.valid_buckets.length, 1);
+ assert.strictEqual(health_status.checks.accounts_status.valid_accounts.length, 2);
+ assert.strictEqual(health_status.checks.accounts_status.invalid_accounts.length, 0);
+ const inaccessible_is_valid = health_status.checks.accounts_status.valid_accounts.find(account =>
+ account.name === account_inaccessible_dn_options.name);
+ assert.strictEqual(inaccessible_is_valid.storage_path, account_inaccessible_dn_options.new_buckets_path);
+ });
+
+ mocha.it('Account with inaccessible path - dn - NC_DISABLE_HEALTH_ACCESS_CHECK: true - should be valid', async function() {
+ await config_fs.create_config_json_file(JSON.stringify({ NC_DISABLE_ACCESS_CHECK: true }));
+ await exec_manage_cli(TYPES.ACCOUNT, ACTIONS.ADD, { config_root, ...account_inaccessible_dn_options });
+ Health.get_service_state.restore();
+ Health.get_endpoint_response.restore();
+ Health.all_account_details = true;
+ Health.all_bucket_details = true;
+ const get_service_state = sinon.stub(Health, "get_service_state");
+ get_service_state.onFirstCall().returns(Promise.resolve({ service_status: 'active', pid: 1000 }))
+ .onSecondCall().returns(Promise.resolve({ service_status: 'active', pid: 2000 }));
+ const get_endpoint_response = sinon.stub(Health, "get_endpoint_response");
+ get_endpoint_response.onFirstCall().returns(Promise.resolve({ response: { response_code: 'RUNNING', total_fork_count: 0 } }));
+ config.NC_DISABLE_HEALTH_ACCESS_CHECK = true;
+ const health_status = await Health.nc_nsfs_health();
+ config.NC_DISABLE_HEALTH_ACCESS_CHECK = false;
await exec_manage_cli(TYPES.ACCOUNT, ACTIONS.DELETE, { config_root, name: account_inaccessible_dn_options.name });
+ assert.strictEqual(health_status.checks.buckets_status.valid_buckets.length, 1);
+ assert.strictEqual(health_status.checks.accounts_status.valid_accounts.length, 2);
+ assert.strictEqual(health_status.checks.accounts_status.invalid_accounts.length, 0);
+ const inaccessible_is_valid = health_status.checks.accounts_status.valid_accounts.find(account =>
+ account.name === account_inaccessible_dn_options.name);
+ assert.strictEqual(inaccessible_is_valid.storage_path, account_inaccessible_dn_options.new_buckets_path);
});
mocha.it('Account with invalid dn', async function() {
@@ -402,10 +502,10 @@ mocha.describe('nsfs nc health', function() {
const get_endpoint_response = sinon.stub(Health, "get_endpoint_response");
get_endpoint_response.onFirstCall().returns(Promise.resolve({response: {response_code: 'RUNNING', total_fork_count: 0}}));
const health_status = await Health.nc_nsfs_health();
+ await exec_manage_cli(TYPES.ACCOUNT, ACTIONS.DELETE, { config_root, name: account_valid.name });
assert.strictEqual(health_status.checks.accounts_status.valid_accounts.length, 1);
assert.strictEqual(health_status.checks.accounts_status.invalid_accounts.length, 1);
assert.strictEqual(health_status.checks.accounts_status.invalid_accounts[0].name, account_valid.name);
- await exec_manage_cli(TYPES.ACCOUNT, ACTIONS.DELETE, { config_root, name: account_valid.name });
});
mocha.it('Account with new_buckets_path missing and allow_bucket_creation true, invalid account', async function() {
diff --git a/src/util/native_fs_utils.js b/src/util/native_fs_utils.js
index 547c72657f..81ad1be49e 100644
--- a/src/util/native_fs_utils.js
+++ b/src/util/native_fs_utils.js
@@ -535,19 +535,24 @@ async function is_path_exists(fs_context, config_path, use_lstat = false) {
}
/**
- * is_dir_rw_accessible validate the dir param accessible for read and write
+ * is_dir_accessible validate the dir param accessible for read by default
+ * if NC_DISABLE_POSIX_MODE_ACCESS_CHECK=false a read and write access check
+ * will be executed by checking mode bits
* @param {nb.NativeFSContext} fs_context
* @param {string} dir_path
* @returns {Promise}
*/
/* eslint-disable no-bitwise */
-async function is_dir_rw_accessible(fs_context, dir_path) {
+async function is_dir_accessible(fs_context, dir_path) {
let stat;
try {
stat = await nb_native().fs.stat(fs_context, dir_path);
} catch (err) {
return false;
}
+
+ if (config.NC_DISABLE_POSIX_MODE_ACCESS_CHECK) return true;
+
const is_owner = fs_context.uid === stat.uid;
const is_group = fs_context.gid === stat.gid;
@@ -686,7 +691,7 @@ exports.get_process_fs_context = get_process_fs_context;
exports.get_fs_context = get_fs_context;
exports.validate_bucket_creation = validate_bucket_creation;
exports.is_path_exists = is_path_exists;
-exports.is_dir_rw_accessible = is_dir_rw_accessible;
+exports.is_dir_accessible = is_dir_accessible;
exports.folder_delete = folder_delete;
exports.unlink_ignore_enoent = unlink_ignore_enoent;
exports.get_bucket_tmpdir_full_path = get_bucket_tmpdir_full_path;