Skip to content

Commit

Permalink
Add support for LDAP authentication (#5)
Browse files Browse the repository at this point in the history
* Add support for LDAP authentication

* Unit test for url parser changes
  • Loading branch information
JD-Robertson authored Sep 20, 2023
1 parent be592e3 commit d21aa76
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 0 deletions.
4 changes: 4 additions & 0 deletions lib/mongo/auth.ex
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ defmodule Mongo.Auth do
Mongo.Auth.X509
end

defp mechanism(%{wire_version: version, auth_mechanism: :plain}) when version >= 3 do
Mongo.Auth.PLAIN
end

defp mechanism(%{wire_version: version}) when version >= 3 do
Mongo.Auth.SCRAM
end
Expand Down
31 changes: 31 additions & 0 deletions lib/mongo/auth/plain.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
defmodule Mongo.Auth.PLAIN do
@moduledoc false
alias Mongo.MongoDBConnection.Utils

def auth({nil, nil}, _db, _s) do
:ok
end

def auth({username, password}, _db, s) do
auth_payload = build_auth_payload(username, password)
message = [saslStart: 1, mechanism: "PLAIN", payload: auth_payload]

case Utils.command(-3, message, s) do
{:ok, _flags, %{"ok" => ok, "done" => true}} when ok == 1 ->
:ok

{:ok, _flags, %{"ok" => ok, "errmsg" => reason, "code" => code}} when ok == 0 ->
{:error, Mongo.Error.exception(message: "auth failed for user #{username}: #{reason}", code: code)}

error ->
error
end
end

defp build_auth_payload(username, password) do
# https://www.ietf.org/rfc/rfc4616.txt
# Null separate listed of authorization ID (blank), username, password. These are sent as raw UTF-8.
payload = "\0#{username}\0#{password}"
%BSON.Binary{binary: payload}
end
end
1 change: 1 addition & 0 deletions lib/mongo/url_parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ defmodule Mongo.UrlParser do

defp decode_percent(:username, value), do: URI.decode_www_form(value)
defp decode_percent(:password, value), do: URI.decode_www_form(value)
defp decode_percent(:auth_source, value), do: URI.decode_www_form(value)
defp decode_percent(_other, value), do: value

defp parse_query_options(opts, %{"options" => options}) when is_binary(options) do
Expand Down
20 changes: 20 additions & 0 deletions test/mongo/url_parser_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,25 @@ defmodule Mongo.UrlParserTest do
username = Keyword.get(opts, :username)
assert username == real_username
end

test "external auth source " do
encoded_external_auth_source = URI.encode_www_form("$external")
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"

assert UrlParser.parse_url(url: url) |> Keyword.drop([:pw_safe]) == [
password: "*****",
username: "user",
database: "db_name",
tls: true,
auth_source: "$external",
auth_mechanism: :plain,
set_name: "set-name",
seeds: [
"seed1.domain.com:27017",
"seed2.domain.com:27017",
"seed3.domain.com:27017"
]
]
end
end
end

0 comments on commit d21aa76

Please sign in to comment.