1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-09 22:15:15 +03:00

ssh: allow a number of auth retries

Rather than just a single attempt at each mechanism, let's allow up
to 3 loops, each time trying all supported mechanisms.  This helps
for the case where the user makes a typo with their password, and
should also help for more complicated auth setups where succeeding
with one mechanism may not be sufficient.

While testing this out I noticed that were deferring closing the
OS level window until after the entire auth attempt, so I added
some logic to proactively close the prompt windows.  In the longer
term I'd like all related prompts to render in the same window
for improved cognotive continuity.
This commit is contained in:
Wez Furlong 2020-01-24 08:39:34 -08:00
parent 970e4a8e64
commit b59893fd9f
4 changed files with 54 additions and 26 deletions

View File

@ -2454,9 +2454,12 @@ impl TermWindow {
let (top, mut lines) = tab.renderer().get_lines(stable_row..stable_row + 1);
let new_highlight = if top == stable_row {
let line = &mut lines[0];
if let Some(cell) = line.cells().get(x) {
cell.attrs().hyperlink.as_ref().cloned()
if let Some(line) = lines.get_mut(0) {
if let Some(cell) = line.cells().get(x) {
cell.attrs().hyperlink.as_ref().cloned()
} else {
None
}
} else {
None
}

View File

@ -252,6 +252,11 @@ impl Mux {
}
}
pub fn kill_window(&self, window_id: WindowId) {
let mut windows = self.windows.borrow_mut();
windows.remove(&window_id);
}
pub fn get_window(&self, window_id: WindowId) -> Option<Ref<Window>> {
if !self.windows.borrow().contains_key(&window_id) {
return None;

View File

@ -281,28 +281,34 @@ pub fn ssh_connect(remote_address: &str, username: &str) -> anyhow::Result<ssh2:
let methods: HashSet<&str> = sess.auth_methods(&username)?.split(',').collect();
if !sess.authenticated() && methods.contains("publickey") {
if let Err(err) = sess.userauth_agent(&username) {
log::info!("while attempting agent auth: {}", err);
for _ in 0..3 {
if sess.authenticated() {
break;
}
}
if !sess.authenticated() && methods.contains("password") {
let pass = password_prompt("", "Password", username, &remote_address)
.ok_or_else(|| anyhow!("password entry was cancelled"))?;
if let Err(err) = sess.userauth_password(username, &pass) {
log::error!("while attempting password auth: {}", err);
if !sess.authenticated() && methods.contains("publickey") {
if let Err(err) = sess.userauth_agent(&username) {
log::info!("while attempting agent auth: {}", err);
}
}
}
if !sess.authenticated() && methods.contains("keyboard-interactive") {
let mut prompt = Prompt {
username,
remote_address: &remote_address,
};
if !sess.authenticated() && methods.contains("password") {
let pass = password_prompt("", "Password", username, &remote_address)
.ok_or_else(|| anyhow!("password entry was cancelled"))?;
if let Err(err) = sess.userauth_password(username, &pass) {
log::error!("while attempting password auth: {}", err);
}
}
if let Err(err) = sess.userauth_keyboard_interactive(&username, &mut prompt) {
log::error!("while attempting keyboard-interactive auth: {}", err);
if !sess.authenticated() && methods.contains("keyboard-interactive") {
let mut prompt = Prompt {
username,
remote_address: &remote_address,
};
if let Err(err) = sess.userauth_keyboard_interactive(&username, &mut prompt) {
log::error!("while attempting keyboard-interactive auth: {}", err);
}
}
}

View File

@ -403,7 +403,7 @@ pub async fn run<
render_rx: Receiver<Vec<Change>>,
width: usize,
height: usize,
) -> anyhow::Result<()> {
) -> anyhow::Result<WindowId> {
let mux = Mux::get().unwrap();
// TODO: make a singleton
@ -431,16 +431,30 @@ pub async fn run<
let gui = front_end().unwrap();
gui.spawn_new_window(&fontconfig, &tab, window_id)?;
Ok(())
Ok(window_id)
}
let window_id: WindowId = promise::spawn::spawn_into_main_thread(async move {
register_tab(input_tx, render_rx, width, height).await
})
.await
.unwrap_or_else(|| bail!("task panicked or was cancelled"))?;
let result = promise::spawn::spawn_into_new_thread(move || f(tw_term))
.await
.unwrap_or_else(|| bail!("task panicked or was cancelled"));
// Since we're typically called with an outstanding Activity token active,
// the dead status of the tab will be ignored until after the activity
// resolves. In the case of SSH where (currently!) several prompts may
// be shown in succession, we don't want to leave lingering dead windows
// on the screen so let's ask the mux to kill off our window now.
promise::spawn::spawn_into_main_thread(async move {
register_tab(input_tx, render_rx, width, height).await.ok();
let mux = Mux::get().unwrap();
mux.kill_window(window_id);
});
promise::spawn::spawn_into_new_thread(move || f(tw_term))
.await
.unwrap_or_else(|| bail!("task panicked or was cancelled"))
result
}
pub fn message_box_ok(message: &str) {