public async Task ActivateOrConnectInstanceAsync(IProjectExplorerVmInstanceNode vmNode) { if (this.remoteDesktopService.TryActivate(vmNode.Reference)) { // RDP session was active, nothing left to do. return; } // Select node so that tracking windows are updated. vmNode.Select(); var settings = (VmInstanceConnectionSettings) this.settingsService.GetConnectionSettings(vmNode); await this.credentialPrompt.ShowCredentialsPromptAsync( this.window, vmNode.Reference, settings, true) .ConfigureAwait(true); // Persist new credentials. this.settingsService.SaveConnectionSettings(settings); await ConnectInstanceAsync( vmNode.Reference, settings) .ConfigureAwait(true); }
//--------------------------------------------------------------------- // IRdpConnectionService. //--------------------------------------------------------------------- public async Task ActivateOrConnectInstanceAsync( IProjectExplorerVmInstanceNode vmNode, bool allowPersistentCredentials) { Debug.Assert(vmNode.IsRdpSupported()); if (this.sessionBroker.TryActivate(vmNode.Reference)) { // RDP session was active, nothing left to do. return; } // Select node so that tracking windows are updated. vmNode.Select(); var settings = this.settingsService.GetConnectionSettings(vmNode); if (allowPersistentCredentials) { await this.credentialPrompt.ShowCredentialsPromptAsync( this.window, vmNode.Reference, settings.TypedCollection, true) .ConfigureAwait(true); // Persist new credentials. settings.Save(); } else { // //Temporarily clear persisted credentials so that the // default credential prompt is triggered. // // NB. Use an empty string (as opposed to null) to // avoid an inherited setting from kicking in. // settings.TypedCollection.RdpPassword.Value = string.Empty; } await ConnectInstanceAsync( vmNode.Reference, (InstanceConnectionSettings)settings.TypedCollection) .ConfigureAwait(true); }
public async Task ActivateOrConnectInstanceAsync(IProjectExplorerVmInstanceNode vmNode) { if (this.remoteDesktopService.TryActivate(vmNode.Reference)) { // RDP session was active, nothing left to do. return; } // Select node so that tracking windows are updated. vmNode.Select(); await this.credentialPrompt.ShowCredentialsPromptAsync( this.window, vmNode.Reference, vmNode.SettingsEditor, true) .ConfigureAwait(true); await ConnectInstanceAsync( vmNode.Reference, vmNode.SettingsEditor.CreateConnectionSettings(vmNode.Reference.Name)) .ConfigureAwait(true); }
//--------------------------------------------------------------------- // ISshConnectionService. //--------------------------------------------------------------------- public async Task ActivateOrConnectInstanceAsync(IProjectExplorerVmInstanceNode vmNode) { Debug.Assert(vmNode.IsSshSupported()); if (this.sessionBroker.TryActivate(vmNode.Reference)) { // SSH session was active, nothing left to do. return; } // Select node so that tracking windows are updated. vmNode.Select(); var instance = vmNode.Reference; var settings = (InstanceConnectionSettings)this.settingsService .GetConnectionSettings(vmNode) .TypedCollection; var timeout = TimeSpan.FromSeconds(settings.SshConnectionTimeout.IntValue); // // Start job to create IAP tunnel. // var tunnelTask = this.jobService.RunInBackground( new JobDescription( $"Opening Cloud IAP tunnel to {instance.Name}...", JobUserFeedbackType.BackgroundFeedback), async token => { try { var destination = new TunnelDestination( vmNode.Reference, (ushort)settings.SshPort.IntValue); // NB. Give IAP the same timeout for probing as SSH itself. return(await this.tunnelBroker.ConnectAsync( destination, new SameProcessRelayPolicy(), timeout) .ConfigureAwait(false)); } catch (NetworkStreamClosedException e) { throw new ConnectionFailedException( "Connecting to the instance failed. Make sure that you have " + "configured your firewall rules to permit Cloud IAP access " + $"to {instance.Name}", HelpTopics.CreateIapFirewallRule, e); } catch (UnauthorizedException) { throw new ConnectionFailedException( "You are not authorized to connect to this VM instance.\n\n" + $"Verify that the Cloud IAP API is enabled in the project {instance.ProjectId} " + "and that your user has the 'IAP-secured Tunnel User' role.", HelpTopics.IapAccess); } }); // // Load persistent CNG key. This must be done on the UI thread. // var email = this.authorizationAdapter.Authorization.Email; var rsaKey = this.keyStoreAdapter.CreateRsaKey( $"IAPDESKTOP_{email}", CngKeyUsages.Signing, true, this.window); Debug.Assert(rsaKey != null); // // Start job to publish key, using whatever mechanism is appropriate // for this instance. // var sshKey = new RsaSshKey(rsaKey); try { var authorizedKeyTask = this.jobService.RunInBackground( new JobDescription( $"Publishing SSH key for {instance.Name}...", JobUserFeedbackType.BackgroundFeedback), async token => { // // Authorize the key. // return(await this.authorizedKeyService.AuthorizeKeyAsync( vmNode.Reference, sshKey, TimeSpan.FromDays(30), // TODO: Make expiry configurable NullIfEmpty(settings.SshUsername.StringValue), AuthorizeKeyMethods.All, token) .ConfigureAwait(true)); }); // // Wait for both jobs to continue (they are both fairly slow). // await Task.WhenAll(tunnelTask, authorizedKeyTask) .ConfigureAwait(true); // // NB. ConnectAsync takes ownership of the key and will retain // it for the lifetime of the session. // await this.sessionBroker.ConnectAsync( instance, new IPEndPoint(IPAddress.Loopback, tunnelTask.Result.LocalPort), authorizedKeyTask.Result, timeout) .ConfigureAwait(true); } catch (Exception) { sshKey.Dispose(); throw; } }