mongo 2.7.2 → 2.8.0.rc0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +1 -3
- data/lib/mongo/address.rb +17 -20
- data/lib/mongo/address/ipv4.rb +6 -3
- data/lib/mongo/address/ipv6.rb +6 -3
- data/lib/mongo/address/unix.rb +5 -2
- data/lib/mongo/auth.rb +15 -2
- data/lib/mongo/auth/cr/conversation.rb +4 -2
- data/lib/mongo/auth/ldap/conversation.rb +4 -2
- data/lib/mongo/auth/scram.rb +3 -7
- data/lib/mongo/auth/scram/conversation.rb +28 -19
- data/lib/mongo/auth/user.rb +45 -10
- data/lib/mongo/auth/x509/conversation.rb +4 -2
- data/lib/mongo/cluster.rb +9 -17
- data/lib/mongo/error.rb +2 -0
- data/lib/mongo/error/missing_password.rb +29 -0
- data/lib/mongo/error/operation_failure.rb +7 -3
- data/lib/mongo/error/parser.rb +2 -1
- data/lib/mongo/error/sdam_error_detection.rb +54 -0
- data/lib/mongo/operation/aggregate/command.rb +1 -16
- data/lib/mongo/operation/aggregate/op_msg.rb +1 -1
- data/lib/mongo/operation/collections_info.rb +2 -3
- data/lib/mongo/operation/delete/command.rb +2 -15
- data/lib/mongo/operation/delete/legacy.rb +1 -16
- data/lib/mongo/operation/explain/command.rb +1 -16
- data/lib/mongo/operation/explain/legacy.rb +1 -16
- data/lib/mongo/operation/find/command.rb +1 -16
- data/lib/mongo/operation/find/legacy.rb +1 -16
- data/lib/mongo/operation/get_more/command.rb +1 -16
- data/lib/mongo/operation/indexes/command.rb +1 -16
- data/lib/mongo/operation/indexes/legacy.rb +4 -16
- data/lib/mongo/operation/list_collections/command.rb +1 -16
- data/lib/mongo/operation/map_reduce/command.rb +1 -16
- data/lib/mongo/operation/parallel_scan/command.rb +1 -16
- data/lib/mongo/operation/result.rb +3 -0
- data/lib/mongo/operation/shared/executable.rb +4 -0
- data/lib/mongo/operation/shared/polymorphic_lookup.rb +1 -1
- data/lib/mongo/operation/shared/polymorphic_result.rb +8 -1
- data/lib/mongo/operation/shared/result/aggregatable.rb +0 -5
- data/lib/mongo/operation/update/command.rb +2 -15
- data/lib/mongo/operation/update/legacy.rb +1 -16
- data/lib/mongo/operation/users_info/command.rb +1 -16
- data/lib/mongo/retryable.rb +22 -10
- data/lib/mongo/server.rb +10 -1
- data/lib/mongo/server/app_metadata.rb +7 -2
- data/lib/mongo/server/connectable.rb +0 -6
- data/lib/mongo/server/connection.rb +86 -135
- data/lib/mongo/server/connection_base.rb +133 -0
- data/lib/mongo/server/connection_pool.rb +11 -24
- data/lib/mongo/server/connection_pool/queue.rb +41 -41
- data/lib/mongo/server/description.rb +1 -1
- data/lib/mongo/server/monitor.rb +4 -4
- data/lib/mongo/server/monitor/connection.rb +26 -7
- data/lib/mongo/server/pending_connection.rb +36 -0
- data/lib/mongo/server_selector/selectable.rb +9 -1
- data/lib/mongo/session.rb +0 -1
- data/lib/mongo/socket.rb +23 -6
- data/lib/mongo/socket/ssl.rb +11 -18
- data/lib/mongo/socket/tcp.rb +13 -14
- data/lib/mongo/socket/unix.rb +9 -27
- data/lib/mongo/uri.rb +1 -1
- data/lib/mongo/version.rb +1 -1
- data/spec/integration/auth_spec.rb +160 -0
- data/spec/integration/retryable_writes_spec.rb +55 -58
- data/spec/integration/sdam_error_handling_spec.rb +115 -0
- data/spec/mongo/address/ipv4_spec.rb +4 -0
- data/spec/mongo/address/ipv6_spec.rb +4 -0
- data/spec/mongo/auth/scram/conversation_spec.rb +6 -5
- data/spec/mongo/auth/scram/negotiation_spec.rb +25 -36
- data/spec/mongo/auth/scram_spec.rb +2 -2
- data/spec/mongo/auth/user_spec.rb +97 -0
- data/spec/mongo/client_construction_spec.rb +1 -1
- data/spec/mongo/error/operation_failure_spec.rb +125 -1
- data/spec/mongo/retryable_spec.rb +17 -8
- data/spec/mongo/server/connection_pool/queue_spec.rb +24 -10
- data/spec/mongo/server/connection_pool_spec.rb +30 -117
- data/spec/mongo/server/connection_spec.rb +147 -25
- data/spec/mongo/server/description_spec.rb +0 -14
- data/spec/mongo/server/monitor/connection_spec.rb +22 -0
- data/spec/mongo/server_selector_spec.rb +1 -0
- data/spec/mongo/server_spec.rb +6 -6
- data/spec/mongo/socket/ssl_spec.rb +48 -116
- data/spec/mongo/socket/tcp_spec.rb +22 -0
- data/spec/mongo/socket/unix_spec.rb +9 -9
- data/spec/mongo/socket_spec.rb +15 -3
- data/spec/spec_tests/server_selection_spec.rb +2 -0
- data/spec/support/client_registry.rb +8 -2
- data/spec/support/common_shortcuts.rb +20 -1
- data/spec/support/constraints.rb +10 -2
- data/spec/support/lite_constraints.rb +8 -0
- data/spec/support/spec_config.rb +9 -1
- metadata +14 -4
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5c0c1dd6dd1ce8ec0ce98e4f038bb188a743d65b0fd45f42383e732b8a9fe6e0
|
4
|
+
data.tar.gz: 69a9fcd5c2284e95b7af207ae381bc5fb4b9a0d00d941b54bb7d86a126a62e70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eb0c350dc452f0eb60656e0a2e6657e0002a7760de5bb3af7820af77876046f48bd7946e8d7d39a727dd80eda43e48656db52b941c2ab45ea6096ba826049a4d
|
7
|
+
data.tar.gz: d13ac4eec40c58e932f61fe5cb3f52259ca77a8ed08f079edf910927b9bb5e0c0ec77e0461374ab6c0f783726b1a5c7972e12c63c8a6d2eb46a6170a80543538
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
data.tar.gz.sig
CHANGED
@@ -1,3 +1 @@
|
|
1
|
-
|
2
|
-
(�GIB�U"oS��8����x|�F}WG�H�-*Ĝr`��f�%�R�M{Go_c'g��˛�'u��?����5LxI�@�x�R<���TԤ���*h�>��.�Fd�*��{������$u~����E�mmE�@pE
|
3
|
-
kRd���)C�&�q��CM*��K���?mܴن�1#K$f렸E��u�}6N�
|
1
|
+
��zW�Y���MH{�zG.�vr�fτ#V���?�Y���b�;�86�o\z�E^����V�b��K=��:����G���壘s��yҌ�uA[݁XSG�Z9>�|�<DZ�Ԍ~2�&�v2�Ȭf/p�n�������-�WLfU�rl,�s_��h'nn����q�;7��vD#�0y}�j"r����H�Rj�N�8=4����YQ�@d#�ԉޮf��.�:��r�b�ӯ�Eʎ��ӗ,��j�_��
|
data/lib/mongo/address.rb
CHANGED
@@ -147,12 +147,15 @@ module Mongo
|
|
147
147
|
#
|
148
148
|
# @param [ Float ] socket_timeout The socket timeout.
|
149
149
|
# @param [ Hash ] ssl_options SSL options.
|
150
|
+
# @param [ Hash ] options The options.
|
151
|
+
#
|
152
|
+
# @option options [ Float ] :connect_timeout Connect timeout.
|
150
153
|
#
|
151
154
|
# @return [ Mongo::Socket::SSL, Mongo::Socket::TCP, Mongo::Socket::Unix ] The socket.
|
152
155
|
#
|
153
156
|
# @since 2.0.0
|
154
|
-
def socket(socket_timeout, ssl_options = {})
|
155
|
-
create_resolver(ssl_options).socket(socket_timeout, ssl_options)
|
157
|
+
def socket(socket_timeout, ssl_options = {}, options = {})
|
158
|
+
create_resolver(ssl_options).socket(socket_timeout, ssl_options, options)
|
156
159
|
end
|
157
160
|
|
158
161
|
# Get the address as a string.
|
@@ -175,25 +178,17 @@ module Mongo
|
|
175
178
|
end
|
176
179
|
end
|
177
180
|
|
178
|
-
#
|
179
|
-
#
|
180
|
-
# @example Connect a socket.
|
181
|
-
# address.connect_socket!(socket)
|
182
|
-
#
|
183
|
-
# @since 2.4.3
|
184
|
-
def connect_socket!(socket)
|
185
|
-
socket.connect!(connect_timeout)
|
186
|
-
end
|
187
|
-
|
188
|
-
private
|
189
|
-
|
181
|
+
# @api private
|
190
182
|
def connect_timeout
|
191
183
|
@connect_timeout ||= @options[:connect_timeout] || Server::CONNECT_TIMEOUT
|
192
184
|
end
|
193
185
|
|
194
|
-
|
195
|
-
|
196
|
-
#
|
186
|
+
private
|
187
|
+
|
188
|
+
# To determine which address the socket will connect to, the driver will
|
189
|
+
# attempt to connect to each IP address returned by Socket::getaddrinfo in
|
190
|
+
# sequence. Once a successful connection is made, a resolver with that
|
191
|
+
# IP address specified is returned. If no successful connection is
|
197
192
|
# made, the error made by the last connection attempt is raised.
|
198
193
|
def create_resolver(ssl_options)
|
199
194
|
return Unix.new(seed.downcase) if seed.downcase =~ Unix::MATCH
|
@@ -202,9 +197,11 @@ module Mongo
|
|
202
197
|
error = nil
|
203
198
|
::Socket.getaddrinfo(host, nil, family, ::Socket::SOCK_STREAM).each do |info|
|
204
199
|
begin
|
205
|
-
|
206
|
-
|
207
|
-
|
200
|
+
specific_address = FAMILY_MAP[info[4]].new(info[3], port, host)
|
201
|
+
socket = specific_address.socket(
|
202
|
+
connect_timeout, ssl_options, connect_timeout: connect_timeout)
|
203
|
+
socket.close
|
204
|
+
return specific_address
|
208
205
|
rescue IOError, SystemCallError, Error::SocketTimeoutError, Error::SocketError => e
|
209
206
|
error = e
|
210
207
|
end
|
data/lib/mongo/address/ipv4.rb
CHANGED
@@ -79,15 +79,18 @@ module Mongo
|
|
79
79
|
#
|
80
80
|
# @param [ Float ] socket_timeout The socket timeout.
|
81
81
|
# @param [ Hash ] ssl_options SSL options.
|
82
|
+
# @param [ Hash ] options The options.
|
83
|
+
#
|
84
|
+
# @option options [ Float ] :connect_timeout Connect timeout.
|
82
85
|
#
|
83
86
|
# @return [ Mongo::Socket::SSL, Mongo::Socket::TCP ] The socket.
|
84
87
|
#
|
85
88
|
# @since 2.0.0
|
86
|
-
def socket(socket_timeout, ssl_options = {})
|
89
|
+
def socket(socket_timeout, ssl_options = {}, options = {})
|
87
90
|
unless ssl_options.empty?
|
88
|
-
Socket::SSL.new(host, port, host_name, socket_timeout, Socket::PF_INET, ssl_options)
|
91
|
+
Socket::SSL.new(host, port, host_name, socket_timeout, Socket::PF_INET, ssl_options.merge(options))
|
89
92
|
else
|
90
|
-
Socket::TCP.new(host, port, socket_timeout, Socket::PF_INET)
|
93
|
+
Socket::TCP.new(host, port, socket_timeout, Socket::PF_INET, options)
|
91
94
|
end
|
92
95
|
end
|
93
96
|
end
|
data/lib/mongo/address/ipv6.rb
CHANGED
@@ -95,15 +95,18 @@ module Mongo
|
|
95
95
|
#
|
96
96
|
# @param [ Float ] socket_timeout The socket timeout.
|
97
97
|
# @param [ Hash ] ssl_options SSL options.
|
98
|
+
# @param [ Hash ] options The options.
|
99
|
+
#
|
100
|
+
# @option options [ Float ] :connect_timeout Connect timeout.
|
98
101
|
#
|
99
102
|
# @return [ Mongo::Socket::SSL, Mongo::Socket::TCP ] The socket.
|
100
103
|
#
|
101
104
|
# @since 2.0.0
|
102
|
-
def socket(socket_timeout, ssl_options = {})
|
105
|
+
def socket(socket_timeout, ssl_options = {}, options = {})
|
103
106
|
unless ssl_options.empty?
|
104
|
-
Socket::SSL.new(host, port, host_name, socket_timeout, Socket::PF_INET6, ssl_options)
|
107
|
+
Socket::SSL.new(host, port, host_name, socket_timeout, Socket::PF_INET6, ssl_options.merge(options))
|
105
108
|
else
|
106
|
-
Socket::TCP.new(host, port, socket_timeout, Socket::PF_INET6)
|
109
|
+
Socket::TCP.new(host, port, socket_timeout, Socket::PF_INET6, options)
|
107
110
|
end
|
108
111
|
end
|
109
112
|
end
|
data/lib/mongo/address/unix.rb
CHANGED
@@ -64,12 +64,15 @@ module Mongo
|
|
64
64
|
#
|
65
65
|
# @param [ Float ] socket_timeout The socket timeout.
|
66
66
|
# @param [ Hash ] ssl_options SSL options - ignored.
|
67
|
+
# @param [ Hash ] options The options.
|
68
|
+
#
|
69
|
+
# @option options [ Float ] :connect_timeout Connect timeout.
|
67
70
|
#
|
68
71
|
# @return [ Mongo::Socket::Unix ] The socket.
|
69
72
|
#
|
70
73
|
# @since 2.0.0
|
71
|
-
def socket(socket_timeout, ssl_options = {})
|
72
|
-
Socket::Unix.new(host, socket_timeout)
|
74
|
+
def socket(socket_timeout, ssl_options = {}, options = {})
|
75
|
+
Socket::Unix.new(host, socket_timeout, options)
|
73
76
|
end
|
74
77
|
end
|
75
78
|
end
|
data/lib/mongo/auth.rb
CHANGED
@@ -102,10 +102,23 @@ module Mongo
|
|
102
102
|
# Mongo::Auth::Unauthorized.new(user)
|
103
103
|
#
|
104
104
|
# @param [ Mongo::Auth::User ] user The unauthorized user.
|
105
|
+
# @param [ String ] used_mechanism Auth mechanism actually used for
|
106
|
+
# authentication. This is a full string like SCRAM-SHA-256.
|
105
107
|
#
|
106
108
|
# @since 2.0.0
|
107
|
-
def initialize(user)
|
108
|
-
|
109
|
+
def initialize(user, used_mechanism = nil)
|
110
|
+
specified_mechanism = if user.mechanism
|
111
|
+
" (mechanism: #{user.mechanism})"
|
112
|
+
else
|
113
|
+
''
|
114
|
+
end
|
115
|
+
used_mechanism = if used_mechanism
|
116
|
+
" (used mechanism: #{used_mechanism})"
|
117
|
+
else
|
118
|
+
''
|
119
|
+
end
|
120
|
+
msg = "User #{user.name}#{specified_mechanism} is not authorized to access #{user.database}#{used_mechanism}"
|
121
|
+
super(msg)
|
109
122
|
end
|
110
123
|
end
|
111
124
|
end
|
@@ -92,7 +92,7 @@ module Mongo
|
|
92
92
|
end
|
93
93
|
|
94
94
|
# Start the CR conversation. This returns the first message that
|
95
|
-
# needs to be
|
95
|
+
# needs to be sent to the server.
|
96
96
|
#
|
97
97
|
# @example Start the conversation.
|
98
98
|
# conversation.start
|
@@ -130,7 +130,9 @@ module Mongo
|
|
130
130
|
private
|
131
131
|
|
132
132
|
def validate!(reply)
|
133
|
-
|
133
|
+
if reply.documents[0][Operation::Result::OK] != 1
|
134
|
+
raise Unauthorized.new(user, MECHANISM)
|
135
|
+
end
|
134
136
|
@nonce = reply.documents[0][Auth::NONCE]
|
135
137
|
@reply = reply
|
136
138
|
end
|
@@ -51,7 +51,7 @@ module Mongo
|
|
51
51
|
end
|
52
52
|
|
53
53
|
# Start the PLAIN conversation. This returns the first message that
|
54
|
-
# needs to be
|
54
|
+
# needs to be sent to the server.
|
55
55
|
#
|
56
56
|
# @example Start the conversation.
|
57
57
|
# conversation.start
|
@@ -97,7 +97,9 @@ module Mongo
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def validate!(reply)
|
100
|
-
|
100
|
+
if reply.documents[0][Operation::Result::OK] != 1
|
101
|
+
raise Unauthorized.new(user, MECHANISM)
|
102
|
+
end
|
101
103
|
@reply = reply
|
102
104
|
end
|
103
105
|
end
|
data/lib/mongo/auth/scram.rb
CHANGED
@@ -32,7 +32,6 @@ module Mongo
|
|
32
32
|
# @since 2.6.0
|
33
33
|
SCRAM_SHA_256_MECHANISM = 'SCRAM-SHA-256'.freeze
|
34
34
|
|
35
|
-
|
36
35
|
# Map the user-specified authentication mechanism to the proper names of the mechanisms.
|
37
36
|
#
|
38
37
|
# @since 2.6.0
|
@@ -62,16 +61,13 @@ module Mongo
|
|
62
61
|
# user.login(connection)
|
63
62
|
#
|
64
63
|
# @param [ Mongo::Connection ] connection The connection to log into.
|
65
|
-
# on.
|
66
|
-
# @param [ String ] mechanism The auth mechanism to use (either 'SCRAM-SHA-1' or
|
67
|
-
# 'SCRAM-SHA-256');
|
68
64
|
#
|
69
65
|
# @return [ Protocol::Message ] The authentication response.
|
70
66
|
#
|
71
67
|
# @since 2.0.0
|
72
|
-
def login(connection
|
73
|
-
mechanism
|
74
|
-
conversation = Conversation.new(user,
|
68
|
+
def login(connection)
|
69
|
+
mechanism = user.mechanism || :scram
|
70
|
+
conversation = Conversation.new(user, mechanism)
|
75
71
|
reply = connection.dispatch([ conversation.start(connection) ])
|
76
72
|
connection.update_cluster_time(Operation::Result.new(reply))
|
77
73
|
reply = connection.dispatch([ conversation.continue(reply, connection) ])
|
@@ -19,8 +19,8 @@ module Mongo
|
|
19
19
|
module Auth
|
20
20
|
class SCRAM
|
21
21
|
|
22
|
-
# Defines behavior around a single SCRAM-SHA-1 conversation between
|
23
|
-
# client and server.
|
22
|
+
# Defines behavior around a single SCRAM-SHA-1/256 conversation between
|
23
|
+
# the client and server.
|
24
24
|
#
|
25
25
|
# @since 2.0.0
|
26
26
|
class Conversation
|
@@ -168,7 +168,7 @@ module Mongo
|
|
168
168
|
end
|
169
169
|
|
170
170
|
# Start the SCRAM conversation. This returns the first message that
|
171
|
-
# needs to be
|
171
|
+
# needs to be sent to the server.
|
172
172
|
#
|
173
173
|
# @example Start the conversation.
|
174
174
|
# conversation.start
|
@@ -180,7 +180,8 @@ module Mongo
|
|
180
180
|
# @since 2.0.0
|
181
181
|
def start(connection = nil)
|
182
182
|
if connection && connection.features.op_msg_enabled?
|
183
|
-
selector = CLIENT_FIRST_MESSAGE.merge(
|
183
|
+
selector = CLIENT_FIRST_MESSAGE.merge(
|
184
|
+
payload: client_first_message, mechanism: full_mechanism)
|
184
185
|
selector[Protocol::Msg::DATABASE_IDENTIFIER] = user.auth_source
|
185
186
|
cluster_time = connection.mongos? && connection.cluster_time
|
186
187
|
selector[Operation::CLUSTER_TIME] = cluster_time if cluster_time
|
@@ -189,12 +190,17 @@ module Mongo
|
|
189
190
|
Protocol::Query.new(
|
190
191
|
user.auth_source,
|
191
192
|
Database::COMMAND,
|
192
|
-
CLIENT_FIRST_MESSAGE.merge(
|
193
|
+
CLIENT_FIRST_MESSAGE.merge(
|
194
|
+
payload: client_first_message, mechanism: full_mechanism),
|
193
195
|
limit: -1
|
194
196
|
)
|
195
197
|
end
|
196
198
|
end
|
197
199
|
|
200
|
+
def full_mechanism
|
201
|
+
MECHANISMS[@mechanism]
|
202
|
+
end
|
203
|
+
|
198
204
|
# Get the id of the conversation.
|
199
205
|
#
|
200
206
|
# @example Get the id of the conversation.
|
@@ -213,9 +219,14 @@ module Mongo
|
|
213
219
|
# Conversation.new(user, mechanism)
|
214
220
|
#
|
215
221
|
# @param [ Auth::User ] user The user to converse about.
|
222
|
+
# @param [ Symbol ] mechanism Authentication mechanism.
|
216
223
|
#
|
217
224
|
# @since 2.0.0
|
218
225
|
def initialize(user, mechanism)
|
226
|
+
unless [:scram, :scram256].include?(mechanism)
|
227
|
+
raise InvalidMechanism.new(mechanism)
|
228
|
+
end
|
229
|
+
|
219
230
|
@user = user
|
220
231
|
@nonce = SecureRandom.base64
|
221
232
|
@client_key = user.send(:client_key)
|
@@ -343,7 +354,7 @@ module Mongo
|
|
343
354
|
# @since 2.0.0
|
344
355
|
def hi(data)
|
345
356
|
case @mechanism
|
346
|
-
when
|
357
|
+
when :scram256
|
347
358
|
OpenSSL::PKCS5.pbkdf2_hmac(
|
348
359
|
data,
|
349
360
|
Base64.strict_decode64(salt),
|
@@ -381,7 +392,7 @@ module Mongo
|
|
381
392
|
@iterations ||= payload_data.match(ITERATIONS)[1].to_i.tap do |i|
|
382
393
|
if i < MIN_ITER_COUNT
|
383
394
|
raise Error::InsufficientIterationCount.new(
|
384
|
-
Error::InsufficientIterationCount.message(MIN_ITER_COUNT,
|
395
|
+
Error::InsufficientIterationCount.message(MIN_ITER_COUNT, i))
|
385
396
|
end
|
386
397
|
end
|
387
398
|
end
|
@@ -421,7 +432,12 @@ module Mongo
|
|
421
432
|
#
|
422
433
|
# @since 2.0.0
|
423
434
|
def salted_password
|
424
|
-
@salted_password ||=
|
435
|
+
@salted_password ||= case @mechanism
|
436
|
+
when :scram256
|
437
|
+
hi(user.sasl_prepped_password)
|
438
|
+
else
|
439
|
+
hi(user.hashed_password)
|
440
|
+
end
|
425
441
|
end
|
426
442
|
|
427
443
|
# Server key algorithm implementation.
|
@@ -505,24 +521,17 @@ module Mongo
|
|
505
521
|
end
|
506
522
|
|
507
523
|
def validate!(reply)
|
508
|
-
|
524
|
+
if reply.documents[0][Operation::Result::OK] != 1
|
525
|
+
raise Unauthorized.new(user, full_mechanism)
|
526
|
+
end
|
509
527
|
@reply = reply
|
510
528
|
end
|
511
529
|
|
512
530
|
private
|
513
531
|
|
514
|
-
def hashed_password
|
515
|
-
case @mechanism
|
516
|
-
when SCRAM::SCRAM_SHA_256_MECHANISM
|
517
|
-
user.sasl_prepped_hashed_password
|
518
|
-
else
|
519
|
-
user.hashed_password
|
520
|
-
end
|
521
|
-
end
|
522
|
-
|
523
532
|
def digest
|
524
533
|
@digest ||= case @mechanism
|
525
|
-
when
|
534
|
+
when :scram256
|
526
535
|
OpenSSL::Digest::SHA256.new.freeze
|
527
536
|
else
|
528
537
|
OpenSSL::Digest::SHA1.new.freeze
|
data/lib/mongo/auth/user.rb
CHANGED
@@ -21,6 +21,7 @@ module Mongo
|
|
21
21
|
#
|
22
22
|
# @since 2.0.0
|
23
23
|
class User
|
24
|
+
include Loggable
|
24
25
|
|
25
26
|
# @return [ String ] The authorization source, either a database or
|
26
27
|
# external name.
|
@@ -44,6 +45,14 @@ module Mongo
|
|
44
45
|
# @return [ Array<String> ] roles The user roles.
|
45
46
|
attr_reader :roles
|
46
47
|
|
48
|
+
# Loggable requires an options attribute. We don't have any options
|
49
|
+
# hence provide this as a stub.
|
50
|
+
#
|
51
|
+
# @api private
|
52
|
+
def options
|
53
|
+
{}
|
54
|
+
end
|
55
|
+
|
47
56
|
# Determine if this user is equal to another.
|
48
57
|
#
|
49
58
|
# @example Check user equality.
|
@@ -99,7 +108,7 @@ module Mongo
|
|
99
108
|
[ name, database, password ].hash
|
100
109
|
end
|
101
110
|
|
102
|
-
# Get the user's hashed password.
|
111
|
+
# Get the user's hashed password for SCRAM-SHA-1.
|
103
112
|
#
|
104
113
|
# @example Get the user's hashed password.
|
105
114
|
# user.hashed_password
|
@@ -108,11 +117,25 @@ module Mongo
|
|
108
117
|
#
|
109
118
|
# @since 2.0.0
|
110
119
|
def hashed_password
|
120
|
+
unless password
|
121
|
+
raise Error::MissingPassword
|
122
|
+
end
|
123
|
+
|
111
124
|
@hashed_password ||= Digest::MD5.hexdigest("#{name}:mongo:#{password}").encode(BSON::UTF8)
|
112
125
|
end
|
113
126
|
|
114
|
-
|
115
|
-
|
127
|
+
# Get the user's stringprepped password for SCRAM-SHA-256.
|
128
|
+
#
|
129
|
+
# @api private
|
130
|
+
def sasl_prepped_password
|
131
|
+
unless password
|
132
|
+
raise Error::MissingPassword
|
133
|
+
end
|
134
|
+
|
135
|
+
@sasl_prepped_password ||= StringPrep.prepare(password,
|
136
|
+
StringPrep::Profiles::SASL::MAPPINGS,
|
137
|
+
StringPrep::Profiles::SASL::PROHIBITED,
|
138
|
+
normalize: true, bidi: true).encode(BSON::UTF8)
|
116
139
|
end
|
117
140
|
|
118
141
|
# Create the new user.
|
@@ -140,6 +163,25 @@ module Mongo
|
|
140
163
|
@name = options[:user]
|
141
164
|
@password = options[:password] || options[:pwd]
|
142
165
|
@mechanism = options[:auth_mech]
|
166
|
+
if @mechanism
|
167
|
+
# Since the driver must select an authentication class for
|
168
|
+
# the specified mechanism, mechanisms that the driver does not
|
169
|
+
# know about, and cannot translate to an authentication class,
|
170
|
+
# need to be rejected.
|
171
|
+
unless @mechanism.is_a?(Symbol)
|
172
|
+
# Although we documented auth_mech option as being a symbol, we
|
173
|
+
# have not enforced this; warn, reject in lint mode
|
174
|
+
if Lint.enabled?
|
175
|
+
raise Error::LintError, "Auth mechanism #{@mechanism.inspect} must be specified as a symbol"
|
176
|
+
else
|
177
|
+
log_warn("Auth mechanism #{@mechanism.inspect} should be specified as a symbol")
|
178
|
+
@mechanism = @mechanism.to_sym
|
179
|
+
end
|
180
|
+
end
|
181
|
+
unless Auth::SOURCES.key?(@mechanism)
|
182
|
+
raise InvalidMechanism.new(options[:auth_mech])
|
183
|
+
end
|
184
|
+
end
|
143
185
|
@auth_mech_properties = options[:auth_mech_properties] || {}
|
144
186
|
@roles = options[:roles] || []
|
145
187
|
@client_key = options[:client_key]
|
@@ -159,13 +201,6 @@ module Mongo
|
|
159
201
|
|
160
202
|
private
|
161
203
|
|
162
|
-
def sasl_prepped_password
|
163
|
-
StringPrep.prepare(password,
|
164
|
-
StringPrep::Profiles::SASL::MAPPINGS,
|
165
|
-
StringPrep::Profiles::SASL::PROHIBITED,
|
166
|
-
normalize: true, bidi: true)
|
167
|
-
end
|
168
|
-
|
169
204
|
# The client key for the user.
|
170
205
|
#
|
171
206
|
# @return [ String ] The client key for the user.
|