Support implicit TLS connections

Update docs to clarify that the :ssl option is also for modern TLS, but the :tls option is only for STARTTLS

These options may benefit from being renamed but they match upstream terminology.
This commit is contained in:
Mark Felder 2024-09-15 13:56:16 -04:00
parent 5539fea3bb
commit af3bf8a462
3 changed files with 31 additions and 24 deletions

1
changelog.d/ldaps.fix Normal file
View file

@ -0,0 +1 @@
LDAPS connections (implicit TLS) are now supported.

View file

@ -968,9 +968,9 @@ Pleroma account will be created with the same name as the LDAP user name.
* `enabled`: enables LDAP authentication * `enabled`: enables LDAP authentication
* `host`: LDAP server hostname * `host`: LDAP server hostname
* `port`: LDAP port, e.g. 389 or 636 * `port`: LDAP port, e.g. 389 or 636
* `ssl`: true to use SSL, usually implies the port 636 * `ssl`: true to use implicit SSL/TLS, usually port 636
* `sslopts`: additional SSL options * `sslopts`: additional SSL options
* `tls`: true to start TLS, usually implies the port 389 * `tls`: true to use explicit TLS (STARTTLS), usually port 389
* `tlsopts`: additional TLS options * `tlsopts`: additional TLS options
* `base`: LDAP base, e.g. "dc=example,dc=com" * `base`: LDAP base, e.g. "dc=example,dc=com"
* `uid`: LDAP attribute name to authenticate the user, e.g. when "cn", the filter will be "cn=username,base" * `uid`: LDAP attribute name to authenticate the user, e.g. when "cn", the filter will be "cn=username,base"

View file

@ -40,34 +40,39 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
host = Keyword.get(ldap, :host, "localhost") host = Keyword.get(ldap, :host, "localhost")
port = Keyword.get(ldap, :port, 389) port = Keyword.get(ldap, :port, 389)
ssl = Keyword.get(ldap, :ssl, false) ssl = Keyword.get(ldap, :ssl, false)
sslopts = Keyword.get(ldap, :sslopts, []) tls = Keyword.get(ldap, :tls, false)
tlsopts = Keyword.get(ldap, :tlsopts, [])
cacertfile = Keyword.get(ldap, :cacertfile) || CAStore.file_path() cacertfile = Keyword.get(ldap, :cacertfile) || CAStore.file_path()
options = default_secure_opts = [
[{:port, port}, {:ssl, ssl}, {:timeout, @connection_timeout}] ++ verify: :verify_peer,
if sslopts != [], do: [{:sslopts, sslopts}], else: [] cacerts: decode_certfile(cacertfile),
customize_hostname_check: [
fqdn_fun: fn _ -> to_charlist(host) end
]
]
cacerts = decode_certfile(cacertfile) sslopts = Keyword.merge(default_secure_opts, Keyword.get(ldap, :sslopts, []))
tlsopts = Keyword.merge(default_secure_opts, Keyword.get(ldap, :tlsopts, []))
# :sslopts can only be included in :eldap.open/2 when {ssl: true}
# or the connection will fail
options =
if ssl do
[{:port, port}, {:ssl, ssl}, {:sslopts, sslopts}, {:timeout, @connection_timeout}]
else
[{:port, port}, {:ssl, ssl}, {:timeout, @connection_timeout}]
end
case :eldap.open([to_charlist(host)], options) do case :eldap.open([to_charlist(host)], options) do
{:ok, connection} -> {:ok, connection} ->
try do cond do
if Keyword.get(ldap, :tls, false) do ssl ->
:application.ensure_all_started(:ssl) :application.ensure_all_started(:ssl)
tls ->
case :eldap.start_tls( case :eldap.start_tls(
connection, connection,
Keyword.merge( tlsopts,
[
verify: :verify_peer,
cacerts: cacerts,
customize_hostname_check: [
fqdn_fun: fn _ -> to_charlist(host) end
]
],
tlsopts
),
@connection_timeout @connection_timeout
) do ) do
:ok -> :ok ->
@ -75,14 +80,15 @@ defmodule Pleroma.Web.Auth.LDAPAuthenticator do
error -> error ->
Logger.error("Could not start TLS: #{inspect(error)}") Logger.error("Could not start TLS: #{inspect(error)}")
:eldap.close(connection)
end end
end
bind_user(connection, ldap, name, password) true ->
after :ok
:eldap.close(connection)
end end
bind_user(connection, ldap, name, password)
{:error, error} -> {:error, error} ->
Logger.error("Could not open LDAP connection: #{inspect(error)}") Logger.error("Could not open LDAP connection: #{inspect(error)}")
{:error, {:ldap_connection_error, error}} {:error, {:ldap_connection_error, error}}