Class: Mongo::Auth::ScramConversationBase Private

Inherits:
SaslConversationBase show all
Defined in:
lib/mongo/auth/scram_conversation_base.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

Defines common behavior around authentication conversations between the client and the server.

Since:

  • 2.0.0

Constant Summary collapse

MIN_ITER_COUNT =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

The minimum iteration count for SCRAM-SHA-1 and SCRAM-SHA-256.

Since:

  • 2.0.0

4096

Constants inherited from SaslConversationBase

Mongo::Auth::SaslConversationBase::CLIENT_CONTINUE_MESSAGE, Mongo::Auth::SaslConversationBase::CLIENT_FIRST_MESSAGE

Instance Attribute Summary collapse

Attributes inherited from ConversationBase

#connection, #user

Instance Method Summary collapse

Methods inherited from SaslConversationBase

#start

Constructor Details

#initialize(user, connection, client_nonce: nil) ⇒ ScramConversationBase

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Create the new conversation.

Parameters:

  • user (Auth::User)

    The user to converse about.

  • client_nonce (String | nil) (defaults to: nil)

    The client nonce to use. If this conversation is created for a connection that performed speculative authentication, this client nonce must be equal to the client nonce used for speculative authentication; otherwise, the client nonce must not be specified.

Since:

  • 2.0.0



35
36
37
38
# File 'lib/mongo/auth/scram_conversation_base.rb', line 35

def initialize(user, connection, client_nonce: nil)
  super
  @client_nonce = client_nonce || SecureRandom.base64
end

Instance Attribute Details

#client_nonceString (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns client_nonce The client nonce.

Returns:

  • (String)

    client_nonce The client nonce.

Since:

  • 2.0.0



41
42
43
# File 'lib/mongo/auth/scram_conversation_base.rb', line 41

def client_nonce
  @client_nonce
end

#idInteger (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Get the id of the conversation.

Examples:

Get the id of the conversation.

conversation.id

Returns:

  • (Integer)

    The conversation id.

Since:

  • 2.0.0



49
50
51
# File 'lib/mongo/auth/scram_conversation_base.rb', line 49

def id
  @id
end

Instance Method Details

#continue(reply_document, connection) ⇒ Protocol::Message

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Continue the SCRAM conversation. This sends the client final message to the server after setting the reply from the previous server communication.

Parameters:

  • reply_document (BSON::Document)

    The reply document of the previous message.

  • connection (Server::Connection)

    The connection being authenticated.

Returns:

Since:

  • 2.0.0



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/mongo/auth/scram_conversation_base.rb', line 70

def continue(reply_document, connection)
  @id = reply_document['conversationId']
  payload_data = reply_document['payload'].data
  parsed_data = parse_payload(payload_data)
  @server_nonce = parsed_data.fetch('r')
  @salt = Base64.strict_decode64(parsed_data.fetch('s'))
  @iterations = parsed_data.fetch('i').to_i.tap do |i|
    if i < MIN_ITER_COUNT
      raise Error::InsufficientIterationCount.new(
        Error::InsufficientIterationCount.message(MIN_ITER_COUNT, i))
    end
  end
  @auth_message = "#{first_bare},#{payload_data},#{without_proof}"

  validate_server_nonce!

  selector = CLIENT_CONTINUE_MESSAGE.merge(
    payload: client_final_message,
    conversationId: id,
  )
  if connection && connection.features.op_msg_enabled?
    selector[Protocol::Msg::DATABASE_IDENTIFIER] = user.auth_source
    cluster_time = connection.mongos? && connection.cluster_time
    selector[Operation::CLUSTER_TIME] = cluster_time if cluster_time
    Protocol::Msg.new([], {}, selector)
  else
    Protocol::Query.new(
      user.auth_source,
      Database::COMMAND,
      selector,
      limit: -1,
    )
  end
end

#finalize(connection) ⇒ Protocol::Query

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Finalize the SCRAM conversation. This is meant to be iterated until the provided reply indicates the conversation is finished.

Parameters:

Returns:

Since:

  • 2.0.0



120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/mongo/auth/scram_conversation_base.rb', line 120

def finalize(connection)
  if connection && connection.features.op_msg_enabled?
    selector = CLIENT_CONTINUE_MESSAGE.merge(
      payload: client_empty_message,
      conversationId: id,
    )
    selector[Protocol::Msg::DATABASE_IDENTIFIER] = user.auth_source
    cluster_time = connection.mongos? && connection.cluster_time
    selector[Operation::CLUSTER_TIME] = cluster_time if cluster_time
    Protocol::Msg.new([], {}, selector)
  else
    Protocol::Query.new(
      user.auth_source,
      Database::COMMAND,
      CLIENT_CONTINUE_MESSAGE.merge(
        payload: client_empty_message,
        conversationId: id,
      ),
      limit: -1,
    )
  end
end

#process_continue_response(reply_document) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Processes the second response from the server.

Parameters:

  • reply_document (BSON::Document)

    The reply document of the continue response.

Since:

  • 2.0.0



109
110
111
112
# File 'lib/mongo/auth/scram_conversation_base.rb', line 109

def process_continue_response(reply_document)
  payload_data = parse_payload(reply_document['payload'].data)
  check_server_signature(payload_data)
end

#server_verified?true | fase

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Whether the client verified the ServerSignature from the server.

Returns:

  • (true | fase)

    Whether the server’s signature was verified.

See Also:

Since:

  • 2.0.0



56
57
58
# File 'lib/mongo/auth/scram_conversation_base.rb', line 56

def server_verified?
  !!@server_verified
end

#speculative_auth_documentHash | nil

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns the hash to provide to the server in the handshake as value of the speculativeAuthenticate key.

If the auth mechanism does not support speculative authentication, this method returns nil.

Returns:

  • (Hash | nil)

    Speculative authentication document.

Since:

  • 2.0.0



150
151
152
# File 'lib/mongo/auth/scram_conversation_base.rb', line 150

def speculative_auth_document
  client_first_document.merge(db: user.auth_source)
end