diff --git a/docs/web/authentication.md b/docs/web/authentication.md index fda750757f..14338e1306 100644 --- a/docs/web/authentication.md +++ b/docs/web/authentication.md @@ -9,26 +9,28 @@ the results stored on a server. Table of Contents ================= -* [Server-side configuration](#server-side-configuration) - * [Dictionary authentication](#dictionary-authentication) - * [External authentication methods](#external-auth-methods) - * [PAM authentication](#pam-authentication) - * [LDAP authentication](#ldap-authentication) - * [Configuration options](#configuration-options) - * [Membership in custom groups with regex_groups](#regex_groups-authentication) - * [OAuth authentication](#oauth-authentication) - * [OAuth Configuration options](#oauth-configuration-options) - * [OAuth details per each provider](#oauth-details-per-each-provider) -* [Client-side configuration](#client-side-configuration) - * [Web-browser client](#web-browser-client) - * [Command-line client](#command-line-client) - * [Preconfigured credentials](#preconfigured-credentials) - * [Automatic login](#automatic-login) - * [Currently active tokens](#currently-active-tokens) -* [Personal access token](#personal-access-token) - * [`new`](#new-personal-access-token) - * [`list`](#list-personal-access-token) - * [`del`](#remove-personal-access-token) +- [CodeChecker authentication subsystem](#codechecker-authentication-subsystem) +- [Table of Contents](#table-of-contents) +- [Server-side configuration ](#server-side-configuration-) + - [Dictionary authentication ](#dictionary-authentication-) + - [External authentication methods ](#external-authentication-methods-) + - [PAM authentication ](#pam-authentication-) + - [LDAP authentication ](#ldap-authentication-) + - [Configuration options ](#configuration-options-) + - [Membership in custom groups with regex\_groups](#membership-in-custom-groups-with-regex_groups) + - [OAuth authentication ](#oauth-authentication-) + - [OAuth Configuration options ](#oauth-configuration-options-) + - [OAuth Details per each provider ](#oauth-details-per-each-provider-) +- [Client-side configuration ](#client-side-configuration-) + - [Web-browser client ](#web-browser-client-) + - [Command-line client ](#command-line-client-) + - [Preconfigured credentials ](#preconfigured-credentials-) + - [Automatic login ](#automatic-login-) + - [Currently active tokens ](#currently-active-tokens-) +- [Personal access token ](#personal-access-token-) + - [New personal access token ](#new-personal-access-token-) + - [List personal access tokens ](#list-personal-access-tokens-) + - [Remove personal access token ](#remove-personal-access-token-) # Server-side configuration @@ -360,7 +362,7 @@ Specific behavior related to each provider is configured by a provider `template A key-value table that is used to set variables across all providers, for convenience. Any variable can be specified. If using the `host` variable, it should be in the format `https://example.com`, including the protocol. - + The `callback_url`'s default value uses the `host` and `provider` variables. Template `ms_entra/v2.0` uses the `tenant_id` variable. @@ -394,7 +396,7 @@ Specific behavior related to each provider is configured by a provider `template * `variables` - A key-value table that is used to set variables used inside parameters. + A key-value table that is used to set variables used inside parameters. To use a variable, specify it using `{variable}`. The `{provider}` variable is automatically set. @@ -494,7 +496,7 @@ Specific behavior related to each provider is configured by a provider `template *Default*: Set by template. ### 🔧 Example: OAuth Configuration using templates - + ```jsonc "github": { "enabled": false, @@ -622,7 +624,14 @@ To alleviate the need for supplying authentication in the command-line every time a server is connected to, users can pre-configure their credentials to be used in authentication. -To do so first copy the `config/session_client.json` file from the CodeChecker +You can pass the credential used as a password or personal access token +in the `.codechecker.password.json` or +directly in the `CC_PASSWORD` environment variable. +If this environment variable is set, the credentials +described in `.codechecker.password.json` will be ignored. + +If you wish to provide (multiple different) credentials in a password configuration file, +first copy the `config/session_client.json` file from the CodeChecker package to your home directory and rename it to `.codechecker.passwords.json` After creating the new file open `~/.codechecker.passwords.json`. @@ -656,10 +665,9 @@ authenticate in the name of the given user. This way no need to store passwords in text files. For more information [see](#personal-access-token). The location of the password file can be configured by the `CC_PASS_FILE` -environment variable. This environment variable can also be used to setup -different credential files to login to the same server with a different user. +environment variable. -Furthermore, the location of the session file can be configured by the +The location of the session file can be configured by the `CC_SESSION_FILE` environment variable. This can be useful if CodeChecker does not have the permission to create a session file under the user's home directory (e.g. in some CI environments). diff --git a/web/client/codechecker_client/cli/store.py b/web/client/codechecker_client/cli/store.py index afe025b2c3..a027527765 100644 --- a/web/client/codechecker_client/cli/store.py +++ b/web/client/codechecker_client/cli/store.py @@ -165,6 +165,10 @@ def get_argparser_ctor_args(): 'epilog': """ Environment variables ------------------------------------------------ + CC_PASSWORD You can provide authentication credentials directly in this + variable. "CodeChecker cmd login" will use it as a + password or personal access token if set. + CC_PASS_FILE The location of the password file for auto login. By default CodeChecker will use '~/.codechecker.passwords.json' file. It can also be used to setup different credential files to diff --git a/web/client/codechecker_client/client.py b/web/client/codechecker_client/client.py index e6a5745f32..47c9ccc5d4 100644 --- a/web/client/codechecker_client/client.py +++ b/web/client/codechecker_client/client.py @@ -111,11 +111,19 @@ def login_user(protocol, host, port, username, login=False): methods = auth_client.getAcceptedAuthMethods() # Attempt username-password auth first. if 'Username:Password' in str(methods): - # Try to use a previously saved credential from configuration file if # autologin is enabled. saved_auth = None - if session.is_autologin_enabled(): + if env.get_password_string(): + # if CC_PASSWORD env var is defined use that + LOG.info("Using credentials from CC_PASSWORD env var to log in.") + if not username: + LOG.error("Cannot login. CC_PASSWORD env var is defined," + "but username is not provided!") + sys.exit(1) + saved_auth = f"{username}:{env.get_password_string()}" + + if session.is_autologin_enabled() and not saved_auth: saved_auth = session.get_auth_string(host, port) if saved_auth: diff --git a/web/codechecker_web/shared/env.py b/web/codechecker_web/shared/env.py index 08a58855ca..aa944c1fa9 100644 --- a/web/codechecker_web/shared/env.py +++ b/web/codechecker_web/shared/env.py @@ -26,6 +26,11 @@ def get_default_workspace(): return workspace +def get_password_string(): + """ Return the location of the CodeChecker password credential. """ + return os.environ.get("CC_PASSWORD", None) + + def get_password_file(): """ Return the location of the CodeChecker password file. """ return os.environ.get("CC_PASS_FILE", diff --git a/web/tests/functional/authentication/test_authentication.py b/web/tests/functional/authentication/test_authentication.py index 5edb4485a3..a829b7426a 100644 --- a/web/tests/functional/authentication/test_authentication.py +++ b/web/tests/functional/authentication/test_authentication.py @@ -542,6 +542,40 @@ def test_nonauth_storage(self): subprocess.check_output( store_cmd, encoding="utf-8", errors="ignore") + def test_cc_password_env_auth(self): + """ + Tests authentication if credential is passed + in the CC_PASSWORD env var. + """ + + codechecker_cfg = self._test_cfg['codechecker_cfg'] + + # Login with good password + my_env = os.environ.copy() + my_env["CC_PASSWORD"] = "test" + + login_cmd = [env.codechecker_cmd(), 'cmd', 'login', 'cc', + '--url', env.parts_to_url(codechecker_cfg)] + + login_response = subprocess.check_output( + login_cmd, env=my_env, encoding="utf-8", errors="ignore") + self.assertTrue(login_response, + "Server reported successful authentication") + + logout_cmd = [env.codechecker_cmd(), 'cmd', 'login', 'cc', + '-d', '--url', env.parts_to_url(codechecker_cfg)] + subprocess.check_output( + logout_cmd, env=my_env, encoding="utf-8", errors="ignore") + # Login with wrong password + my_env["CC_PASSWORD"] = "wrong" + + login_cmd = [env.codechecker_cmd(), 'cmd', 'login', 'cc', + '--url', env.parts_to_url(codechecker_cfg)] + + with self.assertRaises(subprocess.CalledProcessError): + subprocess.check_output( + login_cmd, env=my_env, encoding="utf-8", errors="ignore") + def test_group_auth(self): """ Test for case insensitive group comparison at authorization.