mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
zkey-ekmfweb: Add login support
To perform operations in EKMF Web, the user must log in with a EKMF Web user id and a time based one time passcode. The passcode can be obtained by the user from the EKMF Web user interface, after logging in into EKMF Web. That way a two factor authentication is performed. The plugin passes the passcode to EKMF Web retrieves a bearer token from EKMF Web which it then uses on subsequent requests to authenticate with EKMF Web. Such a bearer token is valid for several minutes, thus no re-login is required for zkey commands run during that time. Signed-off-by: Ingo Franzki <ifranzki@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
committed by
Jan Höppner
parent
5a9c381225
commit
d8054d1a1a
@@ -405,6 +405,9 @@ static int _get_ekmf_config(struct plugin_handle *ph)
|
||||
free(tmp);
|
||||
ph->ekmf_config.max_redirs = 0;
|
||||
|
||||
ph->ekmf_config.login_token = properties_get(ph->properties,
|
||||
EKMFWEB_CONFIG_LOGIN_TOKEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -439,6 +442,29 @@ static void _free_ekmf_config(struct plugin_handle *ph)
|
||||
free((void *)ph->ekmf_config.ekmf_server_pubkey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the login token file, if the error indicates an authorization or
|
||||
* authentication error (-EACCES or -EPERM)
|
||||
*
|
||||
* @param ph the plugin handle
|
||||
* @param error the negative errno value of the last error
|
||||
*/
|
||||
static void _remove_login_token_if_error(struct plugin_handle *ph, int error)
|
||||
{
|
||||
switch (error) {
|
||||
case -EACCES:
|
||||
case -EPERM:
|
||||
remove(ph->ekmf_config.login_token);
|
||||
FREE_AND_SET_NULL(ph->ekmf_config.login_token);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a KMS plugin for usage by zkey. When a repository is bound to a
|
||||
* KMS plugin, zkey calls this function when opening the repository.
|
||||
@@ -1805,6 +1831,41 @@ int kms_deconfigure(const kms_handle_t handle)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts the user for input on stdin, and returns the entered value.
|
||||
* The returned string must be freed by the caller.
|
||||
*
|
||||
* @param ph the plugin handle
|
||||
* @param msg the message to prompt for the input (can be NULL)
|
||||
*
|
||||
* @returns the entered value, or NULL in case of an error.
|
||||
*/
|
||||
static char *_prompt_for_input(struct plugin_handle *ph, const char *msg)
|
||||
{
|
||||
size_t input_len = 0;
|
||||
char *input = NULL;
|
||||
int rc;
|
||||
|
||||
while (input_len == 0 || input == NULL || strlen(input) < 1) {
|
||||
if (msg != NULL)
|
||||
printf("%s: %s: ", program_invocation_short_name, msg);
|
||||
|
||||
rc = getline(&input, &input_len, stdin);
|
||||
if (rc < 0) {
|
||||
_set_error(ph, "Failed to read from stdin: %s",
|
||||
strerror(errno));
|
||||
if (input != NULL)
|
||||
free(input);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (input != NULL && input[strlen(input) - 1] == '\n')
|
||||
input[strlen(input) - 1] = '\0';
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows the KMS plugin to perform a login to the KMS (if required). This
|
||||
* function is called at least once before any key operation function, typically
|
||||
@@ -1826,6 +1887,12 @@ int kms_deconfigure(const kms_handle_t handle)
|
||||
int kms_login(const kms_handle_t handle)
|
||||
{
|
||||
struct plugin_handle *ph = handle;
|
||||
char *passcode_url = NULL;
|
||||
char *error_msg = NULL;
|
||||
char *passcode = NULL;
|
||||
char *user_id = NULL;
|
||||
bool valid = false;
|
||||
int rc;
|
||||
|
||||
util_assert(handle != NULL, "Internal error: handle is NULL");
|
||||
|
||||
@@ -1833,14 +1900,102 @@ int kms_login(const kms_handle_t handle)
|
||||
|
||||
_clear_error(ph);
|
||||
|
||||
if (!ph->config_complete) {
|
||||
if (!ph->connection_configured) {
|
||||
_set_error(ph, "The configuration is incomplete, run 'zkey "
|
||||
"kms configure [OPTIONS]' to complete the "
|
||||
"configuration.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
if (ph->ekmf_config.login_token != NULL) {
|
||||
rc = ekmf_check_login_token(&ph->ekmf_config, &valid, NULL,
|
||||
ph->verbose);
|
||||
pr_verbose(ph, "Login token valid: %d", valid);
|
||||
|
||||
if (rc == 0 && valid)
|
||||
return 0;
|
||||
|
||||
remove(ph->ekmf_config.login_token);
|
||||
FREE_AND_SET_NULL(ph->ekmf_config.login_token);
|
||||
|
||||
rc = _set_or_remove_property(ph, EKMFWEB_CONFIG_LOGIN_TOKEN,
|
||||
NULL);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
passcode_url = properties_get(ph->properties,
|
||||
EKMFWEB_CONFIG_PASSCODE_URL);
|
||||
if (passcode_url == NULL) {
|
||||
util_asprintf(&passcode_url, "%s%s", ph->ekmf_config.base_url,
|
||||
EKMFWEB_PASSCODE_URL);
|
||||
|
||||
rc = _set_or_remove_property(ph, EKMFWEB_CONFIG_PASSCODE_URL,
|
||||
passcode_url);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
}
|
||||
|
||||
pr_verbose(ph, "passcode url: '%s'", passcode_url);
|
||||
|
||||
user_id = _prompt_for_input(ph, "EKMF Web user ID");
|
||||
if (user_id == NULL) {
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pr_verbose(ph, "User-id: '%s'", user_id);
|
||||
|
||||
util_print_indented("Go to the following web page in your web browser, "
|
||||
"login with the same user ID as entered above and "
|
||||
"your password, and obtain a one time passcode and "
|
||||
"enter it here.", 0);
|
||||
printf("%s\n", passcode_url);
|
||||
|
||||
passcode = _prompt_for_input(ph, "Passcode");
|
||||
if (passcode == NULL) {
|
||||
rc = -EIO;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pr_verbose(ph, "Passcode: '%s'", passcode);
|
||||
|
||||
util_asprintf((char **)&ph->ekmf_config.login_token, "%s/%s",
|
||||
ph->config_path, EKMFWEB_CONFIG_LOGIN_TOKEN_FILE);
|
||||
|
||||
rc = ekmf_login(&ph->ekmf_config, &ph->curl_handle, user_id, passcode,
|
||||
&error_msg, ph->verbose);
|
||||
if (rc != 0) {
|
||||
_set_error(ph, "Failed to login to EKMF Web server at '%s': "
|
||||
"%s", ph->ekmf_config.base_url,
|
||||
error_msg != NULL ? error_msg : strerror(-rc));
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = _set_file_permission(ph, ph->ekmf_config.login_token);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
rc = _set_or_remove_property(ph, EKMFWEB_CONFIG_LOGIN_TOKEN,
|
||||
ph->ekmf_config.login_token);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
rc = _save_config(ph);
|
||||
if (rc != 0)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
if (passcode_url != NULL)
|
||||
free(passcode_url);
|
||||
if (user_id != NULL)
|
||||
free(user_id);
|
||||
if (passcode != NULL)
|
||||
free(passcode);
|
||||
if (error_msg != NULL)
|
||||
free(error_msg);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,6 +33,7 @@ struct plugin_handle {
|
||||
#define EKMFWEB_CONFIG_FILE "ekmfweb.conf"
|
||||
#define EKMFWEB_CONFIG_SERVER_CERT_FILE "server-cert.pem"
|
||||
#define EKMFWEB_CONFIG_SERVER_PUBKEY_FILE "server-pubkey.pem"
|
||||
#define EKMFWEB_CONFIG_LOGIN_TOKEN_FILE "login.token"
|
||||
|
||||
#define EKMFWEB_CONFIG_APQNS "apqns"
|
||||
#define EKMFWEB_CONFIG_URL "url"
|
||||
@@ -44,5 +45,9 @@ struct plugin_handle {
|
||||
#define EKMFWEB_CONFIG_SERVER_PUBKEY "server-pubkey"
|
||||
#define EKMFWEB_CONFIG_VERIFY_SERVER_CERT "verify-server-cert"
|
||||
#define EKMFWEB_CONFIG_VERIFY_HOSTNAME "verify-hostname"
|
||||
#define EKMFWEB_CONFIG_LOGIN_TOKEN "login-token"
|
||||
#define EKMFWEB_CONFIG_PASSCODE_URL "passcode-url"
|
||||
|
||||
#define EKMFWEB_PASSCODE_URL "/administration/passcode"
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user