hash passwords and API keys in main config#3257
Conversation
|
|
There was a problem hiding this comment.
Pull request overview
This PR secures Caldera’s main configuration by hashing stored user passwords and red/blue API keys with Argon2, and updating authentication flows to verify hashes instead of plaintext comparisons.
Changes:
- Introduces
app/utility/config_util.pyto generate secure local configs and to hash/verify config credentials (Argon2). - Extends
BaseWorld.apply_config()withapply_hash/overwrite_pathto hash sensitive fields and optionally rewrite the source config file. - Updates auth/login logic and tests to operate on hashed credentials; adds
argon2-cffidependency.
Reviewed changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/web_server/test_core_endpoints.py | Loads main config with hashing enabled in web server tests |
| tests/utility/test_config_util.py | Adds unit tests for hashing/verification and local config generation |
| tests/services/test_rest_svc.py | Updates test config setup to use apply_hash=True |
| tests/conftest.py | Ensures session-wide test config is hashed when applied |
| tests/api/v2/test_security.py | Updates security tests to apply hashed config |
| tests/api/v2/test_responses.py | Updates response middleware tests to apply hashed config |
| tests/api/v2/test_knowledge.py | Updates knowledge API tests to apply hashed config |
| tests/api/v2/managers/test_config_api_manager.py | Updates config manager tests to apply hashed main config |
| server.py | Switches to new config utility + hashes/overwrites config on startup |
| requirements.txt | Adds argon2-cffi dependency |
| app/utility/config_util.py | New hashing/verification + secure config generation utilities |
| app/utility/config_generator.py | Removes previous config generator implementation |
| app/utility/base_world.py | Adds config hashing + optional overwrite support in apply_config |
| app/service/login_handlers/default.py | Uses hash verification for password checks |
| app/service/auth_svc.py | Uses hash verification for API key authentication |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| ph = PasswordHasher() | ||
| try: | ||
| return ph.verify(hash_val, target) | ||
| except (VerifyMismatchError, VerificationError, InvalidHashError): |
| if changes_made and overwrite_path: | ||
| logging.debug(f'Overwriting config file {overwrite_path} with secure values') | ||
| with open(overwrite_path, 'w') as cfg_file: | ||
| cfg_file.write(yaml.dump(config)) |
| with open(overwrite_path, 'w') as cfg_file: | ||
| cfg_file.write(yaml.dump(config)) |
| hash = '$argon2id$v=19$m=65536,t=3,p=4$87lgOXDGx/9JUHuCsxlaZw$bcJp3dQcqMiYdZOCm8LLJ8ncaEwjoS1xVcPHUGs/ajU' | ||
| plaintext = 'testpassword' | ||
| assert verify_hash(hash, plaintext) | ||
| assert not verify_hash(hash, 'testpassword2') |
| BaseWorld.apply_config("main", BaseWorld.strip_yml(main_config_path)[0], apply_hash=True, | ||
| overwrite_path=main_config_path) |
| elif verify_hash(self.get_config(CONFIG_API_KEY_RED), request.headers.get(HEADER_API_KEY)): | ||
| return self.Access.RED, self.Access.APP | ||
| elif request.headers.get(HEADER_API_KEY) == self.get_config(CONFIG_API_KEY_BLUE): | ||
| elif verify_hash(self.get_config(CONFIG_API_KEY_BLUE), request.headers.get(HEADER_API_KEY)): | ||
| return self.Access.BLUE, self.Access.APP |
There was a problem hiding this comment.
Pull request overview
This PR hardens Caldera’s main configuration handling by Argon2-hashing stored user passwords and primary API keys, optionally overwriting the on-disk config with the hashed values, and updating authentication to verify via hashes.
Changes:
- Introduces
app.utility.config_utilwith Argon2 hashing/verification and secure local config generation. - Updates config loading (
BaseWorld.apply_config,server.py) to hash credentials on startup and optionally rewrite config files. - Updates auth/login code paths and tests to expect and validate hashed passwords/API keys.
Reviewed changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| app/utility/config_util.py | New hashing/verification utilities + secure local config generation. |
| app/utility/config_generator.py | Removed legacy local config generator (replaced by config_util). |
| app/utility/base_world.py | Adds apply_hash + optional config overwrite-on-hash behavior. |
| app/service/auth_svc.py | Switches API key checks from plaintext compare to Argon2 verification. |
| app/service/login_handlers/default.py | Switches password checks from plaintext compare to Argon2 verification. |
| server.py | Uses ensure_local_config from new module; hashes main config on load and overwrites when needed. |
| requirements.txt | Adds argon2-cffi dependency. |
| tests/utility/test_config_util.py | New unit tests for hashing/verification and local config generation. |
| tests/conftest.py | Loads main config with apply_hash=True in fixtures. |
| tests/web_server/test_core_endpoints.py | Loads main config with apply_hash=True for endpoint tests. |
| tests/services/test_rest_svc.py | Applies main config with hashing enabled in rest service tests. |
| tests/api/v2/test_security.py | Applies config with hashing enabled in API v2 security tests. |
| tests/api/v2/test_responses.py | Applies config with hashing enabled in API v2 response tests. |
| tests/api/v2/test_knowledge.py | Applies config with hashing enabled in API v2 knowledge tests. |
| tests/api/v2/managers/test_config_api_manager.py | Applies main config with hashing enabled in config API manager tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| async def get_permissions(self, request): | ||
| identity_policy = request.config_dict.get('aiohttp_security_identity_policy') | ||
| identity = await identity_policy.identify(request) | ||
| if identity in self.user_map: | ||
| return [self.Access[p.upper()] for p in self.user_map[identity].permissions] | ||
| elif request.headers.get(HEADER_API_KEY) == self.get_config(CONFIG_API_KEY_RED): | ||
| elif verify_hash(self.get_config(CONFIG_API_KEY_RED), request.headers.get(HEADER_API_KEY)): | ||
| return self.Access.RED, self.Access.APP | ||
| elif request.headers.get(HEADER_API_KEY) == self.get_config(CONFIG_API_KEY_BLUE): | ||
| elif verify_hash(self.get_config(CONFIG_API_KEY_BLUE), request.headers.get(HEADER_API_KEY)): | ||
| return self.Access.BLUE, self.Access.APP |
| ph = PasswordHasher() | ||
| try: | ||
| return ph.verify(hash_val, target) | ||
| except (VerifyMismatchError, VerificationError, InvalidHashError): |
| # Hash credentials | ||
| for group_name, group_dict in config.get('users', dict()).items(): | ||
| for username, val in group_dict.items(): | ||
| if not _is_hashed(val): | ||
| config['users'][group_name][username] = ph.hash(val) | ||
| any_hashed = True |
| if apply_hash: | ||
| changes_made = hash_config_creds(config) | ||
| if changes_made and overwrite_path: | ||
| logging.debug(f'Overwriting config file {overwrite_path} with secure values') | ||
| with open(overwrite_path, 'w') as cfg_file: | ||
| cfg_file.write(yaml.dump(config)) |
| def request_has_valid_api_key(self, request): | ||
| request_api_key = request.headers.get(HEADER_API_KEY) | ||
| if request_api_key is None: | ||
| return False | ||
| for i in [CONFIG_API_KEY_RED, CONFIG_API_KEY_BLUE]: | ||
| api_key = self.get_config(i) | ||
| if api_key is not None and compare_digest(request_api_key, api_key): | ||
| hashed_api_key = self.get_config(i) | ||
| if hashed_api_key is not None and verify_hash(hashed_api_key, request_api_key): | ||
| return True | ||
| return False |
| hash = '$argon2id$v=19$m=65536,t=3,p=4$87lgOXDGx/9JUHuCsxlaZw$bcJp3dQcqMiYdZOCm8LLJ8ncaEwjoS1xVcPHUGs/ajU' | ||
| plaintext = 'testpassword' | ||
| assert verify_hash(hash, plaintext) | ||
| assert not verify_hash(hash, 'testpassword2') |
There was a problem hiding this comment.
Pull request overview
This PR strengthens Caldera’s configuration security by hashing user passwords and primary API keys (red/blue) using Argon2, updating startup/config generation flows accordingly, and adjusting authentication to verify hashes rather than compare plaintext.
Changes:
- Introduces
config_utilwith Argon2 hashing + verification helpers and updates local config generation. - Extends
BaseWorld.apply_configto optionally hash credentials and overwrite config files with hashed values on startup. - Updates auth/login logic and tests to work with hashed credentials and API keys.
Reviewed changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/web_server/test_core_endpoints.py | Loads main config with hashing enabled for endpoint tests. |
| tests/utility/test_config_util.py | Adds unit tests for hashing/verification and local config generation. |
| tests/services/test_rest_svc.py | Updates test config loading to pass apply_hash=True. |
| tests/conftest.py | Ensures test fixtures load hashed main config. |
| tests/api/v2/test_security.py | Updates security tests to load hashed users/API key. |
| tests/api/v2/test_responses.py | Updates responses tests to load hashed users. |
| tests/api/v2/test_knowledge.py | Updates knowledge tests to load hashed main config. |
| tests/api/v2/managers/test_config_api_manager.py | Updates config manager tests to hash main config on load. |
| server.py | Uses new config_util.ensure_local_config and overwrites main config with hashed values at startup. |
| requirements.txt | Adds argon2-cffi dependency pin. |
| app/utility/config_util.py | New module implementing Argon2 hashing/verification and secure local.yml generation. |
| app/utility/config_generator.py | Removes old config generator implementation. |
| app/utility/base_world.py | Adds apply_hash + overwrite_path behavior for config hashing and rewrite. |
| app/service/login_handlers/default.py | Verifies passwords via Argon2 hash instead of plaintext compare. |
| app/service/auth_svc.py | Verifies API keys via Argon2 hash instead of constant-time plaintext compare. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if changes_made and overwrite_path: | ||
| logging.debug(f'Overwriting config file {overwrite_path} with secure values') | ||
| with open(overwrite_path, 'w') as cfg_file: | ||
| cfg_file.write(yaml.dump(config)) |
| blue=dict(blue=secrets.token_urlsafe())) | ||
|
|
||
| # Display API keys and user credentials, then hash them | ||
| logging.info(CONFIG_MSG_TEMPLATE.render(config_path=LOCAL_CONF_PATH, **config)) |
| elif verify_hash(self.get_config(CONFIG_API_KEY_RED), request.headers.get(HEADER_API_KEY)): | ||
| return self.Access.RED, self.Access.APP | ||
| elif request.headers.get(HEADER_API_KEY) == self.get_config(CONFIG_API_KEY_BLUE): | ||
| elif verify_hash(self.get_config(CONFIG_API_KEY_BLUE), request.headers.get(HEADER_API_KEY)): | ||
| return self.Access.BLUE, self.Access.APP |
| def request_has_valid_api_key(self, request): | ||
| request_api_key = request.headers.get(HEADER_API_KEY) | ||
| if request_api_key is None: | ||
| return False | ||
| for i in [CONFIG_API_KEY_RED, CONFIG_API_KEY_BLUE]: | ||
| api_key = self.get_config(i) | ||
| if api_key is not None and compare_digest(request_api_key, api_key): | ||
| hashed_api_key = self.get_config(i) | ||
| if hashed_api_key is not None and verify_hash(hashed_api_key, request_api_key): | ||
| return True | ||
| return False |
| ph = PasswordHasher() | ||
| try: | ||
| return ph.verify(hash_val, target) | ||
| except (VerifyMismatchError, VerificationError, InvalidHashError): |
|
|
||
|
|
||
| def _is_hashed(val): | ||
| return val.startswith('$argon2id$') |
There was a problem hiding this comment.
Pull request overview
This PR hardens Caldera’s configuration handling by Argon2-hashing user passwords and red/blue API keys, rewriting configs on startup with hashed values, and updating authentication checks to verify hashes instead of comparing plaintext.
Changes:
- Add
app.utility.config_utilwith helpers to hash credentials, verify Argon2 hashes, and generate a secureconf/local.yml. - Update server startup and tests to apply config hashing (
apply_hash=True) and overwrite configs with hashed secrets. - Update auth and default login flows to validate API keys/passwords via Argon2 verification; add Argon2 dependency and unit tests.
Reviewed changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/web_server/test_core_endpoints.py | Loads main config with hashing enabled in web server tests. |
| tests/utility/test_config_util.py | Adds unit tests for hashing/verification and local config generation. |
| tests/services/test_rest_svc.py | Updates test config loading to hash secrets. |
| tests/conftest.py | Ensures session/app fixtures hash main config on load. |
| tests/api/v2/test_security.py | Updates BaseWorld config setup to hash secrets. |
| tests/api/v2/test_responses.py | Updates BaseWorld config setup to hash secrets. |
| tests/api/v2/test_knowledge.py | Updates BaseWorld config setup to hash secrets. |
| tests/api/v2/managers/test_config_api_manager.py | Ensures main config is hashed for manager tests. |
| server.py | Switches secure-config helper import and overwrites main config with hashed values on startup. |
| requirements.txt | Adds argon2-cffi dependency pin. |
| app/utility/config_util.py | New hashing/verification + secure local.yml generation logic. |
| app/utility/config_generator.py | Removes old local config generator in favor of config_util. |
| app/utility/base_world.py | Extends apply_config to hash secrets and optionally overwrite config files. |
| app/service/login_handlers/default.py | Switches password validation to Argon2 verification. |
| app/service/auth_svc.py | Switches API key validation to Argon2 verification. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| def verify_hash(hash_val, target): | ||
| """ | ||
| Returns True if the argon2 hash for the target matches hash_val, False otherwise. | ||
| """ | ||
| ph = PasswordHasher() | ||
| try: | ||
| return ph.verify(hash_val, target) | ||
| except (VerifyMismatchError, VerificationError, InvalidHashError): | ||
| return False |
| assert verify_hash(config['users']['group2']['user2'], 'testpassword2') | ||
|
|
||
| @mock.patch.object(PasswordHasher, 'hash', return_value='mockhash') | ||
| @mock.patch.object(yaml, 'safe_load', return_value=SENSITIVE_CONF) |
| hash = '$argon2id$v=19$m=65536,t=3,p=4$87lgOXDGx/9JUHuCsxlaZw$bcJp3dQcqMiYdZOCm8LLJ8ncaEwjoS1xVcPHUGs/ajU' | ||
| plaintext = 'testpassword' | ||
| assert verify_hash(hash, plaintext) | ||
| assert not verify_hash(hash, 'testpassword2') |
| elif verify_hash(self.get_config(CONFIG_API_KEY_RED), request.headers.get(HEADER_API_KEY)): | ||
| return self.Access.RED, self.Access.APP | ||
| elif request.headers.get(HEADER_API_KEY) == self.get_config(CONFIG_API_KEY_BLUE): | ||
| elif verify_hash(self.get_config(CONFIG_API_KEY_BLUE), request.headers.get(HEADER_API_KEY)): | ||
| return self.Access.BLUE, self.Access.APP |
| if changes_made and overwrite_path: | ||
| logging.debug(f'Overwriting config file {overwrite_path} with secure values') | ||
| with open(overwrite_path, 'w') as cfg_file: | ||
| cfg_file.write(yaml.dump(config)) |
| logging.debug(f'Overwriting config file {overwrite_path} with secure values') | ||
| with open(overwrite_path, 'w') as cfg_file: | ||
| cfg_file.write(yaml.dump(config)) |
|
|
||
| logging.info('Creating new secure config in %s' % local_conf_path) | ||
| with local_conf_path.open('w') as fle: | ||
| yaml.safe_dump(make_secure_config(), fle, default_flow_style=False) |
| # Display API keys and user credentials, then hash them | ||
| logging.info(CONFIG_MSG_TEMPLATE.render(config_path=LOCAL_CONF_PATH, **config)) | ||
| hash_config_creds(config) |
There was a problem hiding this comment.
Pull request overview
This PR addresses plaintext storage of user passwords and primary API keys in Caldera config by hashing credentials (Argon2) and updating authentication checks to verify hashes instead of doing plaintext comparisons.
Changes:
- Introduces
app.utility.config_utilfor hashing/verifying credentials and securely generatingconf/local.yml. - Updates auth/login logic to verify API keys and passwords against stored Argon2 hashes.
- Updates config loading paths/tests to hash credentials on load and optionally overwrite config files with hashed values.
Reviewed changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/web_server/test_core_endpoints.py | Loads main config with hashing enabled for web server endpoint tests. |
| tests/utility/test_config_util.py | Adds unit tests for hashing/verification and secure config generation behavior. |
| tests/services/test_rest_svc.py | Applies main config with hashing enabled in REST service tests. |
| tests/conftest.py | Applies hashed main config for shared test fixtures. |
| tests/api/v2/test_security.py | Applies hashed main config in v2 security tests. |
| tests/api/v2/test_responses.py | Applies hashed main config in v2 response tests. |
| tests/api/v2/test_knowledge.py | Applies hashed main config in v2 knowledge tests. |
| tests/api/v2/managers/test_config_api_manager.py | Applies hashed main config in config manager tests. |
| server.py | Switches to config_util.ensure_local_config and overwrites main config with hashed secrets on startup. |
| requirements.txt | Adds Argon2 dependency. |
| app/utility/config_util.py | New utility for hashing/verifying secrets and generating secure local config. |
| app/utility/config_generator.py | Removes legacy config generator (replaced by config_util). |
| app/utility/base_world.py | Adds options to hash credentials and overwrite the on-disk config when changes are made. |
| app/service/login_handlers/default.py | Updates password checks to use hash verification. |
| app/service/auth_svc.py | Updates API key checks and permissions resolution to use hash verification. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| CONFIG_MSG_TEMPLATE = jinja2.Template(""" | ||
| Log into Caldera with the following admin credentials: | ||
| Red: | ||
| {%- if users.red.red %} | ||
| USERNAME: red | ||
| PASSWORD: {{ users.red.red }} | ||
| {%- endif %} | ||
| API_TOKEN: {{ api_key_red }} | ||
| Blue: | ||
| {%- if users.blue.blue %} | ||
| USERNAME: blue | ||
| PASSWORD: {{ users.blue.blue }} | ||
| {%- endif %} | ||
| API_TOKEN: {{ api_key_blue }} | ||
| To modify these values, edit the {{ config_path }} file and restart Caldera. | ||
| """) |
| blue=dict(blue=secrets.token_urlsafe())) | ||
|
|
||
| # Display API keys and user credentials, then hash them | ||
| logging.info(CONFIG_MSG_TEMPLATE.render(config_path=LOCAL_CONF_PATH, **config)) |
| ph = PasswordHasher() | ||
| try: | ||
| return ph.verify(hash_val, target) |
| Modifies the configuration dictionary parameter. | ||
| Returns True if any values were modified (hashed), False otherwise. | ||
| """ | ||
| ph = PasswordHasher() |
| if val and not _is_hashed(val): | ||
| config[option] = ph.hash(val) | ||
| any_hashed = True | ||
|
|
||
| # Hash credentials | ||
| for group_name, group_dict in config.get('users', dict()).items(): | ||
| for username, val in group_dict.items(): | ||
| if not _is_hashed(val): |
|
|
||
| @staticmethod | ||
| def apply_config(name, config): | ||
| def apply_config(name, config, apply_hash=False, overwrite_path=''): |
| if apply_hash: | ||
| changes_made = hash_config_creds(config) | ||
| if changes_made and overwrite_path: | ||
| logging.debug(f'Overwriting config file {overwrite_path} with secure values') | ||
| with open(overwrite_path, 'w') as cfg_file: | ||
| yaml.safe_dump(config, cfg_file, default_flow_style=False) |
…nfig overwrite - verify_hash() now returns False for non-string inputs instead of raising TypeError (prevents 500 errors when API key header is absent and None is passed to verify) - base_world.py overwrite now uses yaml.safe_dump for safe, consistent output - test: rename 'hash' variable to 'hash_val' to avoid shadowing built-in - test: add None-input assertions to test_verify_hash - test: use side_effect=deepcopy to prevent SENSITIVE_CONF module-level mutation
|
There was a problem hiding this comment.
Pull request overview
This PR addresses plaintext credential storage by introducing Argon2 hashing for configured user passwords and red/blue API keys, and persisting the hashed values back into the selected main config on startup.
Changes:
- Add
app.utility.config_utilwith Argon2 hashing/verification helpers and secure local config generation. - Update config loading (
BaseWorld.apply_configandserver.py) to hash credentials and optionally overwrite the source YAML with hashed values. - Switch authentication checks (password + API key) to hash verification and update tests accordingly.
Reviewed changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
app/utility/config_util.py |
New hashing + verification utilities and secure local config generation/logging. |
app/utility/base_world.py |
Extends apply_config to hash credentials and optionally overwrite the config file. |
app/service/auth_svc.py |
Replaces plaintext API key comparison with hash verification. |
app/service/login_handlers/default.py |
Replaces plaintext password comparison with hash verification. |
server.py |
Uses new ensure_local_config and enables hashing + overwrite for main config on startup. |
app/utility/config_generator.py |
Removed legacy secure-config generator module. |
requirements.txt |
Adds argon2-cffi dependency. |
tests/utility/test_config_util.py |
Adds unit tests for hashing/verification and local config creation behavior. |
tests/conftest.py |
Loads test configs with apply_hash=True to match new auth behavior. |
tests/web_server/test_core_endpoints.py |
Loads test config with hashing enabled. |
tests/services/test_rest_svc.py |
Updates test config loading call signature. |
tests/api/v2/test_security.py |
Loads test config with hashing enabled. |
tests/api/v2/test_responses.py |
Loads test config with hashing enabled. |
tests/api/v2/test_knowledge.py |
Loads test config with hashing enabled. |
tests/api/v2/managers/test_config_api_manager.py |
Loads test config with hashing enabled. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| @mock.patch('logging.info') | ||
| @mock.patch.object(yaml, 'safe_load', return_value={'app.contact.http': '0.0.0.0', 'plugins': ['sandcat']}) | ||
| @mock.patch.object(secrets, 'token_urlsafe', return_value='plaintextsecret') | ||
| def test_make_secure_config_logs_plaintext_then_hashes(self, mock_token_urlsafe, mock_safe_load, mock_logging_info): | ||
| with mock.patch.object(builtins, 'open', mock.mock_open()): | ||
| config = make_secure_config() | ||
|
|
||
| # logging.info must have been called exactly once (to display startup credentials) | ||
| mock_logging_info.assert_called_once() | ||
| logged_message = mock_logging_info.call_args[0][0] | ||
|
|
||
| # The logged message must contain the plaintext secret so the admin can read their credentials | ||
| assert 'plaintextsecret' in logged_message, ( | ||
| "Expected plaintext secret in logged startup message, got: %r" % logged_message | ||
| ) | ||
|
|
||
| # The returned config must store argon2 hashes, not the plaintext secret | ||
| assert config['api_key_blue'].startswith('$argon2id$'), ( | ||
| "api_key_blue should be an argon2 hash after make_secure_config, got: %r" % config['api_key_blue'] | ||
| ) | ||
| assert config['api_key_red'].startswith('$argon2id$'), ( | ||
| "api_key_red should be an argon2 hash after make_secure_config, got: %r" % config['api_key_red'] | ||
| ) |
| if apply_hash: | ||
| changes_made = hash_config_creds(config) | ||
| if changes_made and overwrite_path: | ||
| logging.debug(f'Overwriting config file {overwrite_path} with secure values') | ||
| with open(overwrite_path, 'w') as cfg_file: | ||
| yaml.safe_dump(config, cfg_file, default_flow_style=False) |
| """ | ||
| ph = PasswordHasher() | ||
| any_hashed = False | ||
| for option in HASHED_OPTIONS: | ||
| val = config.get(option, '') | ||
|
|
||
| # Skip any values that are already hashed | ||
| if val and not _is_hashed(val): | ||
| config[option] = ph.hash(val) | ||
| any_hashed = True | ||
|
|
||
| # Hash credentials | ||
| for group_name, group_dict in config.get('users', dict()).items(): | ||
| for username, val in group_dict.items(): | ||
| if not _is_hashed(val): | ||
| config['users'][group_name][username] = ph.hash(val) | ||
| any_hashed = True | ||
|
|
| # Display API keys and user credentials, then hash them | ||
| logging.info(CONFIG_MSG_TEMPLATE.render(config_path=LOCAL_CONF_PATH, **config)) | ||
| hash_config_creds(config) |
| def request_has_valid_api_key(self, request): | ||
| request_api_key = request.headers.get(HEADER_API_KEY) | ||
| if request_api_key is None: | ||
| return False | ||
| for i in [CONFIG_API_KEY_RED, CONFIG_API_KEY_BLUE]: | ||
| api_key = self.get_config(i) | ||
| if api_key is not None and compare_digest(request_api_key, api_key): | ||
| hashed_api_key = self.get_config(i) | ||
| if hashed_api_key is not None and verify_hash(hashed_api_key, request_api_key): | ||
| return True |
* hash passwords and API keys in main config * style fixes * remove superfluous line * move hash checks to utility function * simplify code * add unit tests for config util * fix: guard _is_hashed against non-string config values * test: verify make_secure_config logs plaintext once then returns hashes * style: remove unused logging import from test_config_util.py (F401) * fix: guard verify_hash against None inputs; use yaml.safe_dump for config overwrite - verify_hash() now returns False for non-string inputs instead of raising TypeError (prevents 500 errors when API key header is absent and None is passed to verify) - base_world.py overwrite now uses yaml.safe_dump for safe, consistent output - test: rename 'hash' variable to 'hash_val' to avoid shadowing built-in - test: add None-input assertions to test_verify_hash - test: use side_effect=deepcopy to prevent SENSITIVE_CONF module-level mutation --------- Co-authored-by: deacon <[email protected]>





Description
Type of change
How Has This Been Tested?
Checklist: