예제 #1
0
        /// <inheritdoc />
        public async Task <ITransport?> DoHandshakeAsync(CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            _logger.LogDebug("Doing protocol handshake...");

            ITransport currentTransport = _context.Transport ?? throw new InvalidOperationException("Cannot do handshake before a transport has been created.");

            // Negotiate the protocol version that both sides will use
            RfbProtocolVersion protocolVersion = await NegotiateProtocolVersionAsync(currentTransport, cancellationToken).ConfigureAwait(false);

            _state.ProtocolVersion = protocolVersion;

            // Negotiate which security type will be used
            ISecurityType usedSecurityType = await NegotiateSecurityTypeAsync(currentTransport, cancellationToken).ConfigureAwait(false);

            _state.UsedSecurityType = usedSecurityType;

            // Execute authentication
            _logger.LogDebug("Negotiated security type: {name}({id}). Authenticating...", usedSecurityType.Name, usedSecurityType.Id);
            AuthenticationResult authenticationResult = await usedSecurityType
                                                        .AuthenticateAsync(_context.Connection.Parameters.AuthenticationHandler, cancellationToken).ConfigureAwait(false);

            // When a tunnel was built, use that transport for further communication
            if (authenticationResult.TunnelTransport != null)
            {
                currentTransport = authenticationResult.TunnelTransport;
            }

            if (authenticationResult.ExpectSecurityResult)
            {
                // Read the security result
                ReadOnlyMemory <byte> securityResultBytes = await currentTransport.Stream.ReadAllAsync(4, cancellationToken).ConfigureAwait(false);

                uint securityResult = BinaryPrimitives.ReadUInt32BigEndian(securityResultBytes.Span);

                // Authentication failed?
                if (securityResult > 0)
                {
                    // From version 3.8 onwards the server sends a reason
                    if (protocolVersion >= RfbProtocolVersion.RFB_3_8)
                    {
                        string reason = await ReadFailureReasonAsync(currentTransport, cancellationToken).ConfigureAwait(false);

                        throw new HandshakeFailedException($"Authentication failed: {reason}");
                    }

                    // There is no reason
                    throw new HandshakeFailedException("Authentication failed" + (securityResult == 2 ? " because of too many attempts." : "."));
                }
            }

            return(authenticationResult.TunnelTransport);
        }
예제 #2
0
        /// <inhertitdoc />
        public async Task <TInput> ProvideAuthenticationInputAsync <TInput>(RfbConnection connection, ISecurityType securityType, IAuthenticationInputRequest <TInput> request)
            where TInput : class, IAuthenticationInput
        {
            if (typeof(TInput) == typeof(PasswordAuthenticationInput))
            {
                string?password = await Dispatcher.UIThread.InvokeAsync(async() => await EnterPasswordInteraction.Handle(Unit.Default)).ConfigureAwait(false);

                // TODO: Implement canceling of authentication input requests instead of passing an empty password!
                if (password == null)
                {
                    password = string.Empty;
                }

                return((TInput)Convert.ChangeType(new PasswordAuthenticationInput(password), typeof(TInput)));
            }

            throw new InvalidOperationException("The authentication input request is not supported by the interactive authentication handler.");
        }