Esempio n. 1
0
        private async Task EstablishSessionAsync(IServerChannel channel, CancellationToken cancellationToken)
        {
            try
            {
                cancellationToken.ThrowIfCancellationRequested();

                _serverConnectedNodesDictionary.Add(channel.SessionId, channel);

                var timeoutToken = new CancellationTokenSource(TimeSpan.FromSeconds(60));

                var newSession = await channel.ReceiveNewSessionAsync(
                    CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token).Token);

                timeoutToken = new CancellationTokenSource(TimeSpan.FromSeconds(60));

                var negotiatedSession = await channel.NegotiateSessionAsync(
                    channel.Transport.GetSupportedCompression(),
                    channel.Transport.GetSupportedEncryption(),
                    CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token).Token);

                if (negotiatedSession.State == SessionState.Negotiating &&
                    negotiatedSession.Compression != null &&
                    negotiatedSession.Encryption != null)
                {                    
                    await channel.SendNegotiatingSessionAsync(
                        negotiatedSession.Compression.Value,
                        negotiatedSession.Encryption.Value
                        );

                    timeoutToken = new CancellationTokenSource(TimeSpan.FromSeconds(60));

                    if (channel.Transport.Compression != negotiatedSession.Compression.Value)
                    {
                        await channel.Transport.SetCompressionAsync(
                            negotiatedSession.Compression.Value,
                            CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token).Token);
                    }

                    if (channel.Transport.Encryption != negotiatedSession.Encryption.Value)
                    {
                        await channel.Transport.SetEncryptionAsync(
                            negotiatedSession.Encryption.Value,
                            CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token).Token);
                    }

                    timeoutToken = new CancellationTokenSource(TimeSpan.FromSeconds(60));

                    var authenticatedSession = await channel.AuthenticateSessionAsync(
                        new AuthenticationScheme[] { AuthenticationScheme.Plain, AuthenticationScheme.Transport },
                        CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token).Token);

                    if (authenticatedSession.Authentication != null &&
                        authenticatedSession.From != null &&
                        authenticatedSession.From.Domain.Equals(_serverNode.Domain, StringComparison.OrdinalIgnoreCase))
                    {
                        if (authenticatedSession.Authentication is PlainAuthentication)
                        {
                            var plainAuthentication = authenticatedSession.Authentication as PlainAuthentication;

                            string password;

                            if (_identityPasswordDictionary.TryGetValue(authenticatedSession.From.ToIdentity(), out password) &&
                                password.Equals(plainAuthentication.GetFromBase64Password()))
                            {
                                await RegisterChannel(channel, authenticatedSession.From, cancellationToken);
                            }
                            else
                            {
                                await channel.SendFailedSessionAsync(
                                    new Reason()
                                    {
                                        Code = ReasonCodes.SESSION_AUTHENTICATION_FAILED,
                                        Description = "Invalid username or password"
                                    });
                            }

                        }
                        else if (authenticatedSession.Authentication is TransportAuthentication)
                        {
                            var transportAuthentication = authenticatedSession.Authentication as PlainAuthentication;

                            if (channel.Transport is IAuthenticatableTransport)
                            {
                                var authenticableTransport = channel.Transport as IAuthenticatableTransport;

                                if (await authenticableTransport.AuthenticateAsync(authenticatedSession.From.ToIdentity()) != DomainRole.Unknown)
                                {
                                    await RegisterChannel(channel, authenticatedSession.From, cancellationToken);
                                }
                                else
                                {
                                    await channel.SendFailedSessionAsync(
                                        new Reason()
                                        {
                                            Code = ReasonCodes.SESSION_AUTHENTICATION_FAILED,
                                            Description = "The authentication failed"
                                        });
                                }
                            }
                            else
                            {
                                await channel.SendFailedSessionAsync(
                                    new Reason()
                                    {
                                        Code = ReasonCodes.SESSION_AUTHENTICATION_FAILED,
                                        Description = "The current transport doesn't support authentication"
                                    });
                            }

                        }
                        else
                        {
                            await channel.SendFailedSessionAsync(
                                new Reason()
                                {
                                    Code = ReasonCodes.SESSION_AUTHENTICATION_FAILED,
                                    Description = "Unsupported authenticaiton scheme"
                                });
                        }
                    }
                    else
                    {
                        await channel.SendFailedSessionAsync(
                            new Reason()
                            {
                                Code = ReasonCodes.SESSION_AUTHENTICATION_FAILED,
                                Description = "Invalid user"
                            });
                    }
                }
                else
                {
                    await channel.SendFailedSessionAsync(
                        new Reason()
                        {
                            Code = 1,
                            Description = "Invalid selected negotiation options"
                        });
                }
            }
            finally
            {
                channel.DisposeIfDisposable();
            }            
        }
Esempio n. 2
0
        private static async Task AuthenticateSessionAsync(
            IServerChannel channel,
            AuthenticationScheme[] schemeOptions,
            Func <Identity, Authentication, CancellationToken, Task <AuthenticationResult> > authenticationFunc,
            Func <Node, IServerChannel, CancellationToken, Task <Node> > registrationFunc,
            CancellationToken cancellationToken)
        {
            // Sends the authentication options and awaits for the authentication
            var receivedSession = await channel.AuthenticateSessionAsync(schemeOptions, cancellationToken);

            while (receivedSession.State == SessionState.Authenticating &&
                   receivedSession.From != null &&
                   receivedSession.Authentication != null &&
                   receivedSession.Scheme != null &&
                   schemeOptions.Contains(receivedSession.Scheme.Value))
            {
                cancellationToken.ThrowIfCancellationRequested();

                if (receivedSession.Authentication is TransportAuthentication transportAuthentication)
                {
                    await AuthenticateAsTransportAsync(channel, transportAuthentication, receivedSession.From.ToIdentity());
                }

                var authenticationResult = await authenticationFunc(
                    receivedSession.From.ToIdentity(),
                    receivedSession.Authentication,
                    cancellationToken);

                if (authenticationResult.DomainRole != DomainRole.Unknown)
                {
                    var registeredNode = await registrationFunc(receivedSession.From, channel, cancellationToken);

                    if (registeredNode != null)
                    {
                        await channel.SendEstablishedSessionAsync(registeredNode, cancellationToken);
                    }
                    else
                    {
                        await channel.SendFailedSessionAsync(
                            new Reason()
                        {
                            Code        = ReasonCodes.SESSION_REGISTRATION_ERROR,
                            Description = "The session instance registration failed"
                        },
                            cancellationToken);
                    }

                    break;
                }

                if (authenticationResult.Roundtrip != null)
                {
                    receivedSession =
                        await channel.AuthenticateSessionAsync(authenticationResult.Roundtrip, cancellationToken);
                }
                else
                {
                    await channel.SendFailedSessionAsync(
                        new Reason()
                    {
                        Code        = ReasonCodes.SESSION_AUTHENTICATION_FAILED,
                        Description = "The session authentication failed"
                    },
                        cancellationToken);

                    break;
                }
            }
        }
        /// <summary>
        /// Establishes a server channel with transport options negotiation and authentication.
        /// </summary>
        /// <param name="channel">The channel.</param>
        /// <param name="enabledCompressionOptions">The enabled compression options.</param>
        /// <param name="enabledEncryptionOptions">The enabled encryption options.</param>
        /// <param name="schemeOptions">The scheme options.</param>
        /// <param name="authenticateFunc">The authenticate function.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns></returns>
        /// <exception cref="System.ArgumentNullException">
        /// </exception>
        /// <exception cref="System.ArgumentException">
        /// The transport doesn't support one or more of the specified compression options
        /// or
        /// The transport doesn't support one or more of the specified compression options
        /// or
        /// The authentication scheme options is mandatory
        /// </exception>
        public static async Task EstablishSessionAsync(
            this IServerChannel channel,
            SessionCompression[] enabledCompressionOptions,
            SessionEncryption[] enabledEncryptionOptions,
            AuthenticationScheme[] schemeOptions,
            Func <Node, Authentication, AuthenticationResult> authenticateFunc,
            CancellationToken cancellationToken)
        {
            if (channel == null)
            {
                throw new ArgumentNullException(nameof(channel));
            }
            if (enabledCompressionOptions == null ||
                enabledCompressionOptions.Length == 0 ||
                enabledCompressionOptions.Any(o => !channel.Transport.GetSupportedCompression().Contains(o)))
            {
                throw new ArgumentException("The transport doesn't support one or more of the specified compression options", nameof(enabledCompressionOptions));
            }

            if (enabledEncryptionOptions == null ||
                enabledEncryptionOptions.Length == 0 ||
                enabledEncryptionOptions.Any(o => !channel.Transport.GetSupportedEncryption().Contains(o)))
            {
                throw new ArgumentException("The transport doesn't support one or more of the specified compression options", nameof(enabledEncryptionOptions));
            }

            if (schemeOptions == null)
            {
                throw new ArgumentNullException(nameof(schemeOptions));
            }
            if (schemeOptions.Length == 0)
            {
                throw new ArgumentException("The authentication scheme options is mandatory", nameof(schemeOptions));
            }
            if (authenticateFunc == null)
            {
                throw new ArgumentNullException(nameof(authenticateFunc));
            }

            // Awaits for the 'new' session envelope
            var receivedSession = await channel.ReceiveNewSessionAsync(cancellationToken).ConfigureAwait(false);

            if (receivedSession.State == SessionState.New)
            {
                // Check if there's any transport option to negotiate
                var compressionOptions = enabledCompressionOptions.Intersect(channel.Transport.GetSupportedCompression()).ToArray();
                var encryptionOptions  = enabledEncryptionOptions.Intersect(channel.Transport.GetSupportedEncryption()).ToArray();

                if (compressionOptions.Length > 1 || encryptionOptions.Length > 1)
                {
                    // Negotiate the transport options
                    receivedSession = await channel.NegotiateSessionAsync(
                        compressionOptions,
                        encryptionOptions,
                        cancellationToken).ConfigureAwait(false);

                    // Validate the selected options
                    if (receivedSession.State == SessionState.Negotiating &&
                        receivedSession.Compression != null &&
                        compressionOptions.Contains(receivedSession.Compression.Value) &&
                        receivedSession.Encryption != null &&
                        encryptionOptions.Contains(receivedSession.Encryption.Value))
                    {
                        await channel.SendNegotiatingSessionAsync(
                            receivedSession.Compression.Value,
                            receivedSession.Encryption.Value, cancellationToken);

                        if (channel.Transport.Compression != receivedSession.Compression.Value)
                        {
                            await channel.Transport.SetCompressionAsync(
                                receivedSession.Compression.Value,
                                cancellationToken);
                        }

                        if (channel.Transport.Encryption != receivedSession.Encryption.Value)
                        {
                            await channel.Transport.SetEncryptionAsync(
                                receivedSession.Encryption.Value,
                                cancellationToken);
                        }
                    }
                    else
                    {
                        await channel.SendFailedSessionAsync(new Reason()
                        {
                            Code        = ReasonCodes.SESSION_NEGOTIATION_INVALID_OPTIONS,
                            Description = "An invalid negotiation option was selected"
                        }, cancellationToken);
                    }
                }

                if (channel.State != SessionState.Failed)
                {
                    // Sends the authentication options and awaits for the authentication
                    receivedSession = await channel.AuthenticateSessionAsync(schemeOptions, cancellationToken);

                    if (receivedSession.State == SessionState.Authenticating &&
                        receivedSession.Authentication != null &&
                        receivedSession.Scheme != null &&
                        schemeOptions.Contains(receivedSession.Scheme.Value))
                    {
                        while (channel.State == SessionState.Authenticating)
                        {
                            cancellationToken.ThrowIfCancellationRequested();

                            var authenticationResult = authenticateFunc(receivedSession.From, receivedSession.Authentication);
                            if (authenticationResult.Roundtrip != null)
                            {
                                receivedSession = await channel.AuthenticateSessionAsync(authenticationResult.Roundtrip, cancellationToken);
                            }
                            else if (authenticationResult.Node != null)
                            {
                                await channel.SendEstablishedSessionAsync(authenticationResult.Node, cancellationToken);
                            }
                            else
                            {
                                await channel.SendFailedSessionAsync(new Reason()
                                {
                                    Code        = ReasonCodes.SESSION_AUTHENTICATION_FAILED,
                                    Description = "The session authentication failed"
                                }, cancellationToken);
                            }
                        }
                    }
                }
            }
        }
Esempio n. 4
0
        private async Task EstablishSessionAsync(IServerChannel channel, CancellationToken cancellationToken)
        {
            try
            {
                cancellationToken.ThrowIfCancellationRequested();

                _serverConnectedNodesDictionary.Add(channel.SessionId, channel);

                var timeoutToken = new CancellationTokenSource(TimeSpan.FromSeconds(60));

                var newSession = await channel.ReceiveNewSessionAsync(
                    CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token).Token);

                timeoutToken = new CancellationTokenSource(TimeSpan.FromSeconds(60));

                var negotiatedSession = await channel.NegotiateSessionAsync(
                    channel.Transport.GetSupportedCompression(),
                    channel.Transport.GetSupportedEncryption(),
                    CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token).Token);

                if (negotiatedSession.State == SessionState.Negotiating &&
                    negotiatedSession.Compression != null &&
                    negotiatedSession.Encryption != null)
                {
                    await channel.SendNegotiatingSessionAsync(
                        negotiatedSession.Compression.Value,
                        negotiatedSession.Encryption.Value
                        );

                    timeoutToken = new CancellationTokenSource(TimeSpan.FromSeconds(60));

                    if (channel.Transport.Compression != negotiatedSession.Compression.Value)
                    {
                        await channel.Transport.SetCompressionAsync(
                            negotiatedSession.Compression.Value,
                            CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token).Token);
                    }

                    if (channel.Transport.Encryption != negotiatedSession.Encryption.Value)
                    {
                        await channel.Transport.SetEncryptionAsync(
                            negotiatedSession.Encryption.Value,
                            CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token).Token);
                    }

                    timeoutToken = new CancellationTokenSource(TimeSpan.FromSeconds(60));

                    var authenticatedSession = await channel.AuthenticateSessionAsync(
                        new AuthenticationScheme[] { AuthenticationScheme.Plain, AuthenticationScheme.Transport },
                        CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, timeoutToken.Token).Token);

                    if (authenticatedSession.Authentication != null &&
                        authenticatedSession.From != null &&
                        authenticatedSession.From.Domain.Equals(_serverNode.Domain, StringComparison.OrdinalIgnoreCase))
                    {
                        if (authenticatedSession.Authentication is PlainAuthentication)
                        {
                            var plainAuthentication = authenticatedSession.Authentication as PlainAuthentication;

                            string password;

                            if (_identityPasswordDictionary.TryGetValue(authenticatedSession.From.ToIdentity(), out password) &&
                                password.Equals(plainAuthentication.GetFromBase64Password()))
                            {
                                await RegisterChannel(channel, authenticatedSession.From, cancellationToken);
                            }
                            else
                            {
                                await channel.SendFailedSessionAsync(
                                    new Reason()
                                {
                                    Code        = ReasonCodes.SESSION_AUTHENTICATION_FAILED,
                                    Description = "Invalid username or password"
                                });
                            }
                        }
                        else if (authenticatedSession.Authentication is TransportAuthentication)
                        {
                            var transportAuthentication = authenticatedSession.Authentication as PlainAuthentication;

                            if (channel.Transport is IAuthenticatableTransport)
                            {
                                var authenticableTransport = channel.Transport as IAuthenticatableTransport;

                                if (await authenticableTransport.AuthenticateAsync(authenticatedSession.From.ToIdentity()) != DomainRole.Unknown)
                                {
                                    await RegisterChannel(channel, authenticatedSession.From, cancellationToken);
                                }
                                else
                                {
                                    await channel.SendFailedSessionAsync(
                                        new Reason()
                                    {
                                        Code        = ReasonCodes.SESSION_AUTHENTICATION_FAILED,
                                        Description = "The authentication failed"
                                    });
                                }
                            }
                            else
                            {
                                await channel.SendFailedSessionAsync(
                                    new Reason()
                                {
                                    Code        = ReasonCodes.SESSION_AUTHENTICATION_FAILED,
                                    Description = "The current transport doesn't support authentication"
                                });
                            }
                        }
                        else
                        {
                            await channel.SendFailedSessionAsync(
                                new Reason()
                            {
                                Code        = ReasonCodes.SESSION_AUTHENTICATION_FAILED,
                                Description = "Unsupported authenticaiton scheme"
                            });
                        }
                    }
                    else
                    {
                        await channel.SendFailedSessionAsync(
                            new Reason()
                        {
                            Code        = ReasonCodes.SESSION_AUTHENTICATION_FAILED,
                            Description = "Invalid user"
                        });
                    }
                }
                else
                {
                    await channel.SendFailedSessionAsync(
                        new Reason()
                    {
                        Code        = 1,
                        Description = "Invalid selected negotiation options"
                    });
                }
            }
            finally
            {
                channel.DisposeIfDisposable();
            }
        }