Rework authentication for the 3.0 client and multiple server versions

When authentication failures, MongoDB Java client throws a timeout
exception whose cause is a failed command exception which carries
a reason. Still not great at authentication failure notification.
This commit is contained in:
Michael Klishin 2015-05-17 18:51:44 +03:00
parent 6ca5b9d4ba
commit 8b2fd956e4
2 changed files with 22 additions and 36 deletions

View file

@ -19,7 +19,8 @@
* http://clojuremongodb.info/articles/gridfs.html" * http://clojuremongodb.info/articles/gridfs.html"
(:refer-clojure :exclude [count]) (:refer-clojure :exclude [count])
(:require [monger.conversion :refer :all]) (:require [monger.conversion :refer :all])
(:import [com.mongodb MongoClient MongoClientURI DB WriteConcern DBObject DBCursor Bytes MongoClientOptions MongoClientOptions$Builder ServerAddress MapReduceOutput MongoException] (:import [com.mongodb MongoClient MongoClientURI MongoCredential DB WriteConcern DBObject DBCursor Bytes
MongoClientOptions MongoClientOptions$Builder ServerAddress MapReduceOutput MongoException]
[com.mongodb.gridfs GridFS] [com.mongodb.gridfs GridFS]
[java.util Map ArrayList])) [java.util Map ArrayList]))
@ -46,7 +47,7 @@
{:arglists '([] {:arglists '([]
[server-address options] [server-address options]
[[server-address & more] options] [[server-address & more] options]
[{ :keys [host port uri] :or { host *mongodb-host* port *mongodb-port* }}])} [{:keys [host port uri] :or { host *mongodb-host* port *mongodb-port*}}])}
([] ([]
(MongoClient.)) (MongoClient.))
([server-address ^MongoClientOptions options] ([server-address ^MongoClientOptions options]
@ -61,13 +62,23 @@
credentials credentials
[credentials])] [credentials])]
(if (coll? server-address) (if (coll? server-address)
(let [server-list ^ArrayList (ArrayList. ^java.util.Collection server-address) (let [server-list ^ArrayList (ArrayList. ^java.util.Collection server-address)]
]
(MongoClient. server-list creds options)) (MongoClient. server-list creds options))
(MongoClient. ^ServerAddress server-address options)))) (MongoClient. ^ServerAddress server-address options))))
([{ :keys [host port uri] :or { host *mongodb-host* port *mongodb-port* }}] ([{ :keys [host port uri] :or { host *mongodb-host* port *mongodb-port* }}]
(MongoClient. ^String host ^Long port))) (MongoClient. ^String host ^Long port)))
(defn ^MongoClient connect-with-credentials
"Connect with provided credentials and default options"
([credentials]
(connect-with-credentials *mongodb-host* *mongodb-port* credentials))
([^String hostname credentials]
(connect-with-credentials hostname *mongodb-port* credentials))
([^String hostname port credentials]
(MongoClient. [(ServerAddress. hostname port)]
(if (coll? credentials)
credentials
[credentials]))))
(defn get-db-names (defn get-db-names
"Gets a list of all database names present on the server" "Gets a list of all database names present on the server"
@ -155,15 +166,6 @@
(alter-var-root #'*mongodb-write-concern* (constantly wc))) (alter-var-root #'*mongodb-write-concern* (constantly wc)))
(defn authenticate
([^DB db ^String username ^chars password]
(try
(.authenticate db username password)
;; MongoDB Java driver's exception hierarchy is a little crazy
;; and the exception we want is not a public class. MK.
(catch Exception _
false))))
(defn connect-via-uri (defn connect-via-uri
"Connects to MongoDB using a URI, returns the connection and database as a map with :conn and :db. "Connects to MongoDB using a URI, returns the connection and database as a map with :conn and :db.
Commonly used for PaaS-based applications, for example, running on Heroku. Commonly used for PaaS-based applications, for example, running on Heroku.
@ -171,12 +173,7 @@
[^String uri-string] [^String uri-string]
(let [uri (MongoClientURI. uri-string) (let [uri (MongoClientURI. uri-string)
conn (MongoClient. uri) conn (MongoClient. uri)
db (.getDB conn (.getDatabase uri)) db (.getDB conn (.getDatabase uri))]
user (.getUsername uri)
pwd (.getPassword uri)]
(when (and user pwd)
(when-not (authenticate db user pwd)
(throw (IllegalArgumentException. (format "Could not authenticate with MongoDB. Either database name or credentials are invalid. Database name: %s, username: %s" (.getName db) user)))))
{:conn conn :db db})) {:conn conn :db db}))
(defn ^com.mongodb.CommandResult command (defn ^com.mongodb.CommandResult command

View file

@ -1,5 +1,6 @@
(ns monger.test.authentication-test (ns monger.test.authentication-test
(:require [monger util db] (:require [monger util db]
[monger.credentials :as mcr]
[monger.core :as mg] [monger.core :as mg]
[monger.collection :as mc] [monger.collection :as mc]
[clojure.test :refer :all])) [clojure.test :refer :all]))
@ -33,21 +34,9 @@
;; Regular connecton ;; Regular connecton
;; ;;
(let [conn (mg/connect) (deftest ^{:authentication true} test-authentication-with-valid-credentials
db (mg/get-db conn "monger-test")]
(deftest ^{:authentication true} test-authentication-with-valid-credentials-on-the-default-db
;; see ./bin/ci/before_script.sh. MK. ;; see ./bin/ci/before_script.sh. MK.
(let [username "clojurewerkz/monger" (doseq [s ["monger-test" "monger-test2" "monger-test3" "monger-test4"]]
pwd "monger"] (let [creds (mcr/for "clojurewerkz/monger" "monger-test" "monger")
(is (mg/authenticate db username (.toCharArray pwd))))) conn (mg/connect-with-credentials "127.0.0.1" creds)]
(mc/remove (mg/get-db conn "monger-test") "documents"))))
(deftest ^{:authentication true} test-authentication-with-valid-credentials-on-an-arbitrary-db
;; see ./bin/ci/before_script.sh. MK.
(let [username "clojurewerkz/monger"
pwd "monger"]
(is (mg/authenticate (mg/get-db conn "monger-test") username (.toCharArray pwd)))))
(deftest ^{:authentication true} test-authentication-with-invalid-credentials
(let [username "monger"
^String pwd (monger.util/random-str 128 32)]
(is (not (mg/authenticate (mg/get-db conn "monger-test2") username (.toCharArray pwd)))))))