Resolve incorrect handling of tokens in logout flow (#2795) (#2803)

This commit is contained in:
Firstyear 2024-05-29 17:33:46 +10:00 committed by GitHub
parent ba82b1aeaf
commit c4153c96bb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 44 additions and 32 deletions

View file

@ -32,7 +32,7 @@ members = [
] ]
[workspace.package] [workspace.package]
version = "1.2.1" version = "1.2.2"
authors = [ authors = [
"William Brown <william@blackhats.net.au>", "William Brown <william@blackhats.net.au>",
"James Hodgkinson <james@terminaloutcomes.com>", "James Hodgkinson <james@terminaloutcomes.com>",

View file

@ -589,7 +589,17 @@ impl LogoutOpt {
} }
pub async fn exec(&self) { pub async fn exec(&self) {
let mut tokens = read_tokens(&self.copt.get_token_cache_path()).unwrap_or_else(|_| {
error!("Error retrieving authentication token store");
std::process::exit(1);
});
let instance_name = &self.copt.instance; let instance_name = &self.copt.instance;
let n_lookup = instance_name.clone().unwrap_or_default();
let Some(token_instance) = tokens.instances.get_mut(&n_lookup) else {
println!("No sessions for instance {}", n_lookup);
return;
};
let spn: String = if self.local_only { let spn: String = if self.local_only {
// For now we just remove this from the token store. // For now we just remove this from the token store.
@ -624,61 +634,63 @@ impl LogoutOpt {
std::process::exit(1); std::process::exit(1);
} }
}; };
// Parse it for the username.
if let Err(e) = client.logout().await {
error!("Failed to logout - {:?}", e);
std::process::exit(1);
}
// Server acked the logout, lets proceed with the local cleanup now.
// Parse it for the SPN. Annoying but it's what we have to do
// because we don't know what token was used in the lower to client calls.
let jwsc = match JwsCompact::from_str(&token) { let jwsc = match JwsCompact::from_str(&token) {
Ok(j) => j, Ok(j) => j,
Err(err) => { Err(err) => {
error!(?err, "Unable to parse token"); error!(?err, "Unable to parse token");
info!("The token can be removed locally with `--local-only`");
std::process::exit(1); std::process::exit(1);
} }
}; };
let jws_verifier = if let Some(pub_jwk) = jwsc.get_jwk_pubkey() { let Some(key_id) = jwsc.kid() else {
match JwsEs256Verifier::try_from(pub_jwk) { error!("Invalid token, missing KeyID");
info!("The token can be removed locally with `--local-only`");
std::process::exit(1);
};
let Some(pub_jwk) = token_instance.keys().get(key_id) else {
error!("Invalid instance, no signing keys are available");
info!("The token can be removed locally with `--local-only`");
std::process::exit(1);
};
let jws_verifier = match JwsEs256Verifier::try_from(pub_jwk) {
Ok(verifier) => verifier, Ok(verifier) => verifier,
Err(err) => { Err(err) => {
error!(?err, "Unable to configure jws verifier"); error!(?err, "Unable to configure jws verifier");
info!("The token can be removed locally with `--local-only`");
std::process::exit(1); std::process::exit(1);
} }
}
} else {
error!("Unable to access token public key");
std::process::exit(1);
}; };
let uat = match jws_verifier.verify(&jwsc).and_then(|jws| { let uat = match jws_verifier.verify(&jwsc).and_then(|jws| {
jws.from_json::<UserAuthToken>().map_err(|serde_err| { jws.from_json::<UserAuthToken>().map_err(|serde_err| {
error!(?serde_err); error!(?serde_err);
info!("The token can be removed locally with `--local-only`");
JwtError::InvalidJwt JwtError::InvalidJwt
}) })
}) { }) {
Ok(uat) => uat, Ok(uat) => uat,
Err(e) => { Err(e) => {
error!(?e, "Unable to verify token signature, may be corrupt"); error!(?e, "Unable to verify token signature, may be corrupt");
info!("The token can be removed locally with `--local-only`");
std::process::exit(1); std::process::exit(1);
} }
}; };
uat.spn // Now we know we have a valid(ish) token, call the server to do the logout.
}; if let Err(e) = client.logout().await {
error!("Failed to logout - {:?}", e);
let mut tokens = read_tokens(&self.copt.get_token_cache_path()).unwrap_or_else(|_| {
error!("Error retrieving authentication token store");
std::process::exit(1); std::process::exit(1);
}); }
let n_lookup = instance_name.clone().unwrap_or_else(|| "".to_string()); // Server acked the logout, lets proceed with the local cleanup now, return
let Some(token_instance) = tokens.instances.get_mut(&n_lookup) else { // the spn so the outer parts know what to remove.
println!("No sessions for {}", spn); uat.spn
return;
}; };
// Remove our old one // Remove our old one

View file

@ -782,8 +782,8 @@ pub struct ReauthOpt {
pub struct LogoutOpt { pub struct LogoutOpt {
#[clap(flatten)] #[clap(flatten)]
copt: CommonOpt, copt: CommonOpt,
#[clap(short, long, hide = true)] #[clap(short, long)]
/// Do not send the logout to the server - only remove the session token locally /// Do not send a logout request to the server - only remove the session token locally.
local_only: bool, local_only: bool,
} }