private void Browser_AuthenticationPrompt(WebBrowser2 sender, WebBrowser2.AuthenticationPromptEventArgs e) { try { Program.AssertOnEventThread(); log.Debug("Prompting for authentication..."); CompleteClearSecret(lastBrowserState); CompleteGetSecret(lastBrowserState); BrowserState.BrowserCredentials creds = lastBrowserState.Credentials; if (creds != null && creds.Valid) { e.Username = creds.Username; e.Password = creds.Password; e.Success = true; log.Debug("Prompt for authentication successful."); } else { e.Success = false; log.Debug("Prompt for authentication cancelled / failed."); } } catch (Exception exn) { log.Error("Prompt for authentication failed", exn); e.Success = false; } }
private void MaybePersistCredentials(Session session, Pool pool, BrowserState state) { BrowserState.BrowserCredentials creds = state.Credentials; if (creds != null && creds.Valid) { string val = creds.PersistCredentials ? CreateSecret(session, creds.Username, creds.Password) : ""; pool.SetXCPluginSecret(session, PluginDescriptor.Name, state.Obj, val); } }
/// <summary> /// Nothrow guarantee. /// </summary> void Browser_NavigateError(object sender, WebBrowserNavigateErrorEventArgs e) { Program.AssertOnEventThread(); navigationError = true; try { log.DebugFormat("Navigate error ({0}): {1}", e.StatusCode, e.Url); if ((e.StatusCode == 401 || e.StatusCode == 403)) { log.Warn("Clearing secret and re-prompting, since we've seen a 401/403."); BrowserState.BrowserCredentials creds = lastBrowserState.Credentials; bool persisting = creds == null ? true : creds.PersistCredentials; CompleteClearSecret(lastBrowserState); TriggerGetSecret(lastBrowserState); } } catch (Exception exn) { log.Error(exn, exn); } }
/// <summary> /// Prompt for credentials, and set state.Credentials appropriately. /// </summary> /// <param name="defaultPersist">Whether the "persist these credentials" checkbox is checked on entry to the dialog.</param> /// <param name="state"></param> private void PromptForUsernamePassword(bool defaultPersist, BrowserState state) { Program.AssertOnEventThread(); TabPageCredentialsDialog d = new TabPageCredentialsDialog(); d.ServiceName = Label; d.DefaultPersist = defaultPersist; BrowserState.BrowserCredentials creds = new BrowserState.BrowserCredentials(); if (DialogResult.OK == d.ShowDialog(Program.MainWindow)) { creds.Username = d.Username; creds.Password = d.Password; creds.PersistCredentials = d.PersistCredentials; creds.Valid = true; } else { creds.Valid = false; } state.Credentials = creds; }
private void MaybePersistCredentials(Session session, Pool pool, IXenObject obj, BrowserState.BrowserCredentials creds) { if (creds != null && creds.Valid) { string secretUuid = creds.PersistCredentials ? CreateSecret(session, creds.Username, creds.Password) : ""; pool.SetXCPluginSecret(session, PluginDescriptor.Name, obj, secretUuid); } }
/// <summary> /// Get the persisted secret from the server, or prompt for new credentials and persist those back to the server. /// Completion of this thread is indicated by state.Credentials being set. /// /// Nothrow guarantee. /// </summary> /// <param name="obj"></param> private void GetSecret(object obj) { Program.AssertOffEventThread(); BrowserState state = (BrowserState)obj; try { Session session = state.Obj.Connection.Session; do { Pool pool = Helpers.GetPoolOfOne(state.Obj.Connection); if (pool == null) { log.Warn("Failed to get Pool!"); // Sleep and retry. Thread.Sleep(5000); continue; } string secret_uuid = pool.GetXCPluginSecret(PluginDescriptor.Name, state.Obj); if (secret_uuid == null) { log.Debug("Nothing persisted. Prompting for new credentials."); Program.Invoke(Program.MainWindow, (BrowserStateDelegate)PromptForUsernamePassword, true, state); MaybePersistCredentials(session, pool, state); return; } else if (secret_uuid == "") { log.Debug("User chose not to persist these credentials."); Program.Invoke(Program.MainWindow, (BrowserStateDelegate)PromptForUsernamePassword, false, state); MaybePersistCredentials(session, pool, state); return; } else { log.Debug("Found a secret."); XenRef <Secret> secret = null; try { secret = Secret.get_by_uuid(session, secret_uuid); } catch (Failure exn) { log.Warn(string.Format("Secret {0} for {1} on plugin {2} has disappeared!", secret_uuid, Helpers.GetName(state.Obj), PluginDescriptor.Name), exn); TryToRemoveSecret(pool, session, PluginDescriptor.Name, state.Obj); // Retry. continue; } string val = Secret.get_value(session, secret); string[] bits = val.Split(CREDENTIALS_SEPARATOR); if (bits.Length != 2) { log.WarnFormat("Corrupt secret {0} at {1} for {2} on plugin {3}! Deleting.", val, secret_uuid, Helpers.GetName(state.Obj), PluginDescriptor.Name); TryToDestroySecret(session, secret.opaque_ref); TryToRemoveSecret(pool, session, PluginDescriptor.Name, state.Obj); // Retry. continue; } log.Debug("Secret successfully read."); BrowserState.BrowserCredentials creds = new BrowserState.BrowserCredentials(); creds.Username = bits[0]; creds.Password = bits[1]; creds.PersistCredentials = true; creds.Valid = true; state.Credentials = creds; return; } // Unreachable. Should either have returned, or continued (to retry). } while (true); } catch (Exception exn) { log.Warn("Ignoring exception when trying to get secret", exn); // Note that it's essential that we set state.Credentials before leaving this function, because other threads are waiting // for that value to appear. BrowserState.BrowserCredentials creds = new BrowserState.BrowserCredentials(); creds.Valid = false; state.Credentials = creds; } }
/// <summary> /// Get the persisted secret from the server, or prompt for new credentials and persist those back to the server. /// Completion of this thread is indicated by state.Credentials being set. /// /// Nothrow guarantee. /// </summary> /// <param name="obj"></param> private void GetSecret(object obj) { Program.AssertOffEventThread(); BrowserState state = (BrowserState)obj; try { Session session = state.Obj.Connection.Session; do { Pool pool = Helpers.GetPoolOfOne(state.Obj.Connection); if (pool == null) { log.Warn("Failed to get Pool!"); // Sleep and retry. Thread.Sleep(5000); continue; } string secret_uuid = pool.GetXCPluginSecret(PluginDescriptor.Name, state.Obj); if (secret_uuid == null) { log.Debug("Nothing persisted. Prompting for new credentials."); Program.Invoke(Program.MainWindow, (BrowserStateDelegate)PromptForUsernamePassword, true, state); MaybePersistCredentials(session, pool, state); return; } else if (secret_uuid == "") { log.Debug("User chose not to persist these credentials."); Program.Invoke(Program.MainWindow, (BrowserStateDelegate)PromptForUsernamePassword, false, state); MaybePersistCredentials(session, pool, state); return; } else { log.Debug("Found a secret."); XenRef<Secret> secret = null; try { secret = Secret.get_by_uuid(session, secret_uuid); } catch (Failure exn) { log.Warn(string.Format("Secret {0} for {1} on plugin {2} has disappeared!", secret_uuid, Helpers.GetName(state.Obj), PluginDescriptor.Name), exn); TryToRemoveSecret(pool, session, PluginDescriptor.Name, state.Obj); // Retry. continue; } string val = Secret.get_value(session, secret); string[] bits = val.Split(CREDENTIALS_SEPARATOR); if (bits.Length != 2) { log.WarnFormat("Corrupt secret {0} at {1} for {2} on plugin {3}! Deleting.", val, secret_uuid, Helpers.GetName(state.Obj), PluginDescriptor.Name); TryToDestroySecret(session, secret.opaque_ref); TryToRemoveSecret(pool, session, PluginDescriptor.Name, state.Obj); // Retry. continue; } log.Debug("Secret successfully read."); BrowserState.BrowserCredentials creds = new BrowserState.BrowserCredentials(); creds.Username = bits[0]; creds.Password = bits[1]; creds.PersistCredentials = true; creds.Valid = true; state.Credentials = creds; return; } // Unreachable. Should either have returned, or continued (to retry). } while (true); } catch (Exception exn) { log.Warn("Ignoring exception when trying to get secret", exn); // Note that it's essential that we set state.Credentials before leaving this function, because other threads are waiting // for that value to appear. BrowserState.BrowserCredentials creds = new BrowserState.BrowserCredentials(); creds.Valid = false; state.Credentials = creds; } }