There’s an excellent write-up on authenticating users against an LDAP database with Phoenix which was created by Richard Nyström. For some reason even though it’s barely a year old, there seem to be a few points that are either out of date or simply incorrect. I worked through his example and I wanted to share a few amendments to his original code in the interests of other developers who may want to use LDAP with Phoenix.
First the set up of Phoenix
mix phx.new ldap_example # was mix phoenix.new ldap_example ... Fetch and install dependencies? [Yn] Y cd ldap_example mix ecto.create (configure your db in config/dev.exs if needed) mix phx.gen.schema User users username:string name:string email:string # was # mix phoenix.gen.model User users username:string name:string email:string mix ecto.migrate
Next change is in the session_controller.ex file:
#was LdapExample.SessionController defmodule LdapExampleWeb.SessionController do #was LdapExample.Web, :controller use LdapExampleWeb, :controller alias LdapExample.{User, Repo, Ldap} def new(conn, _params) do render conn, "new.html", changeset: User.login_changeset end def create(conn, %{"user" => params}) do username = params["username"] password = params["password"] case Ldap.authenticate(username, password) do :ok -> handle_sign_in(conn, username) _ -> handle_error(conn) end end defp handle_sign_in(conn, username) do {:ok, user} = insert_or_update_user(username) conn |> put_flash(:info, "Logged in.") |> Guardian.Plug.sign_in(user) |> redirect(to: page_path(conn, :index)) end defp insert_or_update_user(username) do {:ok, ldap_entry} = Ldap.get_by_uid(username) user_attributes = Ldap.to_map(ldap_entry) user = Repo.get_by(User, username: username) changeset = case user do nil -> User.changeset(%User{}, user_attributes) _ -> User.changeset(user, user_attributes) end Repo.insert_or_update changeset end defp handle_error(conn) do conn |> put_flash(:error, "Wrong username or password") |> redirect(to: page_path(conn, :new)) end def delete(conn, _params) do Guardian.Plug.sign_out(conn) |> put_flash(:info, "Logged out successfully.") |> redirect(to: "/") end end
The changes to user.ex are not made in the web/model/user.ex; rather they’re made in the existing user.ex file.
And finally a change to session_view.ex
#was LdapExample.SessionView defmodule LdapExampleWeb.SessionView do use LdapExampleWeb, :view end