class Mongo::Auth::Base

Base class for authenticators.

Each authenticator is instantiated for authentication over a particular connection.

@api private

Attributes

connection[R]

@return [ Mongo::Connection ] The connection to authenticate over.

user[R]

@return [ Mongo::Auth::User ] The user to authenticate.

Public Class Methods

new(user, connection, **opts) click to toggle source

Initializes the authenticator.

@param [ Auth::User ] user The user to authenticate. @param [ Mongo::Connection ] connection The connection to authenticate

over.
# File lib/mongo/auth/base.rb, line 37
def initialize(user, connection, **opts)
  @user = user
  @connection = connection
end

Public Instance Methods

conversation() click to toggle source
# File lib/mongo/auth/base.rb, line 42
def conversation
  @conversation ||= self.class.const_get(:Conversation).new(user, connection)
end

Private Instance Methods

converse_1_step(connection, conversation) click to toggle source

Performs a single-step conversation on the given connection.

# File lib/mongo/auth/base.rb, line 49
def converse_1_step(connection, conversation)
  msg = conversation.start(connection)
  dispatch_msg(connection, conversation, msg)
end
converse_2_step(connection, conversation) click to toggle source

Performs a two-step conversation on the given connection.

The implementation is very similar to converse_multi_step, but conversations using this method do not involve the server replying with {done: true} to indicate the end of the conversation.

# File lib/mongo/auth/base.rb, line 59
def converse_2_step(connection, conversation)
  msg = conversation.start(connection)
  reply_document = dispatch_msg(connection, conversation, msg)
  msg = conversation.continue(reply_document, connection)
  dispatch_msg(connection, conversation, msg)
end
converse_multi_step(connection, conversation, speculative_auth_result: nil ) click to toggle source

Performs the variable-length SASL conversation on the given connection.

@param [ Server::Connection ] connection The connection. @param [ Auth::*::Conversation ] conversation The conversation. @param [ BSON::Document | nil ] speculative_auth_result The

value of speculativeAuthenticate field of ismaster response of
the handshake on the specified connection.
# File lib/mongo/auth/base.rb, line 73
def converse_multi_step(connection, conversation,
  speculative_auth_result: nil
)
  # Although the SASL conversation in theory can have any number of
  # steps, all defined authentication methods have a predefined number
  # of steps, and therefore all of our authenticators have a fixed set
  # of methods that generate payloads with one method per step.
  # We support a maximum of 3 total exchanges (start, continue and
  # finalize) and in practice the first two exchanges always happen.
  if speculative_auth_result
    reply_document = speculative_auth_result
  else
    msg = conversation.start(connection)
    reply_document = dispatch_msg(connection, conversation, msg)
  end
  msg = conversation.continue(reply_document, connection)
  reply_document = dispatch_msg(connection, conversation, msg)
  conversation.process_continue_response(reply_document)
  unless reply_document[:done]
    msg = conversation.finalize(connection)
    reply_document = dispatch_msg(connection, conversation, msg)
  end
  unless reply_document[:done]
    raise Error::InvalidServerAuthResponse,
      'Server did not respond with {done: true} after finalizing the conversation'
  end
  reply_document
end
dispatch_msg(connection, conversation, msg) click to toggle source
# File lib/mongo/auth/base.rb, line 102
def dispatch_msg(connection, conversation, msg)
  reply = connection.dispatch([msg])
  reply_document = reply.documents.first
  validate_reply!(connection, conversation, reply_document)
  result = Operation::Result.new(reply, connection.description)
  connection.update_cluster_time(result)
  reply_document
end
validate_reply!(connection, conversation, doc) click to toggle source

Checks whether reply is successful (i.e. has {ok: 1} set) and raises Unauthorized if not.

# File lib/mongo/auth/base.rb, line 113
def validate_reply!(connection, conversation, doc)
  if doc[:ok] != 1
    extra = [doc[:code], doc[:codeName]].compact.join(': ')
    msg = doc[:errmsg]
    unless extra.empty?
      msg += " (#{extra})"
    end
    raise Unauthorized.new(user,
      used_mechanism: self.class.const_get(:MECHANISM),
      message: msg,
      server: connection.server,
    )
  end
end