mirror of
https://github.com/kanidm/kanidm.git
synced 2025-02-23 20:47:01 +01:00
prompting for username when multiple tokens exist on logout (#559)
This commit is contained in:
parent
eb4b25719b
commit
100ef49e4e
|
@ -80,28 +80,13 @@ impl CommonOpt {
|
|||
} else {
|
||||
// Unable to automatically select the user because multiple tokens exist
|
||||
// so we'll prompt the user to select one
|
||||
let mut options = Vec::new();
|
||||
for option in tokens.iter() {
|
||||
options.push(String::from(option.0));
|
||||
}
|
||||
let user_select = Select::with_theme(&ColorfulTheme::default())
|
||||
.with_prompt("Multiple authentication tokens exist. Please select one")
|
||||
.default(0)
|
||||
.items(&options)
|
||||
.interact();
|
||||
let selection = match user_select {
|
||||
Err(error) => {
|
||||
eprintln!("Failed to handle user input: {:?}", error);
|
||||
match prompt_for_username_get_token() {
|
||||
Ok(value) => value,
|
||||
Err(msg) => {
|
||||
eprintln!("{}", msg);
|
||||
std::process::exit(1);
|
||||
}
|
||||
Ok(value) => value,
|
||||
};
|
||||
debug!("Index of the chosen menu item: {:?}", selection);
|
||||
|
||||
let (f_uname, f_token) =
|
||||
tokens.iter().nth(selection).expect("Memory Corruption");
|
||||
info!("Using cached token for name {}", f_uname);
|
||||
f_token.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -129,3 +114,73 @@ impl CommonOpt {
|
|||
client
|
||||
}
|
||||
}
|
||||
|
||||
/// This parses the token store and prompts the user to select their username, returns the username/token as a tuple of Strings
|
||||
///
|
||||
/// Used to reduce duplication in implementing [prompt_for_username_get_username] and [prompt_for_username_get_token]
|
||||
pub fn prompt_for_username_get_values() -> Result<(String, String), String> {
|
||||
let tokens = match read_tokens() {
|
||||
Ok(value) => value,
|
||||
_ => return Err("Error retrieving authentication token store".to_string()),
|
||||
};
|
||||
if tokens.is_empty() {
|
||||
eprintln!("No tokens in store, quitting!");
|
||||
std::process::exit(1);
|
||||
}
|
||||
let mut options = Vec::new();
|
||||
for option in tokens.iter() {
|
||||
options.push(String::from(option.0));
|
||||
}
|
||||
let user_select = Select::with_theme(&ColorfulTheme::default())
|
||||
.with_prompt("Authentication tokens exist. Please select one")
|
||||
.default(0)
|
||||
.items(&options)
|
||||
.interact();
|
||||
let selection = match user_select {
|
||||
Err(error) => {
|
||||
eprintln!("Failed to handle user input: {:?}", error);
|
||||
std::process::exit(1);
|
||||
}
|
||||
Ok(value) => value,
|
||||
};
|
||||
debug!("Index of the chosen menu item: {:?}", selection);
|
||||
|
||||
match tokens.iter().nth(selection) {
|
||||
Some(value) => {
|
||||
let (f_uname, f_token) = value;
|
||||
info!("Using cached token for name {}", f_uname);
|
||||
debug!("Cached token: {}", f_token);
|
||||
Ok((f_uname.to_string(), f_token.to_string()))
|
||||
}
|
||||
None => {
|
||||
eprintln!("Memory corruption trying to read token store, quitting!");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// This parses the token store and prompts the user to select their username, returns the username as a String
|
||||
///
|
||||
/// Powered by [prompt_for_username_get_values]
|
||||
pub fn prompt_for_username_get_username() -> Result<String, String> {
|
||||
match prompt_for_username_get_values() {
|
||||
Ok(value) => {
|
||||
let (f_user, _) = value;
|
||||
Ok(f_user)
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
||||
/// This parses the token store and prompts the user to select their username, returns the token as a String
|
||||
///
|
||||
/// Powered by [prompt_for_username_get_values]
|
||||
pub fn prompt_for_username_get_token() -> Result<String, String> {
|
||||
match prompt_for_username_get_values() {
|
||||
Ok(value) => {
|
||||
let (_, f_token) = value;
|
||||
Ok(f_token)
|
||||
}
|
||||
Err(err) => Err(err),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
use crate::common::prompt_for_username_get_username;
|
||||
use crate::{LoginOpt, LogoutOpt, SessionOpt};
|
||||
|
||||
use kanidm_client::{ClientError, KanidmClient};
|
||||
use kanidm_proto::v1::{AuthAllowed, AuthResponse, AuthState, UserAuthToken};
|
||||
#[cfg(target_family = "unix")]
|
||||
|
@ -166,7 +168,9 @@ impl LoginOpt {
|
|||
let totp = loop {
|
||||
print!("Enter TOTP: ");
|
||||
// We flush stdout so it'll write the buffer to screen, continuing operation. Without it, the application halts.
|
||||
io::stdout().flush().unwrap();
|
||||
if let Err(e) = io::stdout().flush() {
|
||||
eprintln!("Somehow we failed to flush stdout: {:?}", e);
|
||||
};
|
||||
let mut buffer = String::new();
|
||||
if let Err(e) = io::stdin().read_line(&mut buffer) {
|
||||
eprintln!("Failed to read from stdin -> {:?}", e);
|
||||
|
@ -202,6 +206,7 @@ impl LoginOpt {
|
|||
pub fn exec(&self) {
|
||||
let mut client = self.copt.to_unauth_client();
|
||||
|
||||
// TODO: remove this anon, nobody should do default anonymous
|
||||
let username = self.copt.username.as_deref().unwrap_or("anonymous");
|
||||
|
||||
// What auth mechanisms exist?
|
||||
|
@ -340,14 +345,26 @@ impl LoginOpt {
|
|||
|
||||
impl LogoutOpt {
|
||||
pub fn debug(&self) -> bool {
|
||||
self.copt.debug
|
||||
self.debug
|
||||
}
|
||||
|
||||
pub fn exec(&self) {
|
||||
let username = self.copt.username.as_deref().unwrap_or("anonymous");
|
||||
|
||||
// For now we just remove this from the token store.
|
||||
// Read the current tokens
|
||||
|
||||
let mut _tmp_username = String::new();
|
||||
let username = match &self.username {
|
||||
Some(value) => value,
|
||||
None => {
|
||||
_tmp_username = match prompt_for_username_get_username() {
|
||||
Ok(value) => value,
|
||||
Err(msg) => {
|
||||
eprintln!("{}", msg);
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
&_tmp_username
|
||||
}
|
||||
};
|
||||
let mut tokens = read_tokens().unwrap_or_else(|_| {
|
||||
error!("Error retrieving authentication token store");
|
||||
std::process::exit(1);
|
||||
|
|
|
@ -284,8 +284,14 @@ pub struct LoginOpt {
|
|||
|
||||
#[derive(Debug, StructOpt)]
|
||||
pub struct LogoutOpt {
|
||||
#[structopt(flatten)]
|
||||
pub copt: CommonOpt,
|
||||
#[structopt(short = "d", long = "debug", env = "KANIDM_DEBUG")]
|
||||
pub debug: bool,
|
||||
#[structopt(short = "H", long = "url", env = "KANIDM_URL")]
|
||||
pub addr: Option<String>,
|
||||
#[structopt(parse(from_os_str), short = "C", long = "ca", env = "KANIDM_CA_PATH")]
|
||||
pub ca_path: Option<PathBuf>,
|
||||
#[structopt()]
|
||||
pub username: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, StructOpt)]
|
||||
|
|
Loading…
Reference in a new issue