Skip to content

Commit f01d497

Browse files
authored
Add Support for the PLAIN authMechanism (#223)
* Add support for LDAP authentication (#5) * Add support for LDAP authentication * Unit test for url parser changes * Mention PLAIN auth support in the Readme (#6) * Mention PLAIN auth support in the Readme * tweak wording * Update readme (#7)
1 parent 2823e26 commit f01d497

File tree

5 files changed

+61
-0
lines changed

5 files changed

+61
-0
lines changed

README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,11 @@ separated in sub folders and module namespaces.
705705
## Auth Mechanisms
706706

707707
For versions of Mongo 3.0 and greater, the auth mechanism defaults to SCRAM.
708+
709+
If connecting to MongoDB Enterprise Edition or MongoDB Atlas, the [PLAIN](https://www.mongodb.com/docs/manual/tutorial/authenticate-nativeldap-activedirectory/)
710+
auth mechanism is supported for LDAP authentication. The GSSAPI auth mechanism used for Kerberos authentication
711+
is not currently supported.
712+
708713
If you'd like to use [MONGODB-X509](https://www.mongodb.com/docs/v6.0/tutorial/configure-x509-client-authentication/)
709714
authentication, you can specify that as a `start_link` option.
710715

lib/mongo/auth.ex

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ defmodule Mongo.Auth do
3939
Mongo.Auth.X509
4040
end
4141

42+
defp mechanism(%{wire_version: version, auth_mechanism: :plain}) when version >= 3 do
43+
Mongo.Auth.PLAIN
44+
end
45+
4246
defp mechanism(%{wire_version: version}) when version >= 3 do
4347
Mongo.Auth.SCRAM
4448
end

lib/mongo/auth/plain.ex

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
defmodule Mongo.Auth.PLAIN do
2+
@moduledoc false
3+
alias Mongo.MongoDBConnection.Utils
4+
5+
def auth({nil, nil}, _db, _s) do
6+
:ok
7+
end
8+
9+
def auth({username, password}, _db, s) do
10+
auth_payload = build_auth_payload(username, password)
11+
message = [saslStart: 1, mechanism: "PLAIN", payload: auth_payload]
12+
13+
case Utils.command(-3, message, s) do
14+
{:ok, _flags, %{"ok" => ok, "done" => true}} when ok == 1 ->
15+
:ok
16+
17+
{:ok, _flags, %{"ok" => ok, "errmsg" => reason, "code" => code}} when ok == 0 ->
18+
{:error, Mongo.Error.exception(message: "auth failed for user #{username}: #{reason}", code: code)}
19+
20+
error ->
21+
error
22+
end
23+
end
24+
25+
defp build_auth_payload(username, password) do
26+
# https://www.ietf.org/rfc/rfc4616.txt
27+
# Null separate listed of authorization ID (blank), username, password. These are sent as raw UTF-8.
28+
payload = "\0#{username}\0#{password}"
29+
%BSON.Binary{binary: payload}
30+
end
31+
end

lib/mongo/url_parser.ex

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ defmodule Mongo.UrlParser do
113113

114114
defp decode_percent(:username, value), do: URI.decode_www_form(value)
115115
defp decode_percent(:password, value), do: URI.decode_www_form(value)
116+
defp decode_percent(:auth_source, value), do: URI.decode_www_form(value)
116117
defp decode_percent(_other, value), do: value
117118

118119
defp parse_query_options(opts, %{"options" => options}) when is_binary(options) do

test/mongo/url_parser_test.exs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,5 +199,25 @@ defmodule Mongo.UrlParserTest do
199199
username = Keyword.get(opts, :username)
200200
assert username == real_username
201201
end
202+
203+
test "external auth source " do
204+
encoded_external_auth_source = URI.encode_www_form("$external")
205+
url = "mongodb://user:[email protected]:27017,seed2.domain.com:27017,seed3.domain.com:27017/db_name?replicaSet=set-name&authMechanism=PLAIN&authSource=#{encoded_external_auth_source}&tls=true"
206+
207+
assert UrlParser.parse_url(url: url) |> Keyword.drop([:pw_safe]) == [
208+
password: "*****",
209+
username: "user",
210+
database: "db_name",
211+
tls: true,
212+
auth_source: "$external",
213+
auth_mechanism: :plain,
214+
set_name: "set-name",
215+
seeds: [
216+
"seed1.domain.com:27017",
217+
"seed2.domain.com:27017",
218+
"seed3.domain.com:27017"
219+
]
220+
]
221+
end
202222
end
203223
end

0 commit comments

Comments
 (0)