Exemplo n.º 1
0
        /// <summary>
        ///   Opens the connection
        /// </summary>
        private async Task OpenAsyncInternal(Logger logger)
        {
            //switch state to connecting if not done so
            int state = Interlocked.CompareExchange(ref _connectionState, 1, 0);

            if (state == 1)
                return;

            if (state == 2)
                throw new ObjectDisposedException("Connection disposed before opening!");

            try
            {
                //create TCP connection
                _client = new TcpClient();
                await _client.ConnectAsync(_address, _cluster.Config.Port).ConfigureAwait(false);
                _writeStream = _client.GetStream();
                _readStream = _client.GetStream();

                logger.LogVerbose("TCP connection to {0} is opened", Address);

                //start readloop
                StartReadingAsync();

                //get compression option
                _allowCompression = false; //assume false unless
                if (_cluster.Config.AllowCompression)
                {
                    //check wether compression is supported by getting compression options from server
                    var options = new OptionsFrame();
                    var supported =
                        await SendRequestAsync(options, logger, 1, true).ConfigureAwait(false) as SupportedFrame;

                    if (supported == null)
                        throw new ProtocolException(0, "Expected Supported frame not received");

                    IList<string> compressionOptions;
                    //check if options contain compression
                    if (supported.SupportedOptions.TryGetValue("COMPRESSION", out compressionOptions))
                    {
                        //check wether snappy is supported
                        _allowCompression = compressionOptions.Contains("snappy");
                    }

                    //dispose supported frame
                    supported.Dispose();
                }

                //submit startup frame
                var startup = new StartupFrame(_cluster.Config.CqlVersion);
                if (_allowCompression)
                {
                    logger.LogVerbose("Enabling Snappy Compression.");
                    startup.Options["COMPRESSION"] = "snappy";
                }

                Frame response = await SendRequestAsync(startup, logger, 1, true).ConfigureAwait(false);

                //authenticate if required
                var auth = response as AuthenticateFrame;
                if (auth != null)
                {
                    logger.LogVerbose("Authentication requested, attempting to provide credentials", Address);

                    //check if _username is actually set
                    if (_cluster.Config.Username == null || _cluster.Config.Password == null)
                        throw new UnauthorizedException("No credentials provided");

                    //dispose AuthenticateFrame
                    response.Dispose();

                    var cred = new CredentialsFrame(_cluster.Config.Username, _cluster.Config.Password);
                    response = await SendRequestAsync(cred, logger, 1, true).ConfigureAwait(false);
                }

                //check if ready
                if (!(response is ReadyFrame))
                    throw new ProtocolException(0, "Expected Ready frame not received");

                //dispose ready frame
                response.Dispose();

                using (logger.ThreadBinding())
                {
                    if (OnConnectionChange != null)
                        OnConnectionChange(this, new ConnectionChangeEvent { Connected = true });
                }

                logger.LogInfo("{0} is opened and ready for use", this);
            }
            catch (Exception ex)
            {
                using (logger.ThreadBinding())
                {
                    Dispose(true, ex);
                    throw;
                }
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Authenticates the connection.
        /// </summary>
        /// <param name="auth">The authentication request from the server.</param>
        /// <param name="logger">The logger.</param>
        /// <returns></returns>
        /// <exception cref="AuthenticationException">
        /// Unsupported Authenticator:  + auth.Authenticator;null
        /// or
        /// Authentication failed, SASL Challenge was rejected by client
        /// or
        /// Authentication failed, Authenticator rejected SASL result
        /// or
        /// Expected a Authentication Challenge from Server!
        /// or
        /// No credentials provided in configuration
        /// or
        /// Authentication failed: Ready frame not received
        /// </exception>
        private async Task AuthenticateAsync(AuthenticateFrame auth, Logger logger)
        {
            logger.LogVerbose("Authentication requested, attempting to provide credentials");

            //dispose AuthenticateFrame
            auth.Dispose();

            if (auth.ProtocolVersion >= 2)
            {
                //protocol version2: use SASL AuthResponse to authenticate

                //get an AuthenticatorFactory
                IAuthenticatorFactory factory =
                    Loader.Extensions.AuthenticationFactories.FirstOrDefault(
                        f => f.Name.Equals(auth.Authenticator, StringComparison.OrdinalIgnoreCase));

                if (factory == null)
                    throw new AuthenticationException(auth.ProtocolVersion, "Unsupported Authenticator: " + auth.Authenticator);

                logger.LogVerbose("Attempting authentication for scheme {0}", factory.Name);

                //grab an authenticator instance
                IAuthenticator authenticator = factory.CreateAuthenticator(_config);

                //start authentication loop
                byte[] saslChallenge = null;
                while (true)
                {
                    //check for challenge
                    byte[] saslResponse;
                    if (!authenticator.Authenticate(auth.ProtocolVersion, saslChallenge, out saslResponse))
                    {
                        throw new AuthenticationException(auth.ProtocolVersion, "Authentication failed, SASL Challenge was rejected by client");
                    }

                    //send response
                    var cred = new AuthResponseFrame(saslResponse);
                    var authResponse =
                        await
                            SendRequestAsyncInternal(cred, logger, 1, CancellationToken.None).AutoConfigureAwait();

                    //dispose authResponse (makes sure all is read)
                    authResponse.Dispose();

                    //check for success
                    var success = authResponse as AuthSuccessFrame;
                    if (success != null)
                    {
                        if (!authenticator.Authenticate(auth.ProtocolVersion, success.SaslResult))
                        {
                            throw new AuthenticationException(authResponse.ProtocolVersion, "Authentication failed, Authenticator rejected SASL result", authResponse.TracingId);
                        }

                        //yeah, authenticated, break from the authentication loop
                        break;
                    }

                    //no success yet, lets try next round
                    var challenge = authResponse as AuthChallengeFrame;
                    if (challenge == null)
                    {
                        throw new AuthenticationException(authResponse.ProtocolVersion, "Expected a Authentication Challenge from Server!", authResponse.TracingId);
                    }

                    saslChallenge = challenge.SaslChallenge;
                }
            }
            else
            {
                //protocol version1: use Credentials to authenticate

                //check if _username is actually set
                if (_config.Username == null || _config.Password == null)
                    throw new AuthenticationException(auth.ProtocolVersion, "No credentials provided in configuration");

                var cred = new CredentialsFrame(_config.Username, _config.Password);
                var authResponse =
                    await
                        SendRequestAsyncInternal(cred, logger, 1, CancellationToken.None).AutoConfigureAwait();

                //dispose authResponse (makes sure all is read)
                authResponse.Dispose();

                if (!(authResponse is ReadyFrame))
                {
                    throw new AuthenticationException(authResponse.ProtocolVersion, "Authentication failed: Ready frame not received", authResponse.TracingId);
                }
            }
        }