mongo 1.12.5 → 2.0.0.beta

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.
Files changed (437) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/CONTRIBUTING.md +64 -0
  5. data/LICENSE +1 -1
  6. data/README.md +23 -125
  7. data/Rakefile +26 -21
  8. data/bin/mongo_console +6 -38
  9. data/lib/mongo.rb +23 -82
  10. data/lib/mongo/address.rb +111 -0
  11. data/lib/mongo/address/ipv4.rb +85 -0
  12. data/lib/mongo/address/ipv6.rb +85 -0
  13. data/lib/mongo/address/unix.rb +76 -0
  14. data/lib/mongo/auth.rb +108 -0
  15. data/lib/mongo/auth/cr.rb +44 -0
  16. data/lib/mongo/auth/cr/conversation.rb +119 -0
  17. data/lib/mongo/auth/executable.rb +52 -0
  18. data/lib/mongo/auth/ldap.rb +48 -0
  19. data/lib/mongo/auth/ldap/conversation.rb +92 -0
  20. data/lib/mongo/auth/roles.rb +104 -0
  21. data/lib/mongo/auth/scram.rb +53 -0
  22. data/lib/mongo/auth/scram/conversation.rb +450 -0
  23. data/lib/mongo/auth/user.rb +159 -0
  24. data/lib/mongo/auth/user/view.rb +102 -0
  25. data/lib/mongo/auth/x509.rb +48 -0
  26. data/lib/mongo/auth/x509/conversation.rb +92 -0
  27. data/lib/mongo/{gridfs.rb → bulk.rb} +2 -5
  28. data/lib/mongo/bulk/bulk_write.rb +307 -0
  29. data/lib/mongo/client.rb +233 -0
  30. data/lib/mongo/cluster.rb +203 -0
  31. data/lib/mongo/cluster/topology.rb +60 -0
  32. data/lib/mongo/cluster/topology/replica_set.rb +160 -0
  33. data/lib/mongo/cluster/topology/sharded.rb +132 -0
  34. data/lib/mongo/cluster/topology/standalone.rb +132 -0
  35. data/lib/mongo/cluster/topology/unknown.rb +155 -0
  36. data/lib/mongo/collection.rb +130 -1101
  37. data/lib/mongo/collection/view.rb +169 -0
  38. data/lib/mongo/collection/view/aggregation.rb +108 -0
  39. data/lib/mongo/collection/view/explainable.rb +49 -0
  40. data/lib/mongo/collection/view/immutable.rb +43 -0
  41. data/lib/mongo/collection/view/iterable.rb +48 -0
  42. data/lib/mongo/collection/view/map_reduce.rb +191 -0
  43. data/lib/mongo/collection/view/readable.rb +363 -0
  44. data/lib/mongo/collection/view/writable.rb +169 -0
  45. data/lib/mongo/cursor.rb +79 -680
  46. data/lib/mongo/database.rb +224 -0
  47. data/lib/mongo/database/view.rb +101 -0
  48. data/lib/mongo/error.rb +81 -0
  49. data/lib/mongo/error/bulk_write_failure.rb +41 -0
  50. data/lib/mongo/{utils/thread_local_variable_manager.rb → error/empty_batch.rb} +22 -8
  51. data/{test/functional/db_connection_test.rb → lib/mongo/error/invalid_bulk_operation.rb} +19 -8
  52. data/lib/mongo/error/invalid_collection_name.rb +39 -0
  53. data/lib/mongo/error/invalid_database_name.rb +39 -0
  54. data/{test/replica_set/ssl_test.rb → lib/mongo/error/invalid_document.rb} +21 -14
  55. data/lib/mongo/error/invalid_file.rb +38 -0
  56. data/lib/mongo/error/invalid_nonce.rb +46 -0
  57. data/lib/mongo/error/invalid_replacement_document.rb +39 -0
  58. data/lib/mongo/error/invalid_signature.rb +47 -0
  59. data/{test/functional/ssl_test.rb → lib/mongo/error/invalid_update_document.rb} +22 -12
  60. data/lib/mongo/error/max_bson_size.rb +40 -0
  61. data/lib/mongo/error/max_message_size.rb +42 -0
  62. data/lib/mongo/{utils.rb → error/need_primary_server.rb} +10 -6
  63. data/lib/mongo/{connection.rb → error/operation_failure.rb} +10 -6
  64. data/lib/mongo/error/parser.rb +77 -0
  65. data/lib/mongo/{connection/socket.rb → error/socket_error.rb} +10 -5
  66. data/lib/mongo/error/socket_timeout_error.rb +23 -0
  67. data/lib/mongo/error/unsupported_features.rb +43 -0
  68. data/lib/mongo/event.rb +40 -0
  69. data/lib/mongo/event/listeners.rb +63 -0
  70. data/lib/mongo/event/primary_elected.rb +53 -0
  71. data/lib/mongo/event/publisher.rb +42 -0
  72. data/lib/mongo/event/server_added.rb +53 -0
  73. data/lib/mongo/event/server_removed.rb +53 -0
  74. data/lib/mongo/event/subscriber.rb +41 -0
  75. data/lib/mongo/grid.rb +16 -0
  76. data/lib/mongo/grid/file.rb +94 -0
  77. data/lib/mongo/grid/file/chunk.rb +184 -0
  78. data/lib/mongo/grid/file/metadata.rb +223 -0
  79. data/lib/mongo/grid/fs.rb +149 -0
  80. data/lib/mongo/index.rb +64 -0
  81. data/lib/mongo/index/view.rb +205 -0
  82. data/lib/mongo/loggable.rb +126 -0
  83. data/lib/mongo/logger.rb +132 -0
  84. data/lib/mongo/operation.rb +26 -0
  85. data/lib/mongo/operation/aggregate.rb +100 -0
  86. data/lib/mongo/operation/aggregate/result.rb +84 -0
  87. data/lib/mongo/operation/batchable.rb +103 -0
  88. data/lib/mongo/operation/bulk_delete/result.rb +197 -0
  89. data/lib/mongo/operation/bulk_insert/result.rb +195 -0
  90. data/lib/mongo/operation/bulk_update/result.rb +295 -0
  91. data/lib/mongo/operation/command.rb +62 -0
  92. data/lib/mongo/operation/executable.rb +105 -0
  93. data/lib/mongo/operation/kill_cursors.rb +39 -0
  94. data/lib/mongo/operation/limited.rb +37 -0
  95. data/lib/mongo/operation/list_collections/result.rb +116 -0
  96. data/lib/mongo/operation/list_indexes/result.rb +118 -0
  97. data/lib/mongo/operation/map_reduce.rb +96 -0
  98. data/lib/mongo/operation/map_reduce/result.rb +122 -0
  99. data/lib/mongo/{functional.rb → operation/read.rb} +7 -7
  100. data/lib/mongo/operation/read/collections_info.rb +67 -0
  101. data/lib/mongo/operation/read/get_more.rb +71 -0
  102. data/lib/mongo/operation/read/indexes.rb +68 -0
  103. data/lib/mongo/operation/read/list_collections.rb +75 -0
  104. data/lib/mongo/operation/read/list_indexes.rb +77 -0
  105. data/lib/mongo/operation/read/query.rb +71 -0
  106. data/lib/mongo/operation/read_preferrable.rb +34 -0
  107. data/lib/mongo/operation/result.rb +259 -0
  108. data/lib/mongo/operation/specifiable.rb +380 -0
  109. data/lib/mongo/operation/write.rb +25 -0
  110. data/lib/mongo/operation/write/bulk_delete.rb +158 -0
  111. data/lib/mongo/operation/write/bulk_insert.rb +160 -0
  112. data/lib/mongo/operation/write/bulk_update.rb +167 -0
  113. data/lib/mongo/{connection/socket/socket_util.rb → operation/write/command.rb} +9 -24
  114. data/lib/mongo/operation/write/command/create_user.rb +43 -0
  115. data/lib/mongo/operation/write/command/delete.rb +56 -0
  116. data/lib/mongo/operation/write/command/drop_index.rb +51 -0
  117. data/lib/mongo/operation/write/command/ensure_index.rb +55 -0
  118. data/lib/mongo/operation/write/command/insert.rb +55 -0
  119. data/lib/mongo/operation/write/command/remove_user.rb +42 -0
  120. data/lib/mongo/operation/write/command/update.rb +60 -0
  121. data/lib/mongo/operation/write/command/writable.rb +61 -0
  122. data/lib/mongo/operation/write/create_index.rb +84 -0
  123. data/lib/mongo/operation/write/create_user.rb +75 -0
  124. data/lib/mongo/operation/write/delete.rb +91 -0
  125. data/lib/mongo/operation/write/drop_index.rb +62 -0
  126. data/lib/mongo/operation/write/insert.rb +88 -0
  127. data/lib/mongo/operation/write/remove_user.rb +70 -0
  128. data/lib/mongo/operation/write/update.rb +98 -0
  129. data/lib/mongo/protocol.rb +15 -0
  130. data/lib/mongo/protocol/bit_vector.rb +61 -0
  131. data/lib/mongo/protocol/delete.rb +94 -0
  132. data/lib/mongo/protocol/get_more.rb +99 -0
  133. data/lib/mongo/protocol/insert.rb +99 -0
  134. data/lib/mongo/protocol/kill_cursors.rb +74 -0
  135. data/lib/mongo/protocol/message.rb +252 -0
  136. data/lib/mongo/protocol/query.rb +147 -0
  137. data/lib/mongo/protocol/reply.rb +72 -0
  138. data/lib/mongo/protocol/serializers.rb +180 -0
  139. data/lib/mongo/protocol/update.rb +111 -0
  140. data/lib/mongo/server.rb +163 -0
  141. data/lib/mongo/server/connectable.rb +99 -0
  142. data/lib/mongo/server/connection.rb +133 -0
  143. data/lib/mongo/server/connection_pool.rb +141 -0
  144. data/lib/mongo/server/connection_pool/queue.rb +182 -0
  145. data/lib/mongo/server/context.rb +66 -0
  146. data/lib/mongo/server/description.rb +450 -0
  147. data/lib/mongo/server/description/features.rb +85 -0
  148. data/lib/mongo/server/description/inspector.rb +79 -0
  149. data/lib/mongo/server/description/inspector/primary_elected.rb +58 -0
  150. data/lib/mongo/server/description/inspector/server_added.rb +59 -0
  151. data/lib/mongo/server/description/inspector/server_removed.rb +59 -0
  152. data/lib/mongo/server/monitor.rb +160 -0
  153. data/lib/mongo/server/monitor/connection.rb +88 -0
  154. data/lib/mongo/server_selector.rb +81 -0
  155. data/lib/mongo/server_selector/nearest.rb +94 -0
  156. data/lib/mongo/server_selector/primary.rb +88 -0
  157. data/lib/mongo/server_selector/primary_preferred.rb +94 -0
  158. data/lib/mongo/server_selector/secondary.rb +91 -0
  159. data/lib/mongo/server_selector/secondary_preferred.rb +96 -0
  160. data/lib/mongo/server_selector/selectable.rb +209 -0
  161. data/lib/mongo/socket.rb +179 -0
  162. data/lib/mongo/socket/ssl.rb +108 -0
  163. data/lib/mongo/socket/tcp.rb +69 -0
  164. data/lib/mongo/socket/unix.rb +66 -0
  165. data/lib/mongo/uri.rb +504 -0
  166. data/lib/mongo/version.rb +21 -0
  167. data/lib/mongo/write_concern.rb +99 -0
  168. data/lib/mongo/write_concern/acknowledged.rb +38 -0
  169. data/lib/mongo/write_concern/normalizable.rb +73 -0
  170. data/lib/mongo/write_concern/unacknowledged.rb +43 -0
  171. data/mongo.gemspec +17 -14
  172. data/spec/mongo/address/ipv4_spec.rb +74 -0
  173. data/spec/mongo/address/ipv6_spec.rb +74 -0
  174. data/spec/mongo/address/unix_spec.rb +30 -0
  175. data/spec/mongo/address_spec.rb +206 -0
  176. data/spec/mongo/auth/cr_spec.rb +59 -0
  177. data/spec/mongo/auth/ldap_spec.rb +40 -0
  178. data/spec/mongo/auth/scram/conversation_spec.rb +197 -0
  179. data/spec/mongo/auth/scram_spec.rb +55 -0
  180. data/spec/mongo/auth/user/view_spec.rb +76 -0
  181. data/spec/mongo/auth/user_spec.rb +190 -0
  182. data/spec/mongo/auth/x509_spec.rb +40 -0
  183. data/spec/mongo/auth_spec.rb +65 -0
  184. data/spec/mongo/bulk/bulk_write_spec.rb +175 -0
  185. data/spec/mongo/client_spec.rb +564 -0
  186. data/spec/mongo/cluster/topology/replica_set_spec.rb +101 -0
  187. data/spec/mongo/cluster/topology/sharded_spec.rb +74 -0
  188. data/spec/mongo/cluster/topology/standalone_spec.rb +79 -0
  189. data/spec/mongo/cluster/topology_spec.rb +65 -0
  190. data/spec/mongo/cluster_spec.rb +129 -0
  191. data/spec/mongo/collection/view/aggregation_spec.rb +135 -0
  192. data/spec/mongo/collection/view/explainable_spec.rb +32 -0
  193. data/spec/mongo/collection/view/map_reduce_spec.rb +242 -0
  194. data/spec/mongo/collection/view/readable_spec.rb +603 -0
  195. data/spec/mongo/collection/view/writable_spec.rb +504 -0
  196. data/spec/mongo/collection/view_spec.rb +521 -0
  197. data/spec/mongo/collection_spec.rb +362 -0
  198. data/spec/mongo/cursor_spec.rb +295 -0
  199. data/spec/mongo/database_spec.rb +306 -0
  200. data/spec/mongo/error/parser_spec.rb +119 -0
  201. data/spec/mongo/event/publisher_spec.rb +50 -0
  202. data/spec/mongo/event/subscriber_spec.rb +34 -0
  203. data/spec/mongo/grid/file/chunk_spec.rb +226 -0
  204. data/spec/mongo/grid/file/metadata_spec.rb +69 -0
  205. data/spec/mongo/grid/file_spec.rb +138 -0
  206. data/spec/mongo/grid/fs_spec.rb +129 -0
  207. data/spec/mongo/index/view_spec.rb +226 -0
  208. data/spec/mongo/loggable_spec.rb +62 -0
  209. data/spec/mongo/logger_spec.rb +97 -0
  210. data/spec/mongo/operation/aggregate/result_spec.rb +80 -0
  211. data/spec/mongo/operation/aggregate_spec.rb +135 -0
  212. data/spec/mongo/operation/command_spec.rb +106 -0
  213. data/spec/mongo/operation/kill_cursors_spec.rb +66 -0
  214. data/spec/mongo/operation/limited_spec.rb +50 -0
  215. data/spec/mongo/operation/map_reduce_spec.rb +143 -0
  216. data/spec/mongo/operation/read/collections_info_spec.rb +40 -0
  217. data/spec/mongo/operation/read/get_more_spec.rb +81 -0
  218. data/spec/mongo/operation/read/indexes_spec.rb +31 -0
  219. data/spec/mongo/operation/read/query_spec.rb +84 -0
  220. data/spec/mongo/operation/result_spec.rb +275 -0
  221. data/spec/mongo/operation/specifiable_spec.rb +53 -0
  222. data/spec/mongo/operation/write/bulk_delete_spec.rb +473 -0
  223. data/spec/mongo/operation/write/bulk_insert_spec.rb +466 -0
  224. data/spec/mongo/operation/write/bulk_update_spec.rb +524 -0
  225. data/spec/mongo/operation/write/command/delete_spec.rb +116 -0
  226. data/spec/mongo/operation/write/command/insert_spec.rb +117 -0
  227. data/spec/mongo/operation/write/command/update_spec.rb +123 -0
  228. data/spec/mongo/operation/write/create_user_spec.rb +44 -0
  229. data/spec/mongo/operation/write/delete_spec.rb +178 -0
  230. data/spec/mongo/operation/write/drop_index_spec.rb +51 -0
  231. data/spec/mongo/operation/write/ensure_index_spec.rb +81 -0
  232. data/spec/mongo/operation/write/insert_spec.rb +231 -0
  233. data/spec/mongo/operation/write/remove_user_spec.rb +46 -0
  234. data/spec/mongo/operation/write/response_spec.rb +85 -0
  235. data/spec/mongo/operation/write/update_spec.rb +177 -0
  236. data/spec/mongo/protocol/delete_spec.rb +167 -0
  237. data/spec/mongo/protocol/get_more_spec.rb +146 -0
  238. data/spec/mongo/protocol/insert_spec.rb +161 -0
  239. data/spec/mongo/protocol/kill_cursors_spec.rb +101 -0
  240. data/spec/mongo/protocol/query_spec.rb +285 -0
  241. data/spec/mongo/protocol/reply_spec.rb +157 -0
  242. data/spec/mongo/protocol/update_spec.rb +186 -0
  243. data/spec/mongo/server/connection_pool/queue_spec.rb +170 -0
  244. data/spec/mongo/server/connection_pool_spec.rb +120 -0
  245. data/spec/mongo/server/connection_spec.rb +289 -0
  246. data/spec/mongo/server/description/features_spec.rb +138 -0
  247. data/spec/mongo/server/description/inspector/primary_elected_spec.rb +94 -0
  248. data/spec/mongo/server/description/inspector/server_added_spec.rb +92 -0
  249. data/spec/mongo/server/description/inspector/server_removed_spec.rb +95 -0
  250. data/spec/mongo/server/description_spec.rb +510 -0
  251. data/spec/mongo/server/monitor_spec.rb +130 -0
  252. data/spec/mongo/server_discovery_and_monitoring_spec.rb +103 -0
  253. data/spec/mongo/server_selection_rtt_spec.rb +104 -0
  254. data/spec/mongo/server_selection_spec.rb +89 -0
  255. data/spec/mongo/server_selector/nearest_spec.rb +250 -0
  256. data/spec/mongo/server_selector/primary_preferred_spec.rb +290 -0
  257. data/spec/mongo/server_selector/primary_spec.rb +114 -0
  258. data/spec/mongo/server_selector/secondary_preferred_spec.rb +252 -0
  259. data/spec/mongo/server_selector/secondary_spec.rb +196 -0
  260. data/spec/mongo/server_selector_spec.rb +101 -0
  261. data/spec/mongo/server_spec.rb +131 -0
  262. data/spec/mongo/uri_spec.rb +517 -0
  263. data/spec/mongo/write_concern/acknowledged_spec.rb +44 -0
  264. data/spec/mongo/write_concern/unacknowledged_spec.rb +15 -0
  265. data/spec/mongo_orchestration_spec.rb +70 -0
  266. data/spec/spec_helper.rb +148 -0
  267. data/spec/support/authorization.rb +245 -0
  268. data/spec/support/helpers.rb +140 -0
  269. data/spec/support/matchers.rb +37 -0
  270. data/spec/support/mongo_orchestration.rb +61 -0
  271. data/spec/support/mongo_orchestration/requestable.rb +109 -0
  272. data/spec/support/mongo_orchestration/standalone.rb +57 -0
  273. data/spec/support/sdam/rs/discover_arbiters.yml +41 -0
  274. data/spec/support/sdam/rs/discover_passives.yml +41 -0
  275. data/spec/support/sdam/rs/discover_primary.yml +40 -0
  276. data/spec/support/sdam/rs/discover_secondary.yml +41 -0
  277. data/spec/support/sdam/rs/discovery.yml +195 -0
  278. data/spec/support/sdam/rs/ghost_discovered.yml +39 -0
  279. data/spec/support/sdam/rs/hosts_differ_from_seeds.yml +34 -0
  280. data/spec/support/sdam/rs/member_reconfig.yml +68 -0
  281. data/spec/support/sdam/rs/member_standalone.yml +60 -0
  282. data/spec/support/sdam/rs/new_primary.yml +74 -0
  283. data/spec/support/sdam/rs/new_primary_wrong_set_name.yml +71 -0
  284. data/spec/support/sdam/rs/non_rs_member.yml +31 -0
  285. data/spec/support/sdam/rs/normalize_case.yml +49 -0
  286. data/spec/support/sdam/rs/primary_becomes_standalone.yml +52 -0
  287. data/spec/support/sdam/rs/primary_changes_set_name.yml +57 -0
  288. data/spec/support/sdam/rs/primary_disconnect.yml +56 -0
  289. data/spec/support/sdam/rs/primary_wrong_set_name.yml +27 -0
  290. data/spec/support/sdam/rs/response_from_removed.yml +63 -0
  291. data/spec/support/sdam/rs/rsother_discovered.yml +41 -0
  292. data/spec/support/sdam/rs/sec_not_auth.yml +49 -0
  293. data/spec/support/sdam/rs/secondary_wrong_set_name.yml +28 -0
  294. data/spec/support/sdam/rs/secondary_wrong_set_name_with_primary.yml +69 -0
  295. data/spec/support/sdam/rs/unexpected_mongos.yml +26 -0
  296. data/spec/support/sdam/rs/wrong_set_name.yml +35 -0
  297. data/spec/support/sdam/sharded/multiple_mongoses.yml +46 -0
  298. data/spec/support/sdam/sharded/non_mongos_removed.yml +41 -0
  299. data/spec/support/sdam/sharded/normalize_uri_case.yml +32 -0
  300. data/spec/support/sdam/single/direct_connection_external_ip.yml +34 -0
  301. data/spec/support/sdam/single/direct_connection_mongos.yml +33 -0
  302. data/spec/support/sdam/single/direct_connection_rsarbiter.yml +35 -0
  303. data/spec/support/sdam/single/direct_connection_rsprimary.yml +34 -0
  304. data/spec/support/sdam/single/direct_connection_rssecondary.yml +35 -0
  305. data/spec/support/sdam/single/direct_connection_slave.yml +32 -0
  306. data/spec/support/sdam/single/direct_connection_standalone.yml +32 -0
  307. data/spec/support/sdam/single/not_ok_response.yml +39 -0
  308. data/spec/support/sdam/single/standalone_removed.yml +32 -0
  309. data/spec/support/sdam/single/unavailable_seed.yml +28 -0
  310. data/spec/support/server_discovery_and_monitoring.rb +167 -0
  311. data/spec/support/server_selection.rb +140 -0
  312. data/spec/support/server_selection/rtt/first_value.yml +4 -0
  313. data/spec/support/server_selection/rtt/first_value_zero.yml +4 -0
  314. data/spec/support/server_selection/rtt/value_test_1.yml +4 -0
  315. data/spec/support/server_selection/rtt/value_test_2.yml +4 -0
  316. data/spec/support/server_selection/rtt/value_test_3.yml +4 -0
  317. data/spec/support/server_selection/rtt/value_test_4.yml +4 -0
  318. data/spec/support/server_selection/rtt/value_test_5.yml +4 -0
  319. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Nearest.yml +32 -0
  320. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Nearest_non_matching.yml +27 -0
  321. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Primary.yml +23 -0
  322. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/PrimaryPreferred.yml +32 -0
  323. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/PrimaryPreferred_non_matching.yml +27 -0
  324. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Secondary.yml +32 -0
  325. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/SecondaryPreferred.yml +32 -0
  326. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/SecondaryPreferred_non_matching.yml +27 -0
  327. data/spec/support/server_selection/selection/ReplicaSetNoPrimary/read/Secondary_non_matching.yml +27 -0
  328. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Nearest.yml +41 -0
  329. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Nearest_non_matching.yml +34 -0
  330. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/Primary.yml +33 -0
  331. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/PrimaryPreferred.yml +39 -0
  332. data/spec/support/server_selection/selection/ReplicaSetWithPrimary/read/PrimaryPreferred_non_matching.yml +36 -0
  333. data/spec/support/server_selection/selection/Sharded/read/SecondaryPreferred.yml +32 -0
  334. data/spec/support/server_selection/selection/Single/read/SecondaryPreferred.yml +23 -0
  335. data/spec/support/server_selection/selection/Unknown/read/SecondaryPreferred.yml +13 -0
  336. data/spec/support/server_selection_rtt.rb +41 -0
  337. data/spec/support/shared/bulk_write.rb +498 -0
  338. data/spec/support/shared/cursor.rb +38 -0
  339. data/spec/support/shared/operation.rb +77 -0
  340. data/spec/support/shared/protocol.rb +31 -0
  341. data/spec/support/shared/server_selector.rb +111 -0
  342. data/spec/support/shared/socket.rb +82 -0
  343. data/spec/support/travis.rb +14 -0
  344. metadata +523 -189
  345. metadata.gz.sig +0 -0
  346. data/VERSION +0 -1
  347. data/lib/mongo/bulk_write_collection_view.rb +0 -387
  348. data/lib/mongo/collection_writer.rb +0 -364
  349. data/lib/mongo/connection/node.rb +0 -249
  350. data/lib/mongo/connection/pool.rb +0 -340
  351. data/lib/mongo/connection/pool_manager.rb +0 -320
  352. data/lib/mongo/connection/sharding_pool_manager.rb +0 -67
  353. data/lib/mongo/connection/socket/ssl_socket.rb +0 -95
  354. data/lib/mongo/connection/socket/tcp_socket.rb +0 -87
  355. data/lib/mongo/connection/socket/unix_socket.rb +0 -39
  356. data/lib/mongo/db.rb +0 -808
  357. data/lib/mongo/exception.rb +0 -145
  358. data/lib/mongo/functional/authentication.rb +0 -455
  359. data/lib/mongo/functional/logging.rb +0 -85
  360. data/lib/mongo/functional/read_preference.rb +0 -183
  361. data/lib/mongo/functional/scram.rb +0 -556
  362. data/lib/mongo/functional/uri_parser.rb +0 -409
  363. data/lib/mongo/functional/write_concern.rb +0 -66
  364. data/lib/mongo/gridfs/grid.rb +0 -112
  365. data/lib/mongo/gridfs/grid_ext.rb +0 -53
  366. data/lib/mongo/gridfs/grid_file_system.rb +0 -163
  367. data/lib/mongo/gridfs/grid_io.rb +0 -484
  368. data/lib/mongo/legacy.rb +0 -140
  369. data/lib/mongo/mongo_client.rb +0 -697
  370. data/lib/mongo/mongo_replica_set_client.rb +0 -535
  371. data/lib/mongo/mongo_sharded_client.rb +0 -159
  372. data/lib/mongo/networking.rb +0 -372
  373. data/lib/mongo/utils/conversions.rb +0 -110
  374. data/lib/mongo/utils/core_ext.rb +0 -70
  375. data/lib/mongo/utils/server_version.rb +0 -69
  376. data/lib/mongo/utils/support.rb +0 -80
  377. data/test/functional/authentication_test.rb +0 -39
  378. data/test/functional/bulk_api_stress_test.rb +0 -133
  379. data/test/functional/bulk_write_collection_view_test.rb +0 -1198
  380. data/test/functional/client_test.rb +0 -627
  381. data/test/functional/collection_test.rb +0 -2175
  382. data/test/functional/collection_writer_test.rb +0 -83
  383. data/test/functional/conversions_test.rb +0 -163
  384. data/test/functional/cursor_fail_test.rb +0 -57
  385. data/test/functional/cursor_message_test.rb +0 -56
  386. data/test/functional/cursor_test.rb +0 -683
  387. data/test/functional/db_api_test.rb +0 -835
  388. data/test/functional/db_test.rb +0 -348
  389. data/test/functional/grid_file_system_test.rb +0 -285
  390. data/test/functional/grid_io_test.rb +0 -252
  391. data/test/functional/grid_test.rb +0 -273
  392. data/test/functional/pool_test.rb +0 -136
  393. data/test/functional/safe_test.rb +0 -98
  394. data/test/functional/support_test.rb +0 -62
  395. data/test/functional/timeout_test.rb +0 -60
  396. data/test/functional/uri_test.rb +0 -446
  397. data/test/functional/write_concern_test.rb +0 -118
  398. data/test/helpers/general.rb +0 -50
  399. data/test/helpers/test_unit.rb +0 -476
  400. data/test/replica_set/authentication_test.rb +0 -37
  401. data/test/replica_set/basic_test.rb +0 -189
  402. data/test/replica_set/client_test.rb +0 -393
  403. data/test/replica_set/connection_test.rb +0 -138
  404. data/test/replica_set/count_test.rb +0 -66
  405. data/test/replica_set/cursor_test.rb +0 -220
  406. data/test/replica_set/insert_test.rb +0 -157
  407. data/test/replica_set/max_values_test.rb +0 -151
  408. data/test/replica_set/pinning_test.rb +0 -105
  409. data/test/replica_set/query_test.rb +0 -73
  410. data/test/replica_set/read_preference_test.rb +0 -219
  411. data/test/replica_set/refresh_test.rb +0 -211
  412. data/test/replica_set/replication_ack_test.rb +0 -95
  413. data/test/sharded_cluster/basic_test.rb +0 -203
  414. data/test/shared/authentication/basic_auth_shared.rb +0 -260
  415. data/test/shared/authentication/bulk_api_auth_shared.rb +0 -249
  416. data/test/shared/authentication/gssapi_shared.rb +0 -176
  417. data/test/shared/authentication/sasl_plain_shared.rb +0 -96
  418. data/test/shared/authentication/scram_shared.rb +0 -92
  419. data/test/shared/ssl_shared.rb +0 -235
  420. data/test/test_helper.rb +0 -61
  421. data/test/threading/basic_test.rb +0 -120
  422. data/test/tools/mongo_config.rb +0 -708
  423. data/test/tools/mongo_config_test.rb +0 -160
  424. data/test/unit/client_test.rb +0 -381
  425. data/test/unit/collection_test.rb +0 -166
  426. data/test/unit/connection_test.rb +0 -335
  427. data/test/unit/cursor_test.rb +0 -307
  428. data/test/unit/db_test.rb +0 -136
  429. data/test/unit/grid_test.rb +0 -76
  430. data/test/unit/mongo_sharded_client_test.rb +0 -48
  431. data/test/unit/node_test.rb +0 -93
  432. data/test/unit/pool_manager_test.rb +0 -111
  433. data/test/unit/read_pref_test.rb +0 -406
  434. data/test/unit/read_test.rb +0 -159
  435. data/test/unit/safe_test.rb +0 -158
  436. data/test/unit/sharding_pool_manager_test.rb +0 -84
  437. data/test/unit/write_concern_test.rb +0 -175
@@ -1,85 +0,0 @@
1
- # Copyright (C) 2009-2013 MongoDB, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- module Mongo
16
- module Logging
17
-
18
- module Instrumenter
19
- def self.instrument(name, payload = {})
20
- yield
21
- end
22
- end
23
-
24
- @instrumenter = Instrumenter
25
-
26
- def write_logging_startup_message
27
- log(:debug, "Logging level is currently :debug which could negatively impact " +
28
- "client-side performance. You should set your logging level no lower than " +
29
- ":info in production.")
30
- end
31
-
32
- # Log a message with the given level.
33
- def log(level, msg)
34
- return unless @logger
35
- case level
36
- when :fatal then
37
- @logger.fatal "MONGODB [FATAL] #{msg}"
38
- when :error then
39
- @logger.error "MONGODB [ERROR] #{msg}"
40
- when :warn then
41
- @logger.warn "MONGODB [WARNING] #{msg}"
42
- when :info then
43
- @logger.info "MONGODB [INFO] #{msg}"
44
- when :debug then
45
- @logger.debug "MONGODB [DEBUG] #{msg}"
46
- else
47
- @logger.debug "MONGODB [DEBUG] #{msg}"
48
- end
49
- end
50
-
51
- # Execute the block and log the operation described by name and payload.
52
- def instrument(name, payload = {})
53
- start_time = Time.now
54
- res = Logging.instrumenter.instrument(name, payload) do
55
- yield
56
- end
57
- duration = Time.now - start_time
58
- log_operation(name, payload, duration)
59
- res
60
- end
61
-
62
- def self.instrumenter
63
- @instrumenter
64
- end
65
-
66
- def self.instrumenter=(instrumenter)
67
- @instrumenter = instrumenter
68
- end
69
-
70
- protected
71
-
72
- def log_operation(name, payload, duration)
73
- @logger && @logger.debug do
74
- msg = "MONGODB "
75
- msg << "(%.1fms) " % (duration * 1000)
76
- msg << "#{payload[:database]}['#{payload[:collection]}'].#{name}("
77
- msg << payload.values_at(:selector, :document, :documents, :fields ).compact.map(&:inspect).join(', ') + ")"
78
- msg << ".skip(#{payload[:skip]})" if payload[:skip]
79
- msg << ".limit(#{payload[:limit]})" if payload[:limit]
80
- msg << ".sort(#{payload[:order]})" if payload[:order]
81
- msg
82
- end
83
- end
84
- end
85
- end
@@ -1,183 +0,0 @@
1
- # Copyright (C) 2009-2013 MongoDB, Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- module Mongo
16
- module ReadPreference
17
- READ_PREFERENCES = [
18
- :primary,
19
- :primary_preferred,
20
- :secondary,
21
- :secondary_preferred,
22
- :nearest
23
- ]
24
-
25
- MONGOS_MODES = {
26
- :primary => 'primary',
27
- :primary_preferred => 'primaryPreferred',
28
- :secondary => 'secondary',
29
- :secondary_preferred => 'secondaryPreferred',
30
- :nearest => 'nearest'
31
- }
32
-
33
- # Commands that may be sent to replica-set secondaries, depending on
34
- # read preference and tags. All other commands are always run on the primary.
35
- SECONDARY_OK_COMMANDS = [
36
- 'group',
37
- 'aggregate',
38
- 'collstats',
39
- 'dbstats',
40
- 'count',
41
- 'distinct',
42
- 'geonear',
43
- 'geosearch',
44
- 'geowalk',
45
- 'mapreduce',
46
- 'replsetgetstatus',
47
- 'ismaster',
48
- 'parallelcollectionscan',
49
- 'text'
50
- ]
51
-
52
- def self.mongos(mode, tag_sets)
53
- if mode != :secondary_preferred || !tag_sets.empty?
54
- mongos_read_preference = BSON::OrderedHash[:mode => MONGOS_MODES[mode]]
55
- mongos_read_preference[:tags] = tag_sets if !tag_sets.empty?
56
- end
57
- mongos_read_preference
58
- end
59
-
60
- def self.validate(value)
61
- if READ_PREFERENCES.include?(value)
62
- return true
63
- else
64
- raise MongoArgumentError, "#{value} is not a valid read preference. " +
65
- "Please specify one of the following read preferences as a symbol: #{READ_PREFERENCES}"
66
- end
67
- end
68
-
69
- # Returns true if it's ok to run the command on a secondary
70
- def self.secondary_ok?(selector)
71
- command = selector.keys.first.to_s.downcase
72
-
73
- if command == 'mapreduce'
74
- out = selector.select { |k, v| k.to_s.downcase == 'out' }.first.last
75
- # the server only looks at the first key in the out object
76
- return out.respond_to?(:keys) && out.keys.first.to_s.downcase == 'inline'
77
- elsif command == 'aggregate'
78
- pipeline = selector['pipeline'] || selector[:pipeline]
79
- return pipeline.none? { |op| op.key?('$out') || op.key?(:$out) }
80
- end
81
- SECONDARY_OK_COMMANDS.member?(command)
82
- end
83
-
84
- # Returns true if the command should be rerouted to the primary.
85
- def self.reroute_cmd_primary?(read_pref, selector)
86
- return false if read_pref == :primary
87
- !secondary_ok?(selector)
88
- end
89
-
90
- # Given a command and read preference, possibly reroute to primary.
91
- def self.cmd_read_pref(read_pref, selector)
92
- ReadPreference::validate(read_pref)
93
- if reroute_cmd_primary?(read_pref, selector)
94
- warn "Database command '#{selector.keys.first}' rerouted to primary node"
95
- read_pref = :primary
96
- end
97
- read_pref
98
- end
99
-
100
- def read_preference
101
- {
102
- :mode => @read,
103
- :tags => @tag_sets,
104
- :latency => @acceptable_latency
105
- }
106
- end
107
-
108
- def read_pool(read_preference_override={})
109
- return primary_pool if mongos?
110
-
111
- read_pref = read_preference.merge(read_preference_override)
112
-
113
- if pinned_pool && pinned_pool[:read_preference] == read_pref
114
- pool = pinned_pool[:pool]
115
- else
116
- unpin_pool
117
- pool = select_pool(read_pref)
118
- end
119
-
120
- unless pool
121
- raise ConnectionFailure, "No replica set member available for query " +
122
- "with read preference matching mode #{read_pref[:mode]} and tags " +
123
- "matching #{read_pref[:tags]}."
124
- end
125
-
126
- pool
127
- end
128
-
129
- def select_pool(read_pref)
130
- if read_pref[:mode] == :primary && !read_pref[:tags].empty?
131
- raise MongoArgumentError, "Read preference :primary cannot be combined with tags"
132
- end
133
-
134
- case read_pref[:mode]
135
- when :primary
136
- primary_pool
137
- when :primary_preferred
138
- primary_pool || select_secondary_pool(secondary_pools, read_pref)
139
- when :secondary
140
- select_secondary_pool(secondary_pools, read_pref)
141
- when :secondary_preferred
142
- select_secondary_pool(secondary_pools, read_pref) || primary_pool
143
- when :nearest
144
- select_near_pool(pools, read_pref)
145
- end
146
- end
147
-
148
- def select_secondary_pool(candidates, read_pref)
149
- matching_pools = match_tag_sets(secondary_pools, read_pref[:tags])
150
- select_near_pools(matching_pools, read_pref).first
151
- end
152
-
153
- def select_near_pool(candidates, read_pref)
154
- matching_pools = match_tag_sets(candidates, read_pref[:tags])
155
- select_near_pools(matching_pools, read_pref).first
156
- end
157
-
158
- private
159
-
160
- def select_near_pools(candidates, read_pref)
161
- return candidates if candidates.empty?
162
- latency = read_pref[:latency]
163
- nearest_pool = candidates.min_by(&:ping_time)
164
- max_latency = nearest_pool.ping_time + latency
165
- near_pools = candidates.select { |candidate| candidate.ping_time <= max_latency }
166
- near_pools.shuffle!
167
- end
168
-
169
- def match_tag_sets(candidates, tag_sets = [])
170
- return candidates if tag_sets.empty?
171
- matches = []
172
- tag_sets.find do |tag_set|
173
- matches = candidates.select do |candidate|
174
- tag_set.none? do |k,v|
175
- candidate.tags[k.to_s] != v
176
- end
177
- end
178
- !matches.empty?
179
- end
180
- matches
181
- end
182
- end
183
- end
@@ -1,556 +0,0 @@
1
- # Copyright (C) 2014 MongoDB Inc.
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # http://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
- require 'base64'
16
- require 'securerandom'
17
- require 'openssl'
18
- require 'digest/md5'
19
-
20
- module Mongo
21
- module Authentication
22
-
23
- # Defines behaviour around a single SCRAM-SHA-1 conversation between the
24
- # client and server.
25
- #
26
- # @since 1.12.0
27
- class SCRAM
28
-
29
- # The client key string.
30
- #
31
- # @since 1.12.0
32
- CLIENT_KEY = 'Client Key'.freeze
33
-
34
- # The digest to use for encryption.
35
- #
36
- # @since 1.12.0
37
- DIGEST = OpenSSL::Digest::SHA1.new.freeze
38
-
39
- # The key for the done field in the responses.
40
- #
41
- # @since 1.12.0
42
- DONE = 'done'.freeze
43
-
44
- # The conversation id field.
45
- #
46
- # @since 1.12.0
47
- ID = 'conversationId'.freeze
48
-
49
- # The iterations key in the responses.
50
- #
51
- # @since 1.12.0
52
- ITERATIONS = /i=(\d+)/.freeze
53
-
54
- # The payload field.
55
- #
56
- # @since 1.12.0
57
- PAYLOAD = 'payload'.freeze
58
-
59
- # The rnonce key in the responses.
60
- #
61
- # @since 1.12.0
62
- RNONCE = /r=([^,]*)/.freeze
63
-
64
- # The salt key in the responses.
65
- #
66
- # @since 1.12.0
67
- SALT = /s=([^,]*)/.freeze
68
-
69
- # The server key string.
70
- #
71
- # @since 1.12.0
72
- SERVER_KEY = 'Server Key'.freeze
73
-
74
- # The server signature verifier in the response.
75
- #
76
- # @since 1.12.0
77
- VERIFIER = /v=([^,]*)/.freeze
78
-
79
- # @return [ String ] nonce The initial user nonce.
80
- attr_reader :nonce
81
-
82
- # @return [ BSON::OrderedHash ] reply The current reply in the conversation.
83
- attr_reader :reply
84
-
85
- # @return [ Hash ] auth The authentication details.
86
- attr_reader :auth
87
-
88
- # @return [ String ] hashed_password The user's hashed password
89
- attr_reader :hashed_password
90
-
91
- # Continue the SCRAM conversation. This sends the client final message
92
- # to the server after setting the reply from the previous server
93
- # communication.
94
- #
95
- # @example Continue the conversation.
96
- # conversation.continue(reply)
97
- #
98
- # @param [ BSON::OrderedHash ] reply The reply of the previous
99
- # message.
100
- #
101
- # @return [ BSON::OrderedHash ] The next message to send.
102
- #
103
- # @since 1.12.0
104
- def continue(reply)
105
- validate_first_message!(reply)
106
- command = BSON::OrderedHash.new
107
- command['saslContinue'] = 1
108
- command[PAYLOAD] = client_final_message
109
- command[ID] = id
110
- command
111
- end
112
-
113
- # Continue the SCRAM conversation for copydb. This sends the client final message
114
- # to the server after setting the reply from the previous server
115
- # communication.
116
- #
117
- # @example Continue the conversation when copying a database.
118
- # conversation.copy_db_continue(reply)
119
- #
120
- # @param [ BSON::OrderedHash ] reply The reply of the previous
121
- # message.
122
- #
123
- # @return [ BSON::OrderedHash ] The next message to send.
124
- #
125
- # @since 1.12.0
126
- def copy_db_continue(reply)
127
- validate_first_message!(reply)
128
- command = BSON::OrderedHash.new
129
- command['copydb'] = 1
130
- command['fromhost'] = @copy_db[:from_host]
131
- command['fromdb'] = @copy_db[:from_db]
132
- command['todb'] = @copy_db[:to_db]
133
- command[PAYLOAD] = client_final_message
134
- command[ID] = id
135
- command
136
- end
137
-
138
- # Finalize the SCRAM conversation. This is meant to be iterated until
139
- # the provided reply indicates the conversation is finished.
140
- #
141
- # @example Finalize the conversation.
142
- # conversation.finalize(reply)
143
- #
144
- # @param [ BSON::OrderedHash ] reply The reply of the previous
145
- # message.
146
- #
147
- # @return [ BSON::OrderedHash ] The next message to send.
148
- #
149
- # @since 1.12.0
150
- def finalize(reply)
151
- validate_final_message!(reply)
152
- command = BSON::OrderedHash.new
153
- command['saslContinue'] = 1
154
- command[PAYLOAD] = client_empty_message
155
- command[ID] = id
156
- command
157
- end
158
-
159
- # Start the SCRAM conversation. This returns the first message that
160
- # needs to be send to the server.
161
- #
162
- # @example Start the conversation.
163
- # conversation.start
164
- #
165
- # @return [ BSON::OrderedHash ] The first SCRAM conversation message.
166
- #
167
- # @since 1.12.0
168
- def start
169
- command = BSON::OrderedHash.new
170
- command['saslStart'] = 1
171
- command['autoAuthorize'] = 1
172
- command[PAYLOAD] = client_first_message
173
- command['mechanism'] = 'SCRAM-SHA-1'
174
- command
175
- end
176
-
177
- # Start the SCRAM conversation for copying a database.
178
- # This returns the first message that needs to be sent to the server.
179
- #
180
- # @example Start the copydb conversation.
181
- # conversation.copy_db_start
182
- #
183
- # @return [ BSON::OrderedHash ] The first SCRAM copy_db conversation message.
184
- #
185
- # @since 1.12.0
186
- def copy_db_start
187
- command = BSON::OrderedHash.new
188
- command['copydbsaslstart'] = 1
189
- command['autoAuthorize'] = 1
190
- command['fromhost'] = @copy_db[:from_host]
191
- command['fromdb'] = @copy_db[:from_db]
192
- command[PAYLOAD] = client_first_message
193
- command['mechanism'] = 'SCRAM-SHA-1'
194
- command
195
- end
196
-
197
- # Get the id of the conversation.
198
- #
199
- # @example Get the id of the conversation.
200
- # conversation.id
201
- #
202
- # @return [ Integer ] The conversation id.
203
- #
204
- # @since 1.12.0
205
- def id
206
- reply[ID]
207
- end
208
-
209
- # Create the new conversation.
210
- #
211
- # @example Create the new conversation.
212
- # Conversation.new(auth, password)
213
- #
214
- # @since 1.12.0
215
- def initialize(auth, hashed_password, opts={})
216
- @auth = auth
217
- @hashed_password = hashed_password
218
- @nonce = SecureRandom.base64
219
- @copy_db = opts[:copy_db] if opts[:copy_db]
220
- end
221
-
222
- private
223
-
224
- # Auth message algorithm implementation.
225
- #
226
- # @api private
227
- #
228
- # @see http://tools.ietf.org/html/rfc5802#section-3
229
- #
230
- # @since 1.12.0
231
- def auth_message
232
- @auth_message ||= "#{first_bare},#{payload_data},#{without_proof}"
233
- end
234
-
235
- # Get the empty client message.
236
- #
237
- # @api private
238
- #
239
- # @since 1.12.0
240
- def client_empty_message
241
- BSON::Binary.new('')
242
- end
243
-
244
- # Get the final client message.
245
- #
246
- # @api private
247
- #
248
- # @see http://tools.ietf.org/html/rfc5802#section-3
249
- #
250
- # @since 1.12.0
251
- def client_final_message
252
- BSON::Binary.new("#{without_proof},p=#{client_final}")
253
- end
254
-
255
- # Get the client first message
256
- #
257
- # @api private
258
- #
259
- # @see http://tools.ietf.org/html/rfc5802#section-3
260
- #
261
- # @since 1.12.0
262
- def client_first_message
263
- BSON::Binary.new("n,,#{first_bare}")
264
- end
265
-
266
- # Client final implementation.
267
- #
268
- # @api private
269
- #
270
- # @see http://tools.ietf.org/html/rfc5802#section-7
271
- #
272
- # @since 1.12.0
273
- def client_final
274
- @client_final ||= client_proof(client_key, client_signature(stored_key(client_key), auth_message))
275
- end
276
-
277
- # Client key algorithm implementation.
278
- #
279
- # @api private
280
- #
281
- # @see http://tools.ietf.org/html/rfc5802#section-3
282
- #
283
- # @since 1.12.0
284
- def client_key
285
- @client_key ||= hmac(salted_password, CLIENT_KEY)
286
- end
287
-
288
- if Base64.respond_to?(:strict_encode64)
289
-
290
- # Client proof algorithm implementation.
291
- #
292
- # @api private
293
- #
294
- # @see http://tools.ietf.org/html/rfc5802#section-3
295
- #
296
- # @since 1.12.0
297
- def client_proof(key, signature)
298
- @client_proof ||= Base64.strict_encode64(xor(key, signature))
299
- end
300
- else
301
-
302
- # Client proof algorithm implementation.
303
- #
304
- # @api private
305
- #
306
- # @see http://tools.ietf.org/html/rfc5802#section-3
307
- #
308
- # @since 1.12.0
309
- def client_proof(key, signature)
310
- @client_proof ||= Base64.encode64(xor(key, signature)).gsub("\n",'')
311
- end
312
- end
313
-
314
- # Client signature algorithm implementation.
315
- #
316
- # @api private
317
- #
318
- # @see http://tools.ietf.org/html/rfc5802#section-3
319
- #
320
- # @since 1.12.0
321
- def client_signature(key, message)
322
- @client_signature ||= hmac(key, message)
323
- end
324
-
325
- if Base64.respond_to?(:strict_decode64)
326
-
327
- # Get the base 64 decoded salt.
328
- #
329
- # @api private
330
- #
331
- # @since 1.12.0
332
- def decoded_salt
333
- @decoded_salt ||= Base64.strict_decode64(salt)
334
- end
335
- else
336
-
337
- # Get the base 64 decoded salt.
338
- #
339
- # @api private
340
- #
341
- # @since 1.12.0
342
- def decoded_salt
343
- @decoded_salt ||= Base64.decode64(salt)
344
- end
345
- end
346
-
347
- # First bare implementation.
348
- #
349
- # @api private
350
- #
351
- # @see http://tools.ietf.org/html/rfc5802#section-7
352
- #
353
- # @since 1.12.0
354
- def first_bare
355
- @first_bare ||= "n=#{auth[:username].gsub('=','=3D').gsub(',','=2C')},r=#{nonce}"
356
- end
357
-
358
- # H algorithm implementation.
359
- #
360
- # @api private
361
- #
362
- # @see http://tools.ietf.org/html/rfc5802#section-2.2
363
- #
364
- # @since 1.12.0
365
- def h(string)
366
- DIGEST.digest(string)
367
- end
368
-
369
- if defined?(OpenSSL::PKCS5)
370
-
371
- # HI algorithm implementation.
372
- #
373
- # @api private
374
- #
375
- # @see http://tools.ietf.org/html/rfc5802#section-2.2
376
- #
377
- # @since 1.12.0
378
- def hi(data)
379
- OpenSSL::PKCS5.pbkdf2_hmac_sha1(data, decoded_salt, iterations, DIGEST.size)
380
- end
381
- else
382
-
383
- # HI algorithm implementation.
384
- #
385
- # @api private
386
- #
387
- # @see http://tools.ietf.org/html/rfc5802#section-2.2
388
- #
389
- # @since 1.12.0
390
- def hi(data)
391
- u = hmac(data, decoded_salt + [1].pack("N"))
392
- v = u
393
- 2.upto(iterations) do |i|
394
- u = hmac(data, u)
395
- v = xor(v, u)
396
- end
397
- v
398
- end
399
- end
400
-
401
- # HMAC algorithm implementation.
402
- #
403
- # @api private
404
- #
405
- # @see http://tools.ietf.org/html/rfc5802#section-2.2
406
- #
407
- # @since 1.12.0
408
- def hmac(data, key)
409
- OpenSSL::HMAC.digest(DIGEST, data, key)
410
- end
411
-
412
- # Get the iterations from the server response.
413
- #
414
- # @api private
415
- #
416
- # @since 1.12.0
417
- def iterations
418
- @iterations ||= payload_data.match(ITERATIONS)[1].to_i
419
- end
420
-
421
- # Get the data from the returned payload.
422
- #
423
- # @api private
424
- #
425
- # @since 1.12.0
426
- def payload_data
427
- reply[PAYLOAD].to_s
428
- end
429
-
430
- # Get the server nonce from the payload.
431
- #
432
- # @api private
433
- #
434
- # @since 1.12.0
435
- def rnonce
436
- @rnonce ||= payload_data.match(RNONCE)[1]
437
- end
438
-
439
- # Gets the salt from the server response.
440
- #
441
- # @api private
442
- #
443
- # @since 1.12.0
444
- def salt
445
- @salt ||= payload_data.match(SALT)[1]
446
- end
447
-
448
- # Salted password algorithm implementation.
449
- #
450
- # @api private
451
- #
452
- # @see http://tools.ietf.org/html/rfc5802#section-3
453
- #
454
- # @since 1.12.0
455
- def salted_password
456
- @salted_password ||= hi(hashed_password)
457
- end
458
-
459
- # Server key algorithm implementation.
460
- #
461
- # @api private
462
- #
463
- # @see http://tools.ietf.org/html/rfc5802#section-3
464
- #
465
- # @since 1.12.0
466
- def server_key
467
- @server_key ||= hmac(salted_password, SERVER_KEY)
468
- end
469
-
470
- if Base64.respond_to?(:strict_encode64)
471
-
472
- # Server signature algorithm implementation.
473
- #
474
- # @api private
475
- #
476
- # @see http://tools.ietf.org/html/rfc5802#section-3
477
- #
478
- # @since 1.12.0
479
- def server_signature
480
- @server_signature ||= Base64.strict_encode64(hmac(server_key, auth_message))
481
- end
482
- else
483
-
484
- # Server signature algorithm implementation.
485
- #
486
- # @api private
487
- #
488
- # @see http://tools.ietf.org/html/rfc5802#section-3
489
- #
490
- # @since 1.12.0
491
- def server_signature
492
- @server_signature ||= Base64.encode64(hmac(server_key, auth_message)).gsub("\n",'')
493
- end
494
- end
495
-
496
- # Stored key algorithm implementation.
497
- #
498
- # @api private
499
- #
500
- # @see http://tools.ietf.org/html/rfc5802#section-3
501
- #
502
- # @since 1.12.0
503
- def stored_key(key)
504
- h(key)
505
- end
506
-
507
- # Get the verifier token from the server response.
508
- #
509
- # @api private
510
- #
511
- # @since 1.12.0
512
- def verifier
513
- @verifier ||= payload_data.match(VERIFIER)[1]
514
- end
515
-
516
- # Get the without proof message.
517
- #
518
- # @api private
519
- #
520
- # @see http://tools.ietf.org/html/rfc5802#section-7
521
- #
522
- # @since 1.12.0
523
- def without_proof
524
- @without_proof ||= "c=biws,r=#{rnonce}"
525
- end
526
-
527
- # XOR operation for two strings.
528
- #
529
- # @api private
530
- #
531
- # @since 1.12.0
532
- def xor(first, second)
533
- first.bytes.zip(second.bytes).map{ |(a,b)| (a ^ b).chr }.join('')
534
- end
535
-
536
- def validate_final_message!(reply)
537
- validate!(reply)
538
- unless verifier == server_signature
539
- raise InvalidSignature.new(verifier, server_signature)
540
- end
541
- end
542
-
543
- def validate_first_message!(reply)
544
- validate!(reply)
545
- raise InvalidNonce.new(nonce, rnonce) unless rnonce.start_with?(nonce)
546
- end
547
-
548
- def validate!(reply)
549
- unless Support.ok?(reply)
550
- raise AuthenticationError, "Could not authorize user #{auth[:username]} on database #{auth[:db_name]}."
551
- end
552
- @reply = reply
553
- end
554
- end
555
- end
556
- end