diff --git a/proto/src/v1.rs b/proto/src/v1.rs index 3e7676037..214f27264 100644 --- a/proto/src/v1.rs +++ b/proto/src/v1.rs @@ -1012,30 +1012,26 @@ impl PartialEq for AuthAllowed { } } +impl From<&AuthAllowed> for u8 { + fn from(a: &AuthAllowed) -> u8 { + match a { + AuthAllowed::Anonymous => 0, + AuthAllowed::Password => 1, + AuthAllowed::BackupCode => 2, + AuthAllowed::Totp => 3, + AuthAllowed::Passkey(_) => 4, + AuthAllowed::SecurityKey(_) => 5, + } + } +} + impl Eq for AuthAllowed {} impl Ord for AuthAllowed { fn cmp(&self, other: &Self) -> Ordering { - if self.eq(other) { - Ordering::Equal - } else { - // Relies on the fact that match is executed in order! - match (self, other) { - (AuthAllowed::Anonymous, _) => Ordering::Less, - (_, AuthAllowed::Anonymous) => Ordering::Greater, - (AuthAllowed::Password, _) => Ordering::Less, - (_, AuthAllowed::Password) => Ordering::Greater, - (AuthAllowed::BackupCode, _) => Ordering::Less, - (_, AuthAllowed::BackupCode) => Ordering::Greater, - (AuthAllowed::Totp, _) => Ordering::Less, - (_, AuthAllowed::Totp) => Ordering::Greater, - (AuthAllowed::SecurityKey(_), _) => Ordering::Less, - (_, AuthAllowed::SecurityKey(_)) => Ordering::Greater, - (AuthAllowed::Passkey(_), _) => Ordering::Less, - // Unreachable - // (_, AuthAllowed::Passkey(_)) => Ordering::Greater, - } - } + let self_ord: u8 = self.into(); + let other_ord: u8 = other.into(); + self_ord.cmp(&other_ord) } } diff --git a/tools/cli/src/cli/session.rs b/tools/cli/src/cli/session.rs index 0c0e4f9e7..19351eafd 100644 --- a/tools/cli/src/cli/session.rs +++ b/tools/cli/src/cli/session.rs @@ -1,4 +1,5 @@ use crate::common::OpType; +use std::cmp::Reverse; use std::collections::BTreeMap; use std::fs::{create_dir, File}; use std::io::{self, BufReader, BufWriter, ErrorKind, IsTerminal, Write}; @@ -264,16 +265,18 @@ async fn process_auth_state( } _ => { let mut options = Vec::new(); + // because we want them in "most secure to least secure" order. + allowed.sort_unstable_by(|a, b| Reverse(a).cmp(&Reverse(b))); for val in allowed.iter() { options.push(val.to_string()); } - let msg = "Please choose what credential to provide:"; + let msg = "Please choose which credential to provide:"; let selection = get_index_choice_dialoguer(msg, &options); #[allow(clippy::expect_used)] allowed .get(selection) - .expect("can not fail - bounds already checked.") + .expect("Failed to select an authentication option!") } }; @@ -391,7 +394,7 @@ impl LoginOpt { }; // What auth mechanisms exist? - let mechs: Vec<_> = client + let mut mechs: Vec<_> = client .auth_step_init(username) .await .unwrap_or_else(|e| { @@ -401,6 +404,8 @@ impl LoginOpt { .into_iter() .collect(); + mechs.sort_unstable_by(|a, b| Reverse(a).cmp(&Reverse(b))); + let mech = match mechs.len() { 0 => { error!("Error during authentication init phase: Server offered no authentication mechanisms");