// public methods
        /// <summary>
        /// Transitions to the next step in the conversation.
        /// </summary>
        /// <param name="conversation">The conversation.</param>
        /// <param name="input">The input.</param>
        /// <returns>An ISaslStep.</returns>
        /// <exception cref="MongoSecurityException">Unable to initialize context.</exception>
        public ISaslStep Transition(SaslConversation conversation, byte[] input)
        {
            GsaslContext context;
            try
            {
                context = GsaslContext.Initialize();
                conversation.RegisterItemForDisposal(context);
            }
            catch (GsaslException ex)
            {
                throw new MongoSecurityException("Unable to initialize context.", ex);
            }

            GsaslSession session;
            try
            {
                session = context.BeginSession(_name);
                conversation.RegisterItemForDisposal(session);
            }
            catch (GsaslException ex)
            {
                throw new MongoSecurityException("Unable to start a session.", ex);
            }

            foreach (var property in GetProperties())
            {
                session.SetProperty(property.Key, property.Value);
            }

            return new GsaslAuthenticateStep(session, null)
                .Transition(conversation, input);
        }
        // methods
        /// <inheritdoc/>
        public void Authenticate(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken)
        {
            Ensure.IsNotNull(connection, nameof(connection));
            Ensure.IsNotNull(description, nameof(description));

            using (var conversation = new SaslConversation(description.ConnectionId))
            {
                var currentStep = _mechanism.Initialize(connection, description);

                var command = CreateStartCommand(currentStep);
                while (true)
                {
                    BsonDocument result;
                    try
                    {
                        var protocol = CreateCommandProtocol(command);
                        result = protocol.Execute(connection, cancellationToken);
                    }
                    catch (MongoCommandException ex)
                    {
                        throw CreateException(connection, ex);
                    }

                    currentStep = Transition(conversation, currentStep, result);
                    if (currentStep == null)
                    {
                        return;
                    }

                    command = CreateContinueCommand(currentStep, result);
                }
            }
        }
        // methods
        /// <inheritdoc/>
        public async Task AuthenticateAsync(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken)
        {
            Ensure.IsNotNull(connection, nameof(connection));
            Ensure.IsNotNull(description, nameof(description));

            using (var conversation = new SaslConversation(description.ConnectionId))
            {
                var currentStep = _mechanism.Initialize(connection, description);

                var command = new BsonDocument
                {
                    { "saslStart", 1 },
                    { "mechanism", _mechanism.Name },
                    { "payload", currentStep.BytesToSendToServer }
                };

                while (true)
                {
                    BsonDocument result;
                    try
                    {
                        var protocol = new CommandWireProtocol<BsonDocument>(
                            new DatabaseNamespace(DatabaseName),
                            command,
                            true,
                            BsonDocumentSerializer.Instance,
                            null);
                        result = await protocol.ExecuteAsync(connection, cancellationToken).ConfigureAwait(false);
                    }
                    catch (MongoCommandException ex)
                    {
                        var message = string.Format("Unable to authenticate using sasl protocol mechanism {0}.", Name);
                        throw new MongoAuthenticationException(connection.ConnectionId, message, ex);
                    }

                    // we might be done here if the client is not expecting a reply from the server
                    if (result.GetValue("done", false).ToBoolean() && currentStep.IsComplete)
                    {
                        break;
                    }

                    currentStep = currentStep.Transition(conversation, result["payload"].AsByteArray);

                    // we might be done here if the client had some final verification it needed to do
                    if (result.GetValue("done", false).ToBoolean() && currentStep.IsComplete)
                    {
                        break;
                    }

                    command = new BsonDocument
                    {
                        { "saslContinue", 1 },
                        { "conversationId", result["conversationId"].AsInt32 },
                        { "payload", currentStep.BytesToSendToServer }
                    };
                }
            }
        }
        // methods
        public async Task AuthenticateAsync(IConnection connection, TimeSpan timeout, CancellationToken cancellationToken)
        {
            using (var conversation = new SaslConversation())
            {
                var currentStep = _mechanism.Initialize(connection);

                var command = new BsonDocument
                {
                    { "saslStart", 1 },
                    { "mechanism", _mechanism.Name },
                    { "payload", currentStep.BytesToSendToServer }
                };

                var slidingTimeout = new SlidingTimeout(timeout);

                while (true)
                {
                    BsonDocument result;
                    try
                    {
                        var protocol = new CommandWireProtocol(DatabaseName, command, true);
                        result = await protocol.ExecuteAsync(connection, slidingTimeout, cancellationToken);
                    }
                    catch(MongoCommandException ex)
                    {
                        var message = string.Format("Unable to authenticate using sasl protocol mechanism {0}.", Name);
                        throw new MongoAuthenticationException(message, ex);
                    }

                    // we might be done here if the client is not expecting a reply from the server
                    if (result.GetValue("done", false).ToBoolean() && currentStep.IsComplete)
                    {
                        break;
                    }

                    currentStep = currentStep.Transition(conversation, result["payload"].AsByteArray);

                    // we might be done here if the client had some final verification it needed to do
                    if (result.GetValue("done", false).ToBoolean() && currentStep.IsComplete)
                    {
                        break;
                    }

                    command = new BsonDocument
                    {
                        { "saslContinue", 1 },
                        { "conversationId", result["conversationId"].AsInt32 },
                        { "payload", currentStep.BytesToSendToServer }
                    };
                }
            }
        }
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                var encoding           = Utf8Encodings.Strict;
                var serverFirstMessage = encoding.GetString(bytesReceivedFromServer);
                var map = SaslMapParser.Parse(serverFirstMessage);

                var r = map['r'];

                if (!r.StartsWith(_rPrefix, StringComparison.Ordinal))
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, message: "Server sent an invalid nonce.");
                }
                var s = map['s'];
                var i = map['i'];

                const string gs2Header      = "n,,";
                var          channelBinding = "c=" + Convert.ToBase64String(encoding.GetBytes(gs2Header));
                var          nonce          = "r=" + r;
                var          clientFinalMessageWithoutProof = channelBinding + "," + nonce;

                var salt       = Convert.FromBase64String(map['s']);
                var iterations = int.Parse(map['i']);

                byte[] clientKey;
                byte[] serverKey;

                var cacheKey = new ScramCacheKey(_credential.SaslPreppedPassword, salt, iterations);

                if (_cache.TryGet(cacheKey, out var cacheEntry))
                {
                    clientKey = cacheEntry.ClientKey;
                    serverKey = cacheEntry.ServerKey;
                }
                else
                {
                    var saltedPassword = _hi(_credential, salt, iterations);
                    clientKey = _hmac(encoding, saltedPassword, "Client Key");
                    serverKey = _hmac(encoding, saltedPassword, "Server Key");
                    _cache.Add(cacheKey, new ScramCacheEntry(clientKey, serverKey));
                }

                var storedKey          = _h(clientKey);
                var authMessage        = _clientFirstMessageBare + "," + serverFirstMessage + "," + clientFinalMessageWithoutProof;
                var clientSignature    = _hmac(encoding, storedKey, authMessage);
                var clientProof        = XOR(clientKey, clientSignature);
                var serverSignature    = _hmac(encoding, serverKey, authMessage);
                var proof              = "p=" + Convert.ToBase64String(clientProof);
                var clientFinalMessage = clientFinalMessageWithoutProof + "," + proof;

                return(new ClientLast(encoding.GetBytes(clientFinalMessage), serverSignature));
            }
예제 #6
0
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                var encoding = Utf8Encodings.Strict;
                var map      = NVParser.Parse(encoding.GetString(bytesReceivedFromServer));

                var serverSignature = map['v'];

                if (_serverSignature64 != serverSignature)
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, message: "Server signature was invalid.");
                }

                return(new CompletedStep());
            }
예제 #7
0
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                var encoding = new UTF8Encoding(false, true);
                var map      = NVParser.Parse(encoding.GetString(bytesReceivedFromServer));

                var serverSignature = map['v'];

                if (_serverSignature64 != serverSignature)
                {
                    throw new AuthenticationException("Server signature was invalid.");
                }

                return(new CompletedStep());
            }
예제 #8
0
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                if (bytesReceivedFromServer == null || bytesReceivedFromServer.Length != 32) //RFC specifies this must be 4 octets
                {
                    throw new MongoSecurityException("Invalid server response.");
                }

                byte[] decryptedBytes;
                try
                {
                    _context.DecryptMessage(0, bytesReceivedFromServer, out decryptedBytes);
                }
                catch (Win32Exception ex)
                {
                    throw new MongoSecurityException("Unabled to decrypt message.", ex);
                }

                int length = 4;

                if (_authorizationId != null)
                {
                    length += _authorizationId.Length;
                }

                bytesReceivedFromServer    = new byte[length];
                bytesReceivedFromServer[0] = 0x1; // NO_PROTECTION
                bytesReceivedFromServer[1] = 0x0; // NO_PROTECTION
                bytesReceivedFromServer[2] = 0x0; // NO_PROTECTION
                bytesReceivedFromServer[3] = 0x0; // NO_PROTECTION

                if (_authorizationId != null)
                {
                    var authorizationIdBytes = Encoding.UTF8.GetBytes(_authorizationId);
                    authorizationIdBytes.CopyTo(bytesReceivedFromServer, 4);
                }

                byte[] bytesToSendToServer;
                try
                {
                    _context.EncryptMessage(bytesReceivedFromServer, out bytesToSendToServer);
                }
                catch (Win32Exception ex)
                {
                    throw new MongoSecurityException("Unabled to encrypt message.", ex);
                }

                return(new SaslCompletionStep(bytesToSendToServer));
            }
예제 #9
0
            public ISaslStep Initialize(IConnection connection, SaslConversation conversation, ConnectionDescription description)
            {
                Ensure.IsNotNull(connection, nameof(connection));
                Ensure.IsNotNull(description, nameof(description));

                const string gs2Header = "n,,";
                var          username  = "******" + PrepUsername(_credential.Username);
                var          r         = GenerateRandomString();
                var          nonce     = "r=" + r;

                var clientFirstMessageBare  = username + "," + nonce;
                var clientFirstMessage      = gs2Header + clientFirstMessageBare;
                var clientFirstMessageBytes = Utf8Encodings.Strict.GetBytes(clientFirstMessage);

                return(new ClientFirst(clientFirstMessageBytes, clientFirstMessageBare, _credential, r, _h, _hi, _hmac, _cache));
            }
예제 #10
0
            public ISaslStep Initialize(IConnection connection, SaslConversation conversation, ConnectionDescription description)
            {
                Ensure.IsNotNull(connection, nameof(connection));
                Ensure.IsNotNull(description, nameof(description));

                var nonce = GenerateRandomBytes();

                var document = new BsonDocument
                {
                    { "r", nonce },
                    { "p", (int)'n' }
                };

                var clientMessageBytes = document.ToBson();

                return(new ClientFirst(clientMessageBytes, nonce, _awsCredentials, _clock));
            }
            // public methods
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                try
                {
                    var bytesToSendToServer = _session.Step(bytesReceivedFromServer);
                    if (_session.IsComplete)
                    {
                        return(new SaslCompletionStep(bytesToSendToServer));
                    }

                    return(new GsaslAuthenticateStep(_session, bytesToSendToServer));
                }
                catch (GsaslException ex)
                {
                    throw new MongoSecurityException("Unable to authenticate.", ex);
                }
            }
        // public methods
        /// <summary>
        /// Transitions to the next step in the conversation.
        /// </summary>
        /// <param name="conversation">The conversation.</param>
        /// <param name="bytesReceivedFromServer">The bytes received from the server.</param>
        /// <returns>An ISaslStep.</returns>
        public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
        {
            var directives = DirectiveParser.Parse(bytesReceivedFromServer);
            var encoding = Encoding.UTF8;

            var sb = new StringBuilder();
            sb.AppendFormat("username=\"{0}\"", _username);
            sb.AppendFormat(",nonce=\"{0}\"", encoding.GetString(directives["nonce"]).Replace("\"", "\\\""));
            sb.AppendFormat(",cnonce=\"{0}\"", encoding.GetString(_cnonce).Replace("\"", "\\\""));
            sb.AppendFormat(",nc={0}", _nonceCount);
            sb.AppendFormat(",qop={0}", _qop);
            sb.AppendFormat(",digest-uri=\"{0}\"", _digestUri);
            sb.AppendFormat(",response={0}", ComputeResponse(encoding, directives["nonce"]));
            sb.Append(",charset=\"utf-8\"");

            return new ManagedDigestMD5FinalStep(encoding.GetBytes(sb.ToString()));
        }
예제 #13
0
        private ISaslStep Transition(SaslConversation conversation, ISaslStep currentStep, BsonDocument result)
        {
            // we might be done here if the client is not expecting a reply from the server
            if (result.GetValue("done", false).ToBoolean() && currentStep.IsComplete)
            {
                return(null);
            }

            currentStep = currentStep.Transition(conversation, result["payload"].AsByteArray);

            // we might be done here if the client had some final verification it needed to do
            if (result.GetValue("done", false).ToBoolean() && currentStep.IsComplete)
            {
                return(null);
            }

            return(currentStep);
        }
예제 #14
0
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                var serverFirstMessageDocument = BsonSerializer.Deserialize <BsonDocument>(bytesReceivedFromServer);
                var serverNonce = serverFirstMessageDocument["s"].AsByteArray;
                var host        = serverFirstMessageDocument["h"].AsString;

                if (serverNonce.Length != ClientNonceLength * 2 || !serverNonce.Take(ClientNonceLength).SequenceEqual(_nonce))
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, "Server sent an invalid nonce.");
                }
                if (host.Length < 1 || host.Length > 255 || host.Contains(".."))
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, "Server returned an invalid sts host.");
                }
                var unexpectedNames = serverFirstMessageDocument.Names.Except(new[] { "h", "s" });

                if (unexpectedNames.Any())
                {
                    throw new MongoAuthenticationException(
                              conversation.ConnectionId,
                              $"Server returned unexpected fields: {string.Join(", ", unexpectedNames)}.");
                }

                AwsSignatureVersion4.CreateAuthorizationRequest(
                    _clock.UtcNow,
                    _awsCredentials.AccessKeyId,
                    _awsCredentials.SecretAccessKey,
                    _awsCredentials.SessionToken,
                    serverNonce,
                    host,
                    out var authorizationHeader,
                    out var timestamp);

                var document = new BsonDocument
                {
                    { "a", authorizationHeader },
                    { "d", timestamp },
                    { "t", _awsCredentials.SessionToken, _awsCredentials.SessionToken != null }
                };

                var clientSecondMessageBytes = document.ToBson();

                return(new ClientLast(clientSecondMessageBytes));
            }
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                try
                {
                    // NOTE: We simply check whether we can successfully decrypt the message,
                    //       but don't do anything with the decrypted plaintext
                    _ = _context.DecryptMessage(0, bytesReceivedFromServer);
                }
                catch (GssapiException ex)
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, "Unable to decrypt message.", ex);
                }

                int length = 4;

                if (_authorizationId != null)
                {
                    length += _authorizationId.Length;
                }

                bytesReceivedFromServer    = new byte[length];
                bytesReceivedFromServer[0] = 0x1; // NO_PROTECTION
                bytesReceivedFromServer[1] = 0x0; // NO_PROTECTION
                bytesReceivedFromServer[2] = 0x0; // NO_PROTECTION
                bytesReceivedFromServer[3] = 0x0; // NO_PROTECTION

                if (_authorizationId != null)
                {
                    var authorizationIdBytes = Encoding.UTF8.GetBytes(_authorizationId);
                    authorizationIdBytes.CopyTo(bytesReceivedFromServer, 4);
                }

                byte[] bytesToSendToServer;
                try
                {
                    bytesToSendToServer = _context.EncryptMessage(bytesReceivedFromServer);
                }
                catch (GssapiException ex)
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, "Unable to encrypt message.", ex);
                }

                return(new CompletedStep(bytesToSendToServer));
            }
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                byte[] bytesToSendToServer;
                try
                {
                    bytesToSendToServer = _context.Next(bytesReceivedFromServer);
                }
                catch (GssapiException ex)
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, "Unable to initialize security context", ex);
                }

                if (!_context.IsInitialized)
                {
                    return(new InitializeStep(_authorizationId, _context, bytesToSendToServer));
                }

                return(new NegotiateStep(_authorizationId, _context, bytesToSendToServer));
            }
예제 #17
0
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                byte[] bytesToSendToServer;
                try
                {
                    _context.Initialize(_servicePrincipalName, bytesReceivedFromServer, out bytesToSendToServer);
                }
                catch (Win32Exception ex)
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, "Unable to initialize security context", ex);
                }

                if (!_context.IsInitialized)
                {
                    return(new InitializeStep(_servicePrincipalName, _authorizationId, _context, bytesToSendToServer));
                }

                return(new NegotiateStep(_authorizationId, _context, bytesToSendToServer));
            }
예제 #18
0
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                byte[] decryptedBytes;
                try
                {
                    _context.DecryptMessage(0, bytesReceivedFromServer, out decryptedBytes);
                }
                catch (Win32Exception ex)
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, "Unabled to decrypt message.", ex);
                }

                int length = 4;

                if (_authorizationId != null)
                {
                    length += _authorizationId.Length;
                }

                bytesReceivedFromServer    = new byte[length];
                bytesReceivedFromServer[0] = 0x1; // NO_PROTECTION
                bytesReceivedFromServer[1] = 0x0; // NO_PROTECTION
                bytesReceivedFromServer[2] = 0x0; // NO_PROTECTION
                bytesReceivedFromServer[3] = 0x0; // NO_PROTECTION

                if (_authorizationId != null)
                {
                    var authorizationIdBytes = Encoding.UTF8.GetBytes(_authorizationId);
                    authorizationIdBytes.CopyTo(bytesReceivedFromServer, 4);
                }

                byte[] bytesToSendToServer;
                try
                {
                    _context.EncryptMessage(bytesReceivedFromServer, out bytesToSendToServer);
                }
                catch (Win32Exception ex)
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, "Unabled to encrypt message.", ex);
                }

                return(new CompletedStep(bytesToSendToServer));
            }
        // public methods
        /// <summary>
        /// Transitions to the next step in the conversation.
        /// </summary>
        /// <param name="conversation">The conversation.</param>
        /// <param name="bytesReceivedFromServer">The bytes received from the server.</param>
        /// <returns>An ISaslStep.</returns>
        public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
        {
            SecurityCredential securityCredential;

            try
            {
                securityCredential = SecurityCredential.Acquire(SspiPackage.Kerberos, _authorizationId, _evidence);
                conversation.RegisterItemForDisposal(securityCredential);
            }
            catch (Win32Exception ex)
            {
                throw new MongoSecurityException("Unable to acquire security credential.", ex);
            }

            byte[]          bytesToSendToServer;
            SecurityContext context;

            try
            {
                context = SecurityContext.Initialize(securityCredential, _servicePrincipalName, bytesReceivedFromServer, out bytesToSendToServer);
            }
            catch (Win32Exception ex)
            {
                if (_evidence is PasswordEvidence)
                {
                    throw new MongoSecurityException("Unable to initialize security context. Ensure the username and password are correct.", ex);
                }
                else
                {
                    throw new MongoSecurityException("Unable to initialize security context.", ex);
                }
            }

            if (!context.IsInitialized)
            {
                return(new SspiInitializeStep(_servicePrincipalName, _authorizationId, context, bytesToSendToServer));
            }

            return(new SspiNegotiateStep(_authorizationId, context, bytesToSendToServer));
        }
예제 #20
0
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                var encoding           = Utf8Encodings.Strict;
                var serverFirstMessage = encoding.GetString(bytesReceivedFromServer);
                var map = NVParser.Parse(serverFirstMessage);

                var r = map['r'];

                if (!r.StartsWith(_rPrefix))
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, message: "Server sent an invalid nonce.");
                }
                var s = map['s'];
                var i = map['i'];

                const string gs2Header      = "n,,";
                var          channelBinding = "c=" + Convert.ToBase64String(encoding.GetBytes(gs2Header));
                var          nonce          = "r=" + r;
                var          clientFinalMessageWithoutProof = channelBinding + "," + nonce;

                var saltedPassword = Hi(
                    AuthenticationHelper.MongoPasswordDigest(_credential.Username, _credential.Password),
                    Convert.FromBase64String(s),
                    int.Parse(i));

                var clientKey       = HMAC(encoding, saltedPassword, "Client Key");
                var storedKey       = H(clientKey);
                var authMessage     = _clientFirstMessageBare + "," + serverFirstMessage + "," + clientFinalMessageWithoutProof;
                var clientSignature = HMAC(encoding, storedKey, authMessage);
                var clientProof     = XOR(clientKey, clientSignature);
                var serverKey       = HMAC(encoding, saltedPassword, "Server Key");
                var serverSignature = HMAC(encoding, serverKey, authMessage);

                var proof = "p=" + Convert.ToBase64String(clientProof);
                var clientFinalMessage = clientFinalMessageWithoutProof + "," + proof;

                return(new ClientLast(encoding.GetBytes(clientFinalMessage), serverSignature));
            }
        // public methods
        /// <summary>
        /// Transitions to the next step in the conversation.
        /// </summary>
        /// <param name="conversation">The conversation.</param>
        /// <param name="bytesReceivedFromServer">The bytes received from the server.</param>
        /// <returns>An ISaslStep.</returns>
        public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
        {
            SecurityCredential securityCredential;
            try
            {
                securityCredential = SecurityCredential.Acquire(SspiPackage.Kerberos, _authorizationId, _evidence);
                conversation.RegisterItemForDisposal(securityCredential);
            }
            catch (Win32Exception ex)
            {
                throw new MongoSecurityException("Unable to acquire security credential.", ex);
            }

            byte[] bytesToSendToServer;
            SecurityContext context;
            try
            {
                context = SecurityContext.Initialize(securityCredential, _servicePrincipalName, bytesReceivedFromServer, out bytesToSendToServer);
            }
            catch (Win32Exception ex)
            {
                if (_evidence is PasswordEvidence)
                {
                    throw new MongoSecurityException("Unable to initialize security context. Ensure the username and password are correct.", ex);
                }
                else
                {
                    throw new MongoSecurityException("Unable to initialize security context.", ex);
                }
            }

            if (!context.IsInitialized)
            {
                return new SspiInitializeStep(_servicePrincipalName, _authorizationId, context, bytesToSendToServer);
            }

            return new SspiNegotiateStep(_authorizationId, context, bytesToSendToServer);
        }
        // public methods
        public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
        {
            var encoding = Encoding.UTF8;
            var mongoPassword = _username + ":mongo:" + _password;
            byte[] password;
            using (var md5 = MD5.Create())
            {
                password = GetMongoPassword(md5, encoding, _username, _password);
                var temp = ToHexString(password);
                password = encoding.GetBytes(temp);
            }

            byte[] digest;
            using (var hmacMd5 = new HMACMD5(password))
            {
                digest = hmacMd5.ComputeHash(bytesReceivedFromServer);
            }

            var response = _username + " " + ToHexString(digest);
            var bytesToSendToServer = encoding.GetBytes(response);

            return new SaslCompletionStep(bytesToSendToServer);
        }
예제 #23
0
        // methods
        /// <inheritdoc/>
        public void Authenticate(IConnection connection, ConnectionDescription description, CancellationToken cancellationToken)
        {
            Ensure.IsNotNull(connection, nameof(connection));
            Ensure.IsNotNull(description, nameof(description));

            using (var conversation = new SaslConversation(description.ConnectionId))
            {
                ISaslStep    currentStep;
                BsonDocument command;
                var          speculativeAuthenticateResult = description.HelloResult.SpeculativeAuthenticate;
                if (_speculativeFirstStep != null && speculativeAuthenticateResult != null)
                {
                    currentStep = Transition(conversation, _speculativeFirstStep, speculativeAuthenticateResult, out command);
                }
                else
                {
                    currentStep = _mechanism.Initialize(connection, conversation, description);
                    command     = CreateStartCommand(currentStep);
                }

                while (currentStep != null)
                {
                    BsonDocument result;
                    try
                    {
                        var protocol = CreateCommandProtocol(command);
                        result = protocol.Execute(connection, cancellationToken);
                    }
                    catch (MongoException ex)
                    {
                        throw CreateException(connection, ex);
                    }

                    currentStep = Transition(conversation, currentStep, result, out command);
                }
            }
        }
            public ISaslStep Initialize(IConnection connection, SaslConversation conversation, ConnectionDescription description)
            {
                Ensure.IsNotNull(connection, nameof(connection));
                Ensure.IsNotNull(description, nameof(description));

                string hostName;
                var    dnsEndPoint = connection.EndPoint as DnsEndPoint;

                if (dnsEndPoint != null)
                {
                    hostName = dnsEndPoint.Host;
                }
                else if (connection.EndPoint is IPEndPoint)
                {
                    hostName = ((IPEndPoint)connection.EndPoint).Address.ToString();
                }
                else
                {
                    throw new MongoAuthenticationException(connection.ConnectionId, "Only DnsEndPoint and IPEndPoint are supported for GSSAPI authentication.");
                }

                if (_canonicalizeHostName)
                {
#if NETSTANDARD1_5
                    var entry = Dns.GetHostEntryAsync(hostName).GetAwaiter().GetResult();
#else
                    var entry = Dns.GetHostEntry(hostName);
#endif
                    if (entry != null)
                    {
                        hostName = entry.HostName;
                    }
                }

                return(new FirstStep(_serviceName, hostName, _realm, _username, _password, conversation));
            }
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                var encoding = new UTF8Encoding(false, true);
                var serverFirstMessage = encoding.GetString(bytesReceivedFromServer);
                var map = NVParser.Parse(serverFirstMessage);

                var r = map['r'];
                if (!r.StartsWith(_rPrefix))
                {
                    throw new MongoAuthenticationException("Server sent an invalid nonce.");
                }
                var s = map['s'];
                var i = map['i'];

                const string gs2Header = "n,,";
                var channelBinding = "c=" + Convert.ToBase64String(encoding.GetBytes(gs2Header));
                var nonce = "r=" + r;
                var clientFinalMessageWithoutProof = channelBinding + "," + nonce;

                var saltedPassword = Hi(
                    AuthenticationHelper.MongoUsernamePasswordDigest(_credential.Username, _credential.Password),
                    Convert.FromBase64String(s),
                    int.Parse(i));

                var clientKey = HMAC(encoding, saltedPassword, "Client Key");
                var storedKey = H(clientKey);
                var authMessage = _clientFirstMessageBare + "," + serverFirstMessage + "," + clientFinalMessageWithoutProof;
                var clientSignature = HMAC(encoding, storedKey, authMessage);
                var clientProof = XOR(clientKey, clientSignature);
                var serverKey = HMAC(encoding, saltedPassword, "Server Key");
                var serverSignature = HMAC(encoding, serverKey, authMessage);

                var proof = "p=" + Convert.ToBase64String(clientProof);
                var clientFinalMessage = clientFinalMessageWithoutProof + "," + proof;

                return new ClientLast(encoding.GetBytes(clientFinalMessage), Convert.ToBase64String(serverSignature));
            }
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                byte[] decryptedBytes;
                try
                {
                    _context.DecryptMessage(0, bytesReceivedFromServer, out decryptedBytes);
                }
                catch (Win32Exception ex)
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, "Unabled to decrypt message.", ex);
                }

                int length = 4;
                if (_authorizationId != null)
                {
                    length += _authorizationId.Length;
                }

                bytesReceivedFromServer = new byte[length];
                bytesReceivedFromServer[0] = 0x1; // NO_PROTECTION
                bytesReceivedFromServer[1] = 0x0; // NO_PROTECTION
                bytesReceivedFromServer[2] = 0x0; // NO_PROTECTION
                bytesReceivedFromServer[3] = 0x0; // NO_PROTECTION

                if (_authorizationId != null)
                {
                    var authorizationIdBytes = Encoding.UTF8.GetBytes(_authorizationId);
                    authorizationIdBytes.CopyTo(bytesReceivedFromServer, 4);
                }

                byte[] bytesToSendToServer;
                try
                {
                    _context.EncryptMessage(bytesReceivedFromServer, out bytesToSendToServer);
                }
                catch (Win32Exception ex)
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, "Unabled to encrypt message.", ex);
                }

                return new CompletedStep(bytesToSendToServer);
            }
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                byte[] bytesToSendToServer;
                try
                {
                    _context.Initialize(_servicePrincipalName, bytesReceivedFromServer, out bytesToSendToServer);
                }
                catch (Win32Exception ex)
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, "Unable to initialize security context", ex);
                }

                if (!_context.IsInitialized)
                {
                    return new InitializeStep(_servicePrincipalName, _authorizationId, _context, bytesToSendToServer);
                }

                return new NegotiateStep(_authorizationId, _context, bytesToSendToServer);
            }
 // public methods
 /// <summary>
 /// Transitions to the next step in the conversation.
 /// </summary>
 /// <param name="conversation">The conversation.</param>
 /// <param name="input">The input.</param>
 /// <returns>An ISaslStep.</returns>
 public ISaslStep Transition(SaslConversation conversation, byte[] input)
 {
     throw new MongoException("No more transitions available.  The conversation is completed.");
 }
 public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
 {
     return new SaslCompletionStep(new byte[0]);
 }
예제 #30
0
            public FirstStep(string serviceName, string hostName, string realm, string username, SecureString password, SaslConversation conversation)
            {
                _authorizationId      = username;
                _password             = password;
                _servicePrincipalName = string.Format("{0}/{1}", serviceName, hostName);
                if (!string.IsNullOrEmpty(realm))
                {
                    _servicePrincipalName += "@" + realm;
                }

                SecurityCredential securityCredential;

                try
                {
                    securityCredential = SecurityCredential.Acquire(SspiPackage.Kerberos, _authorizationId, _password);
                    conversation.RegisterItemForDisposal(securityCredential);
                }
                catch (Win32Exception ex)
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, "Unable to acquire security credential.", ex);
                }

                try
                {
                    _context = Sspi.SecurityContext.Initialize(securityCredential, _servicePrincipalName, null, out _bytesToSendToServer);
                }
                catch (Win32Exception ex)
                {
                    if (_password != null)
                    {
                        throw new MongoAuthenticationException(conversation.ConnectionId, "Unable to initialize security context. Ensure the username and password are correct.", ex);
                    }
                    else
                    {
                        throw new MongoAuthenticationException(conversation.ConnectionId, "Unable to initialize security context.", ex);
                    }
                }
            }
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                // Even though RFC says that clients should specifically check this and raise an error
                // if it isn't true, this breaks on Windows XP, so we are skipping the check for windows
                // XP, identified as Win32NT 5.1: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724832(v=vs.85).aspx
                if (Environment.OSVersion.Platform != PlatformID.Win32NT ||
                    Environment.OSVersion.Version.Major != 5 ||
                    Environment.OSVersion.Version.Minor != 1)
                {
                    if (bytesReceivedFromServer == null || bytesReceivedFromServer.Length != 32) //RFC specifies this must be 4 octets
                    {
                        throw new MongoSecurityException("Invalid server response.");
                    }
                }

                byte[] decryptedBytes;
                try
                {
                    _context.DecryptMessage(0, bytesReceivedFromServer, out decryptedBytes);
                }
                catch (Win32Exception ex)
                {
                    throw new MongoSecurityException("Unabled to decrypt message.", ex);
                }

                int length = 4;
                if (_authorizationId != null)
                {
                    length += _authorizationId.Length;
                }

                bytesReceivedFromServer = new byte[length];
                bytesReceivedFromServer[0] = 0x1; // NO_PROTECTION
                bytesReceivedFromServer[1] = 0x0; // NO_PROTECTION
                bytesReceivedFromServer[2] = 0x0; // NO_PROTECTION
                bytesReceivedFromServer[3] = 0x0; // NO_PROTECTION

                if (_authorizationId != null)
                {
                    var authorizationIdBytes = Encoding.UTF8.GetBytes(_authorizationId);
                    authorizationIdBytes.CopyTo(bytesReceivedFromServer, 4);
                }

                byte[] bytesToSendToServer;
                try
                {
                    _context.EncryptMessage(bytesReceivedFromServer, out bytesToSendToServer);
                }
                catch (Win32Exception ex)
                {
                    throw new MongoSecurityException("Unabled to encrypt message.", ex);
                }

                return new SaslCompletionStep(bytesToSendToServer);
            }
            // public methods
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                try
                {
                    var bytesToSendToServer = _session.Step(bytesReceivedFromServer);
                    if (_session.IsComplete)
                    {
                        return new SaslCompletionStep(bytesToSendToServer);
                    }

                    return new GsaslAuthenticateStep(_session, bytesToSendToServer);
                }
                catch (GsaslException ex)
                {
                    throw new MongoSecurityException("Unable to authenticate.", ex);
                }
            }
 // public methods
 /// <summary>
 /// Transitions to the next step in the conversation.
 /// </summary>
 /// <param name="conversation">The conversation.</param>
 /// <param name="input">The input.</param>
 /// <returns>An ISaslStep.</returns>
 public ISaslStep Transition(SaslConversation conversation, byte[] input)
 {
     throw new MongoException("No more transitions available.  The conversation is completed.");
 }
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                if (bytesReceivedFromServer == null || bytesReceivedFromServer.Length != 32) //RFC specifies this must be 4 octets
                {
                    throw new MongoSecurityException("Invalid server response.");
                }

                byte[] decryptedBytes;
                try
                {
                    _context.DecryptMessage(0, bytesReceivedFromServer, out decryptedBytes);
                }
                catch (Win32Exception ex)
                {
                    throw new MongoSecurityException("Unabled to decrypt message.", ex);
                }

                int length = 4;
                if (_authorizationId != null)
                {
                    length += _authorizationId.Length;
                }

                bytesReceivedFromServer = new byte[length];
                bytesReceivedFromServer[0] = 0x1; // NO_PROTECTION
                bytesReceivedFromServer[1] = 0x0; // NO_PROTECTION
                bytesReceivedFromServer[2] = 0x0; // NO_PROTECTION
                bytesReceivedFromServer[3] = 0x0; // NO_PROTECTION

                if (_authorizationId != null)
                {
                    var authorizationIdBytes = Encoding.UTF8.GetBytes(_authorizationId);
                    authorizationIdBytes.CopyTo(bytesReceivedFromServer, 4);
                }

                byte[] bytesToSendToServer;
                try
                {
                    _context.EncryptMessage(bytesReceivedFromServer, out bytesToSendToServer);
                }
                catch (Win32Exception ex)
                {
                    throw new MongoSecurityException("Unabled to encrypt message.", ex);
                }

                return new SaslCompletionStep(bytesToSendToServer);
            }
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                var encoding = new UTF8Encoding(false, true);
                var map = NVParser.Parse(encoding.GetString(bytesReceivedFromServer));

                var serverSignature = map['v'];

                if (_serverSignature64 != serverSignature)
                {
                    throw new MongoAuthenticationException("Server signature was invalid.");
                }

                return new CompletedStep();
            }
 public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
 {
     throw new InvalidOperationException("Sasl conversation has completed.");
 }
예제 #37
0
 public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
 {
     return(new CompletedStep());
 }
        private ISaslStep Transition(SaslConversation conversation, ISaslStep currentStep, BsonDocument result)
        {
            // we might be done here if the client is not expecting a reply from the server
            if (result.GetValue("done", false).ToBoolean() && currentStep.IsComplete)
            {
                return null;
            }

            currentStep = currentStep.Transition(conversation, result["payload"].AsByteArray);

            // we might be done here if the client had some final verification it needed to do
            if (result.GetValue("done", false).ToBoolean() && currentStep.IsComplete)
            {
                return null;
            }

            return currentStep;
        }
예제 #39
0
 public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
 {
     throw new InvalidOperationException("Sasl conversation has completed.");
 }
예제 #40
0
            public ISaslStep Transition(SaslConversation conversation, byte[] bytesReceivedFromServer)
            {
                var encoding = Utf8Encodings.Strict;
                var map = NVParser.Parse(encoding.GetString(bytesReceivedFromServer));
                var serverSignature = Convert.FromBase64String(map['v']);

                if (!ConstantTimeEquals(_serverSignature64, serverSignature))
                {
                    throw new MongoAuthenticationException(conversation.ConnectionId, message: "Server signature was invalid.");
                }

                return new CompletedStep();
            }
            public FirstStep(string serviceName, string hostname, string realm, string username, SecureString password, SaslConversation conversation)
            {
                _authorizationId = username;

                try
                {
                    _context = SecurityContextFactory.InitializeSecurityContext(serviceName, hostname, realm, _authorizationId, password);
                    conversation.RegisterItemForDisposal(_context);
                    _bytesToSendToServer = _context.Next(null);
                }
                catch (GssapiException ex)
                {
                    if (password != null)
                    {
                        throw new MongoAuthenticationException(conversation.ConnectionId, "Unable to initialize security context. Ensure the username and password are correct.", ex);
                    }
                    else
                    {
                        throw new MongoAuthenticationException(conversation.ConnectionId, "Unable to initialize security context.", ex);
                    }
                }
            }