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);
        }
示例#2
0
        //---------------------------------------------------------------------
        // 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);
        }
示例#3
0
        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;
            }
        }