/// <summary> /// Reads a packet from a stream. /// </summary> /// <param name="stream"> The stream. </param> /// <returns> </returns> internal static async Task<Frame> FromStream(Stream stream) { //read header int read = 0; var header = new byte[8]; while (read < 8) read += await stream.ReadAsync(header, read, 8 - read).ConfigureAwait(false); //get length if (BitConverter.IsLittleEndian) Array.Reverse(header, 4, 4); int length = BitConverter.ToInt32(header, 4); Frame frame; switch ((FrameOpcode)header[3]) { case FrameOpcode.Error: frame = new ErrorFrame(); break; case FrameOpcode.Ready: frame = new ReadyFrame(); break; case FrameOpcode.Authenticate: frame = new AuthenticateFrame(); break; case FrameOpcode.Supported: frame = new SupportedFrame(); break; case FrameOpcode.Result: frame = new ResultFrame(); break; case FrameOpcode.Event: frame = new EventFrame(); break; default: throw new ProtocolException(0, "Unexpected OpCode received."); } frame.Version = (FrameVersion)header[0]; frame.Flags = (FrameFlags)header[1]; frame.Stream = unchecked((sbyte)header[2]); frame.OpCode = (FrameOpcode)header[3]; frame.Length = length; //wrap the stream in a window, that will be completely read when disposed var reader = new FrameReader(stream, length); frame.Reader = reader; //decompress the contents of the frame (implicity loads the entire frame body!) if (frame.Flags.HasFlag(FrameFlags.Compression)) await reader.DecompressAsync(); //read tracing id if set if (frame.Flags.HasFlag(FrameFlags.Tracing)) frame.TracingId = await reader.ReadUuidAsync().ConfigureAwait(false); await frame.InitializeAsync().ConfigureAwait(false); return frame; }
/// <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); } } }
/// <summary> /// Reads a packet from a stream. /// </summary> /// <param name="stream"> The stream. </param> /// <returns> </returns> internal static async Task <Frame> FromStream(Stream stream) { //read header int read = 0; var header = new byte[8]; while (read < 8) { read += await stream.ReadAsync(header, read, 8 - read).ConfigureAwait(false); } //get length if (BitConverter.IsLittleEndian) { Array.Reverse(header, 4, 4); } int length = BitConverter.ToInt32(header, 4); Frame frame; switch ((FrameOpcode)header[3]) { case FrameOpcode.Error: frame = new ErrorFrame(); break; case FrameOpcode.Ready: frame = new ReadyFrame(); break; case FrameOpcode.Authenticate: frame = new AuthenticateFrame(); break; case FrameOpcode.Supported: frame = new SupportedFrame(); break; case FrameOpcode.Result: frame = new ResultFrame(); break; case FrameOpcode.Event: frame = new EventFrame(); break; default: throw new ProtocolException(0, "Unexpected OpCode received."); } frame.Version = (FrameVersion)header[0]; frame.Flags = (FrameFlags)header[1]; frame.Stream = unchecked ((sbyte)header[2]); frame.OpCode = (FrameOpcode)header[3]; frame.Length = length; //wrap the stream in a window, that will be completely read when disposed var reader = new FrameReader(stream, length); frame.Reader = reader; //decompress the contents of the frame (implicity loads the entire frame body!) if (frame.Flags.HasFlag(FrameFlags.Compression)) { await reader.DecompressAsync(); } //read tracing id if set if (frame.Flags.HasFlag(FrameFlags.Tracing)) { frame.TracingId = await reader.ReadUuidAsync().ConfigureAwait(false); } await frame.InitializeAsync().ConfigureAwait(false); return(frame); }
/// <summary> /// Gets the frame from opcode. /// </summary> /// <param name="protocolVersion">the version of the cql binary protocol in use</param> /// <param name="opcode">The opcode.</param> /// <returns></returns> /// <exception cref="ProtocolException">Unexpected OpCode received.</exception> private static Frame GetFrameFromOpcode(byte protocolVersion, FrameOpcode opcode) { Frame frame; switch(opcode) { case FrameOpcode.Error: frame = new ErrorFrame(); break; case FrameOpcode.Ready: frame = new ReadyFrame(); break; case FrameOpcode.Authenticate: frame = new AuthenticateFrame(); break; case FrameOpcode.AuthChallenge: frame = new AuthChallengeFrame(); break; case FrameOpcode.AuthSuccess: frame = new AuthSuccessFrame(); break; case FrameOpcode.Supported: frame = new SupportedFrame(); break; case FrameOpcode.Result: frame = new ResultFrame(); break; case FrameOpcode.Event: frame = new EventFrame(); break; default: throw new ProtocolException(protocolVersion, 0, string.Format("Unexpected OpCode {0:X} received.", opcode)); } return frame; }