Exemple #1
0
        public async Task WhenClosingSessionBeforeChannel_ThenDoubleFreeIsPrevented(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var instanceLocator = await instanceLocatorTask;
            var endpoint        = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    instanceLocator,
                    "testuser",
                    key).ConfigureAwait(true);

                var session     = CreateSession();
                var connection  = session.Connect(endpoint);
                var authSession = connection.Authenticate(
                    "testuser",
                    key,
                    UnexpectedAuthenticationCallback);
                var channel = authSession.OpenExecChannel(
                    "whoami",
                    LIBSSH2_CHANNEL_EXTENDED_DATA.NORMAL);

                session.Dispose();

                // Free channel after session - note that this causes an assertion
                // when debugging.
                channel.Dispose();
            }
        }
        public async Task When2faRequiredAndPromptThrowsException_ThenAuthenticationFailsWithoutRetry(
            [LinuxInstance(InitializeScript = RequireSshPassword)] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    await instanceLocatorTask,
                    "testuser",
                    key);

                using (var session = CreateSession())
                    using (var connection = session.Connect(endpoint))
                    {
                        var callbackCount = 0;

                        Assert.Throws <OperationCanceledException>(
                            () => connection.Authenticate(
                                "testuser",
                                key,
                                (name, instruction, prompt, echo) =>
                        {
                            callbackCount++;
                            throw new OperationCanceledException();
                        }));
                        Assert.AreEqual(1, callbackCount);
                    }
            }
        }
        public async Task WhenNonWhitelistedEnvironmentVariablePassed_ThenOpenShellChannelAsyncThrowsRequestDenied(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    await instanceLocatorTask,
                    "testuser",
                    key).ConfigureAwait(true);

                using (var session = CreateSession())
                    using (var connection = session.Connect(endpoint))
                        using (var authSession = connection.Authenticate("testuser", key))
                        {
                            SshAssert.ThrowsNativeExceptionWithError(
                                session,
                                LIBSSH2_ERROR.CHANNEL_REQUEST_DENIED,
                                () => authSession.OpenShellChannel(
                                    LIBSSH2_CHANNEL_EXTENDED_DATA.MERGE,
                                    DefaultTerminal,
                                    80,
                                    24,
                                    new[]
                            {
                                new EnvironmentVariable("FOO", "foo", true),
                                new EnvironmentVariable("BAR", "bar", true)
                            }));
                        }
            }
        }
        public async Task WhenPublicKeyValidAndKnownFromMetadata_ThenAuthenticationSucceeds(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    await instanceLocatorTask,
                    "testuser",
                    key);

                using (var session = CreateSession())
                    using (var connection = session.Connect(endpoint))
                    {
                        var authSession = connection.Authenticate(
                            "testuser",
                            key,
                            this.UnexpectedAuthenticationCallback);
                        Assert.IsNotNull(authSession);
                    }
            }
        }
Exemple #5
0
        public async Task WhenDisposingConnection_ThenWorkerIsStopped(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    await instanceLocatorTask,
                    "testuser",
                    key);

                using (var connection = new SshShellConnection(
                           "testuser",
                           endpoint,
                           key,
                           SshShellConnection.DefaultTerminal,
                           SshShellConnection.DefaultTerminalSize,
                           CultureInfo.InvariantCulture,
                           _ => { },
                           exception =>
                {
                    Assert.Fail("Unexpected error");
                }))
                {
                    await connection.ConnectAsync();
                }
            }
        }
Exemple #6
0
        public async Task WhenProjectAndInstanceMetadataAllowed_ThenAuthorizeKeyAsyncPushesKeyToProjectMetadata()
        {
            var computeEngineAdapter = CreateComputeEngineAdapterMock(
                osLoginEnabledForProject: null,
                osLoginEnabledForInstance: null,
                osLogin2fa: false,
                legacySshKeyPresent: false,
                projectWideKeysBlockedForProject: false,
                projectWideKeysBlockedForInstance: false);
            var service = new AuthorizedKeyService(
                CreateAuthorizationAdapterMock().Object,
                computeEngineAdapter.Object,
                CreateResourceManagerAdapterMock(true).Object,
                CreateOsLoginServiceMock().Object);

            using (var key = RsaSshKey.NewEphemeralKey())
            {
                var authorizedKey = await service.AuthorizeKeyAsync(
                    SampleLocator,
                    key,
                    TimeSpan.FromMinutes(1),
                    null,
                    AuthorizeKeyMethods.All,
                    CancellationToken.None);

                Assert.IsNotNull(authorizedKey);
                Assert.AreEqual(AuthorizeKeyMethods.ProjectMetadata, authorizedKey.AuthorizationMethod);
                Assert.AreEqual("bob", authorizedKey.Username);

                computeEngineAdapter.Verify(a => a.UpdateCommonInstanceMetadataAsync(
                                                It.IsAny <string>(),
                                                It.IsAny <Action <Metadata> >(),
                                                It.IsAny <CancellationToken>()), Times.Once);
            }
        }
        public async Task WhenCommandIsValid_ThenOpenExecChannelAsyncSucceeds(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    await instanceLocatorTask,
                    "testuser",
                    key).ConfigureAwait(true);

                using (var session = CreateSession())
                    using (var connection = session.Connect(endpoint))
                        using (var authSession = connection.Authenticate("testuser", key))
                            using (var channel = authSession.OpenExecChannel(
                                       "whoami",
                                       LIBSSH2_CHANNEL_EXTENDED_DATA.NORMAL))
                            {
                                channel.WaitForEndOfStream();

                                var buffer    = new byte[1024];
                                var bytesRead = channel.Read(buffer);
                                Assert.AreNotEqual(0, bytesRead);

                                Assert.AreEqual("testuser\n", Encoding.ASCII.GetString(buffer, 0, (int)bytesRead));

                                Assert.AreEqual(0, channel.ExitCode);
                                Assert.IsNull(channel.ExitSignal);
                                channel.Close();
                            }
            }
        }
        public async Task WhenSessionDisconnected_ThenAuthenticateThrowsSocketSend(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    await instanceLocatorTask,
                    "testuser",
                    key);

                using (var session = CreateSession())
                    using (var connection = session.Connect(endpoint))
                    {
                        connection.Dispose();

                        SshAssert.ThrowsNativeExceptionWithError(
                            session,
                            LIBSSH2_ERROR.SOCKET_SEND,
                            () => connection.Authenticate("testuser", key));
                    }
            }
        }
Exemple #9
0
        public async Task WhenNoMoreDataToRead_ThenReadReturnZero(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    await instanceLocatorTask,
                    "testuser",
                    key).ConfigureAwait(true);

                using (var session = CreateSession())
                    using (var connection = session.Connect(endpoint))
                        using (var authSession = connection.Authenticate(
                                   "testuser",
                                   key,
                                   UnexpectedAuthenticationCallback))
                            using (var channel = authSession.OpenExecChannel(
                                       "whoami",
                                       LIBSSH2_CHANNEL_EXTENDED_DATA.NORMAL))
                            {
                                channel.WaitForEndOfStream();

                                Assert.AreNotEqual(0, channel.Read(new byte[1024]));
                                Assert.AreEqual(0, channel.Read(new byte[1024]));
                                channel.Close();
                            }
            }
        }
Exemple #10
0
        public async Task WhenKeyUnknown_ThenErrorIsShownAndWindowIsClosed(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var instanceLocator = await instanceLocatorTask;

            using (var key = new RsaSshKey(new RSACng()))
            {
                SessionAbortedEvent deliveredEvent = null;
                this.eventService.BindHandler <SessionAbortedEvent>(e => deliveredEvent = e);

                var broker = new SshTerminalSessionBroker(
                    this.serviceProvider);
                await broker.ConnectAsync(
                    instanceLocator,
                    new IPEndPoint(await PublicAddressFromLocator(instanceLocator), 22),
                    AuthorizedKey.ForMetadata(key, "test", true, null),
                    TimeSpan.FromSeconds(10))
                .ConfigureAwait(true);

                Assert.IsNotNull(deliveredEvent, "Event fired");
                Assert.IsInstanceOf(typeof(SshNativeException), this.ExceptionShown);
                Assert.AreEqual(
                    LIBSSH2_ERROR.AUTHENTICATION_FAILED,
                    ((SshNativeException)this.ExceptionShown).ErrorCode);
            }
        }
Exemple #11
0
        public async Task WhenDisconnected_ThenOpenExecChannelAsyncThrowsSocketSend(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var instanceLocator = await instanceLocatorTask;
            var endpoint        = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    instanceLocator,
                    "testuser",
                    key).ConfigureAwait(true);

                using (var session = CreateSession())
                    using (var connection = session.Connect(endpoint))
                        using (var authSession = connection.Authenticate("testuser", key))
                        {
                            connection.Dispose();
                            SshAssert.ThrowsNativeExceptionWithError(
                                session,
                                LIBSSH2_ERROR.SOCKET_SEND,
                                () => authSession.OpenExecChannel(
                                    "whoami",
                                    LIBSSH2_CHANNEL_EXTENDED_DATA.NORMAL));
                        }
            }
        }
Exemple #12
0
        public async Task WhenConnected_ThenOpenShellChannelAsyncChannelSucceeds(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var instanceLocator = await instanceLocatorTask;
            var endpoint        = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    instanceLocator,
                    "testuser",
                    key).ConfigureAwait(true);

                using (var session = CreateSession())
                    using (var connection = session.Connect(endpoint))
                        using (var authSession = connection.Authenticate("testuser", key))
                            using (var channel = authSession.OpenExecChannel(
                                       "whoami",
                                       LIBSSH2_CHANNEL_EXTENDED_DATA.NORMAL))
                            {
                                channel.Close();
                            }
            }
        }
Exemple #13
0
        public async Task WhenServerRejectsLocale_ThenShellUsesDefaultLocale(
            [LinuxInstance(InitializeScript =
                               "sed -i '/AcceptEnv/d' /etc/ssh/sshd_config && systemctl restart sshd")]
            ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    await instanceLocatorTask,
                    "testuser",
                    key);

                var receiveBuffer = new StringBuilder();

                void receiveHandler(string data)
                {
                    lock (receiveBuffer)
                    {
                        receiveBuffer.Append(data);
                    }
                }

                using (var connection = new SshShellConnection(
                           "testuser",
                           endpoint,
                           key,
                           SshShellConnection.DefaultTerminal,
                           SshShellConnection.DefaultTerminalSize,
                           new CultureInfo("en-AU"),
                           receiveHandler,
                           exception =>
                {
                    Assert.Fail("Unexpected error");
                }))
                {
                    await connection.ConnectAsync();

                    AssertEx.ThrowsAggregateException <InvalidOperationException>(
                        () => connection.ConnectAsync().Wait());

                    await connection.SendAsync("locale;sleep 1;exit\n");

                    await AwaitBufferContentAsync(
                        receiveBuffer,
                        TimeSpan.FromSeconds(10),
                        "testuser");

                    StringAssert.Contains(
                        "LC_ALL=\r\n",
                        receiveBuffer.ToString());
                }
            }
        }
Exemple #14
0
        public async Task WhenSendingEchoCommand_ThenEchoIsReceived(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    await instanceLocatorTask,
                    "testuser",
                    key);

                var receiveBuffer = new StringBuilder();

                void receiveHandler(string data)
                {
                    lock (receiveBuffer)
                    {
                        receiveBuffer.Append(data);
                    }
                }

                using (var connection = new SshShellConnection(
                           "testuser",
                           endpoint,
                           key,
                           SshShellConnection.DefaultTerminal,
                           SshShellConnection.DefaultTerminalSize,
                           CultureInfo.InvariantCulture,
                           receiveHandler,
                           exception =>
                {
                    Assert.Fail("Unexpected error");
                }))
                {
                    await connection.ConnectAsync();

                    AssertEx.ThrowsAggregateException <InvalidOperationException>(
                        () => connection.ConnectAsync().Wait());

                    await connection.SendAsync("whoami\n");

                    await connection.SendAsync("exit\n");

                    await AwaitBufferContentAsync(
                        receiveBuffer,
                        TimeSpan.FromSeconds(10),
                        "testuser");

                    StringAssert.Contains(
                        "testuser",
                        receiveBuffer.ToString());
                }
            }
        }
        public async Task WhenLocaleIsNull_ThenShellUsesDefaultLocale(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    await instanceLocatorTask,
                    "testuser",
                    key);

                var receiveBuffer = new StringBuilder();

                void receiveHandler(string data)
                {
                    lock (receiveBuffer)
                    {
                        receiveBuffer.Append(data);
                    }
                }

                using (var connection = new SshShellConnection(
                           "testuser",
                           endpoint,
                           key,
                           SshShellConnection.DefaultTerminal,
                           SshShellConnection.DefaultTerminalSize,
                           null,
                           UnexpectedAuthenticationCallback,
                           receiveHandler,
                           UnexpectedErrorCallback))
                {
                    await connection.ConnectAsync();

                    AssertEx.ThrowsAggregateException <InvalidOperationException>(
                        () => connection.ConnectAsync().Wait());

                    await connection.SendAsync("locale;sleep 1;exit\n");

                    await AwaitBufferContentAsync(
                        receiveBuffer,
                        TimeSpan.FromSeconds(10),
                        "testuser");

                    StringAssert.Contains(
                        "LC_ALL=\r\n",
                        receiveBuffer.ToString());
                }
            }
        }
        public async Task WhenConnected_ThenTryActivateReturnsTrue(
            [LinuxInstance] ResourceTask <InstanceLocator> testInstance,
            [Credential(Role = PredefinedRole.ComputeInstanceAdminV1)] ResourceTask <ICredential> credential)
        {
            var locator = await testInstance;

            using (var key = new RsaSshKey(new RSACng()))
                using (var gceAdapter = new ComputeEngineAdapter(
                           this.serviceProvider.GetService <IAuthorizationAdapter>()))
                    using (var keyAdapter = new AuthorizedKeyService(
                               this.serviceProvider.GetService <IAuthorizationAdapter>(),
                               new ComputeEngineAdapter(await credential),
                               new ResourceManagerAdapter(await credential),
                               new Mock <IOsLoginService>().Object))
                    {
                        var authorizedKey = await keyAdapter.AuthorizeKeyAsync(
                            locator,
                            key,
                            TimeSpan.FromMinutes(10),
                            null,
                            AuthorizeKeyMethods.InstanceMetadata,
                            CancellationToken.None)
                                            .ConfigureAwait(true);

                        var instance = await gceAdapter.GetInstanceAsync(
                            locator,
                            CancellationToken.None)
                                       .ConfigureAwait(true);

                        // Connect
                        var broker = new SshTerminalSessionBroker(this.serviceProvider);

                        ISshTerminalSession session = null;
                        await AssertRaisesEventAsync <SessionStartedEvent>(
                            async() => session = await broker.ConnectAsync(
                                locator,
                                new IPEndPoint(instance.PublicAddress(), 22),
                                authorizedKey,
                                null,
                                TimeSpan.FromSeconds(10)));

                        Assert.IsNull(this.ExceptionShown);

                        Assert.AreSame(session, SshTerminalPane.TryGetActivePane(this.mainForm));
                        Assert.AreSame(session, SshTerminalPane.TryGetExistingPane(this.mainForm, locator));
                        Assert.IsTrue(broker.IsConnected(locator));
                        Assert.IsTrue(broker.TryActivate(locator));

                        AssertRaisesEvent <SessionEndedEvent>(
                            () => session.Close());
                    }
        }
Exemple #17
0
        public async Task WhenExistingInvalidManagedKeyFound_ThenNewKeyIsPushed()
        {
            using (var key = RsaSshKey.NewEphemeralKey())
            {
                var existingProjectKeySet = MetadataAuthorizedKeySet
                                            .FromMetadata(new Metadata())
                                            .Add(new ManagedMetadataAuthorizedKey(
                                                     "bob",
                                                     "ssh-rsa",
                                                     key.PublicKeyString,
                                                     new ManagedKeyMetadata(SampleEmailAddress, DateTime.UtcNow.AddMinutes(-5))));

                var computeEngineAdapter = CreateComputeEngineAdapterMock(
                    osLoginEnabledForProject: false,
                    osLoginEnabledForInstance: false,
                    osLogin2fa: false,
                    legacySshKeyPresent: false,
                    projectWideKeysBlockedForProject: false,
                    projectWideKeysBlockedForInstance: false,
                    existingProjectKeySet: existingProjectKeySet,
                    existingInstanceKeySet: null);
                var service = new AuthorizedKeyService(
                    CreateAuthorizationAdapterMock().Object,
                    computeEngineAdapter.Object,
                    CreateResourceManagerAdapterMock(true).Object,
                    CreateOsLoginServiceMock().Object);

                var authorizedKey = await service.AuthorizeKeyAsync(
                    SampleLocator,
                    key,
                    TimeSpan.FromMinutes(1),
                    "bob",
                    AuthorizeKeyMethods.All,
                    CancellationToken.None);

                Assert.IsNotNull(authorizedKey);
                Assert.AreEqual(AuthorizeKeyMethods.ProjectMetadata, authorizedKey.AuthorizationMethod);
                Assert.AreEqual("bob", authorizedKey.Username);

                computeEngineAdapter.Verify(a => a.UpdateMetadataAsync(
                                                It.IsAny <InstanceLocator>(),
                                                It.IsAny <Action <Metadata> >(),
                                                It.IsAny <CancellationToken>()), Times.Never);

                computeEngineAdapter.Verify(a => a.UpdateCommonInstanceMetadataAsync(
                                                It.IsAny <string>(),
                                                It.IsAny <Action <Metadata> >(),
                                                It.IsAny <CancellationToken>()), Times.Once);
            }
        }
        public async Task WhenPseudoterminalResized_ThenShellReflectsNewSize(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    await instanceLocatorTask,
                    "testuser",
                    key).ConfigureAwait(true);

                using (var session = CreateSession())
                    using (var connection = session.Connect(endpoint))
                        using (var authSession = connection.Authenticate(
                                   "testuser",
                                   key,
                                   UnexpectedAuthenticationCallback))
                            using (var channel = authSession.OpenShellChannel(
                                       LIBSSH2_CHANNEL_EXTENDED_DATA.MERGE,
                                       DefaultTerminal,
                                       80,
                                       24))
                            {
                                var welcome = ReadUntil(channel, "~$", Encoding.ASCII);

                                // Read initial terminal size.
                                channel.Write(Encoding.ASCII.GetBytes("echo $COLUMNS $LINES\n"));
                                ReadUntil(channel, "\n", Encoding.ASCII);

                                var terminalSize = ReadUntil(channel, "\n", Encoding.ASCII);
                                Assert.AreEqual("80 24\r\n", terminalSize);

                                // Resize terminal.
                                channel.ResizePseudoTerminal(100, 30);

                                // Read terminal size again.
                                channel.Write(Encoding.ASCII.GetBytes("echo $COLUMNS $LINES\n"));
                                ReadUntil(channel, "\n", Encoding.ASCII);

                                terminalSize = ReadUntil(channel, "\n", Encoding.ASCII);
                                Assert.AreEqual("100 30\r\n", terminalSize);

                                channel.Close();
                            }
            }
        }
        private async Task <SshTerminalPane> ConnectSshTerminalPane(
            InstanceLocator instanceLocator,
            ICredential credential)
        {
            var authorization = new Mock <IAuthorization>();

            authorization
            .SetupGet(a => a.Email)
            .Returns("*****@*****.**");
            var authorizationAdapter = new Mock <IAuthorizationAdapter>();

            authorizationAdapter
            .Setup(a => a.Authorization)
            .Returns(authorization.Object);

            using (var key = new RsaSshKey(new RSACng()))
                using (var keyAdapter = new AuthorizedKeyService(
                           authorizationAdapter.Object,
                           new ComputeEngineAdapter(credential),
                           new ResourceManagerAdapter(credential),
                           new Mock <IOsLoginService>().Object))
                {
                    var authorizedKey = await keyAdapter.AuthorizeKeyAsync(
                        instanceLocator,
                        key,
                        TimeSpan.FromMinutes(10),
                        null,
                        AuthorizeKeyMethods.InstanceMetadata,
                        CancellationToken.None)
                                        .ConfigureAwait(true);

                    // Connect and wait for event
                    SessionStartedEvent connectedEvent = null;
                    this.eventService.BindHandler <SessionStartedEvent>(e => connectedEvent = e);

                    var broker = new SshTerminalSessionBroker(
                        this.serviceProvider);
                    var pane = await broker.ConnectAsync(
                        instanceLocator,
                        new IPEndPoint(await PublicAddressFromLocator(instanceLocator), 22),
                        authorizedKey)
                               .ConfigureAwait(true);

                    Assert.IsNotNull(connectedEvent, "ConnectionSuceededEvent event fired");
                    PumpWindowMessages();

                    return((SshTerminalPane)pane);
                }
        }
        public async Task WhenWhitelistedEnvironmentVariablePassed_ThenShellCanAccessVariable(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    await instanceLocatorTask,
                    "testuser",
                    key).ConfigureAwait(true);

                using (var session = CreateSession())
                    using (var connection = session.Connect(endpoint))
                        using (var authSession = connection.Authenticate(
                                   "testuser",
                                   key,
                                   UnexpectedAuthenticationCallback))
                            using (var channel = authSession.OpenShellChannel(
                                       LIBSSH2_CHANNEL_EXTENDED_DATA.MERGE,
                                       DefaultTerminal,
                                       80,
                                       24,
                                       new[]
                            {
                                new EnvironmentVariable(
                                    "LANG",
                                    "LC_ALL",
                                    true) // LANG is whitelisted by sshd by default.
                            }))
                            {
                                var bytesWritten = channel.Write(Encoding.ASCII.GetBytes("echo $LANG;exit\n"));
                                Assert.AreEqual(16, bytesWritten);

                                var output = ReadToEnd(channel, Encoding.ASCII);
                                channel.Close();

                                StringAssert.Contains(
                                    "en_US.UTF-8",
                                    output);

                                Assert.AreEqual(0, channel.ExitCode);
                            }
            }
        }
        public async Task WhenPublicKeyValidButUnrecognized_ThenAuthenticateThrowsAuthenticationFailed(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var session = CreateSession())
                using (var connection = session.Connect(endpoint))
                    using (var key = new RsaSshKey(new RSACng()))
                    {
                        SshAssert.ThrowsNativeExceptionWithError(
                            session,
                            LIBSSH2_ERROR.AUTHENTICATION_FAILED,
                            () => connection.Authenticate("invaliduser", key));
                    }
        }
        public async Task WhenConnected_ThenOpenShellChannelAsyncSucceeds(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    await instanceLocatorTask,
                    "testuser",
                    key).ConfigureAwait(true);

                using (var session = CreateSession())
                    using (var connection = session.Connect(endpoint))
                        using (var authSession = connection.Authenticate(
                                   "testuser",
                                   key,
                                   UnexpectedAuthenticationCallback))
                            using (var channel = authSession.OpenShellChannel(
                                       LIBSSH2_CHANNEL_EXTENDED_DATA.MERGE,
                                       DefaultTerminal,
                                       80,
                                       24))
                            {
                                // Run command.
                                var bytesWritten = channel.Write(Encoding.ASCII.GetBytes("whoami;exit\n"));
                                Assert.AreEqual(12, bytesWritten);

                                // Read command output.
                                var output = ReadToEnd(channel, Encoding.ASCII);
                                channel.Close();

                                StringAssert.Contains(
                                    "whoami;exit\r\ntestuser\r\nlogout\r\n",
                                    output);

                                Assert.AreEqual(0, channel.ExitCode);
                                Assert.AreEqual(null, channel.ExitSignal);
                            }
            }
        }
Exemple #23
0
        public async Task WhenCommandInvalidAndExtendedDataModeIsNormal_ThenExecuteSucceedsAndStderrContainsError(
            [LinuxInstance] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    await instanceLocatorTask,
                    "testuser",
                    key).ConfigureAwait(true);

                using (var session = CreateSession())
                    using (var connection = session.Connect(endpoint))
                        using (var authSession = connection.Authenticate(
                                   "testuser",
                                   key,
                                   UnexpectedAuthenticationCallback))
                            using (var channel = authSession.OpenExecChannel(
                                       "invalidcommand",
                                       LIBSSH2_CHANNEL_EXTENDED_DATA.NORMAL))
                            {
                                channel.WaitForEndOfStream();

                                var buffer    = new byte[1024];
                                var bytesRead = channel.Read(
                                    buffer,
                                    LIBSSH2_STREAM.EXTENDED_DATA_STDERR);
                                Assert.AreNotEqual(0, bytesRead);

                                Assert.AreEqual(
                                    "bash: invalidcommand: command not found\n",
                                    Encoding.ASCII.GetString(buffer, 0, (int)bytesRead));

                                Assert.AreEqual(127, channel.ExitCode);
                                Assert.IsNull(channel.ExitSignal);
                                channel.Close();
                            }
            }
        }
Exemple #24
0
        public void WhenMetadataUpdatesFails_ThenAuthorizeKeyAsyncThrowsSshKeyPushFailedException(
            [Values(
                 HttpStatusCode.Forbidden,
                 HttpStatusCode.BadRequest)] HttpStatusCode httpStatus)
        {
            var computeEngineAdapter = CreateComputeEngineAdapterMock(
                osLoginEnabledForProject: null,
                osLoginEnabledForInstance: null,
                osLogin2fa: false,
                legacySshKeyPresent: false,
                projectWideKeysBlockedForProject: false,
                projectWideKeysBlockedForInstance: false);

            computeEngineAdapter
            .Setup(a => a.UpdateCommonInstanceMetadataAsync(
                       It.IsAny <string>(),
                       It.IsAny <Action <Metadata> >(),
                       It.IsAny <CancellationToken>()))
            .Throws(new GoogleApiException("GCE", "mock-error")
            {
                HttpStatusCode = httpStatus
            });

            var service = new AuthorizedKeyService(
                CreateAuthorizationAdapterMock().Object,
                computeEngineAdapter.Object,
                CreateResourceManagerAdapterMock(true).Object,
                CreateOsLoginServiceMock().Object);

            using (var key = RsaSshKey.NewEphemeralKey())
            {
                AssertEx.ThrowsAggregateException <SshKeyPushFailedException>(
                    () => service.AuthorizeKeyAsync(
                        SampleLocator,
                        key,
                        TimeSpan.FromMinutes(1),
                        null,
                        AuthorizeKeyMethods.All,
                        CancellationToken.None).Wait());
            }
        }
        public async Task WhenWrongPort_ThenErrorIsShownAndWindowIsClosed()
        {
            using (var key = new RsaSshKey(new RSACng()))
            {
                SessionAbortedEvent deliveredEvent = null;
                this.eventService.BindHandler <SessionAbortedEvent>(e => deliveredEvent = e);

                var broker = new SshTerminalSessionBroker(
                    this.serviceProvider);
                await broker.ConnectAsync(
                    new InstanceLocator("project-1", "zone-1", "instance-1"),
                    NonSshEndpoint,
                    AuthorizedKey.ForMetadata(key, "test", true, null))
                .ConfigureAwait(true);

                Assert.IsNotNull(deliveredEvent, "Event fired");
                Assert.IsInstanceOf(typeof(SocketException), this.ExceptionShown);
                Assert.AreEqual(
                    SocketError.ConnectionRefused,
                    ((SocketException)this.ExceptionShown).SocketErrorCode);
            }
        }
        public async Task When2faRequiredAndPromptReturnsNull_ThenPromptIsRetried(
            [LinuxInstance(InitializeScript = RequireSshPassword)] ResourceTask <InstanceLocator> instanceLocatorTask)
        {
            var endpoint = new IPEndPoint(
                await InstanceUtil.PublicIpAddressForInstanceAsync(await instanceLocatorTask),
                22);

            using (var key = new RsaSshKey(new RSACng()))
            {
                await InstanceUtil.AddPublicKeyToMetadata(
                    await instanceLocatorTask,
                    "testuser",
                    key);

                using (var session = CreateSession())
                    using (var connection = session.Connect(endpoint))
                    {
                        var callbackCount = 0;

                        SshAssert.ThrowsNativeExceptionWithError(
                            session,
                            LIBSSH2_ERROR.AUTHENTICATION_FAILED,
                            () => connection.Authenticate(
                                "testuser",
                                key,
                                (name, instruction, prompt, echo) =>
                        {
                            callbackCount++;

                            Assert.AreEqual("Password: ", prompt);
                            Assert.IsFalse(echo);

                            return(null);
                        }));
                        Assert.AreEqual(SshConnectedSession.KeyboardInteractiveRetries, callbackCount);
                    }
            }
        }
        //---------------------------------------------------------------------
        // ISshConnectionService.
        //---------------------------------------------------------------------

        public async Task ActivateOrConnectInstanceAsync(IProjectModelInstanceNode vmNode)
        {
            Debug.Assert(vmNode.IsSshSupported());

            if (this.sessionBroker.TryActivate(vmNode.Instance))
            {
                // SSH session was active, nothing left to do.
                return;
            }

            // Select node so that tracking windows are updated.
            await this.projectModelService.SetActiveNodeAsync(
                vmNode,
                CancellationToken.None)
            .ConfigureAwait(true);

            var instance = vmNode.Instance;
            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.Instance,
                        (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 sshSettings       = this.sshSettingsRepository.GetSettings();
                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.Instance,
                               sshKey,
                               TimeSpan.FromSeconds(sshSettings.PublicKeyValidity.IntValue),
                               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);

                var language = sshSettings.IsPropagateLocaleEnabled.BoolValue
                     ? CultureInfo.CurrentUICulture
                     : null;

                //
                // 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,
                    language,
                    timeout)
                .ConfigureAwait(true);
            }
            catch (Exception)
            {
                sshKey.Dispose();
                throw;
            }
        }