123456789_123456789_123456789_123456789_123456789_

Class: Mongo::Auth::Base Private

Do not use. This class is for internal use only.
Relationships & Source Files
Extension / Inclusion / Inheritance Descendants
Subclasses:
Aws, Mongo::Auth::CR, Mongo::Auth::Gssapi, Mongo::Auth::LDAP, Mongo::Auth::Scram, Mongo::Auth::Scram256, Mongo::Auth::X509
Inherits: Object
Defined in: lib/mongo/auth/base.rb

Overview

Base class for authenticators.

Each authenticator is instantiated for authentication over a particular connection.

Since:

  • 2.0.0

Class Method Summary

Instance Attribute Summary

Instance Method Summary

Instance Attribute Details

#connectionMongo::Connection (readonly)

Returns:

  • (Mongo::Connection)

    The connection to authenticate over.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/auth/base.rb', line 33

attr_reader :connection

#userMongo::Auth::User (readonly)

Returns:

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/auth/base.rb', line 30

attr_reader :user

Instance Method Details

#conversation

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/auth/base.rb', line 45

def conversation
  @conversation ||= self.class.const_get(:Conversation).new(user, connection)
end

#converse_1_step(connection, conversation) (private)

Performs a single-step conversation on the given connection.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/auth/base.rb', line 52

def converse_1_step(connection, conversation)
  msg = conversation.start(connection)
  dispatch_msg(connection, conversation, msg)
end

#converse_2_step(connection, conversation) (private)

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 true to indicate the end of the conversation.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/auth/base.rb', line 62

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) (private)

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

Parameters:

  • connection (Server::Connection)

    The connection.

  • conversation (Auth::*::Conversation)

    The conversation.

  • speculative_auth_result (BSON::Document | nil)

    The value of speculativeAuthenticate field of hello response of the handshake on the specified connection.

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/auth/base.rb', line 76

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) (private)

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/auth/base.rb', line 105

def dispatch_msg(connection, conversation, msg)
  context = Operation::Context.new(options: {
    server_api: connection.options[:server_api],
  })
  if server_api = context.server_api
    msg = msg.maybe_add_server_api(server_api)
  end
  reply = connection.dispatch([msg], context)
  reply_document = reply.documents.first
  validate_reply!(connection, conversation, reply_document)
  connection_global_id = if connection.respond_to?(:global_id)
    connection.global_id
  else
    nil
  end
  result = Operation::Result.new(reply, connection.description, connection_global_id, context: context)
  connection.update_cluster_time(result)
  reply_document
end

#validate_reply!(connection, conversation, doc) (private)

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

Since:

  • 2.0.0

[ GitHub ]

  
# File 'lib/mongo/auth/base.rb', line 127

def validate_reply!(connection, conversation, doc)
  if doc[:ok] != 1
    message = Error::Parser.build_message(
      code: doc[:code],
      code_name: doc[:codeName],
      message: doc[:errmsg],
    )

    raise Unauthorized.new(user,
      used_mechanism: self.class.const_get(:MECHANISM),
      message: message,
      server: connection.server,
      code: doc[:code]
    )
  end
end