defmodule FrenzyWeb.LoginController do use FrenzyWeb, :controller alias Frenzy.{Repo, User} alias FrenzyWeb.Endpoint if Frenzy.oidc_enabled?() do plug Ueberauth end def login(conn, params) do conn |> put_session(:continue_path, Map.get(params, "continue")) |> render("login.html", %{ oidc_enabled?: Frenzy.oidc_enabled?() }) end def login_post(conn, %{"username" => username, "password" => password} = params) do user = Repo.get_by(User, username: username) case Bcrypt.check_pass(user, password) do {:ok, user} -> put_user_and_redirect(conn, user) {:error, _reason} -> conn |> put_flash(:error, "Invalid username or password.") |> redirect(to: Routes.login_path(Endpoint, :login, continue: continue_path(conn))) end end def logout(conn, _params) do conn |> put_flash(:info, "Logged out.") |> clear_session() |> redirect(to: "/") end def ueberauth_callback(%{assigns: %{ueberauth_failure: _fails}} = conn, _params) do conn |> put_flash(:error, "Failed to authenticate.") |> redirect(to: Routes.login_path(Endpoint, :login, continue: continue_path(conn))) end def ueberauth_callback( %{assigns: %{ueberauth_auth: %{credentials: %{other: %{user_info: %{"sub" => subject}}}}}} = conn, _params ) do case Repo.get_by(User, oidc_subject: subject) do nil -> conn = FrenzyWeb.Plug.Authenticate.call(conn, nil) case conn.assigns.user do %User{} = user -> changeset = User.set_oidc_subject_changeset(user, %{oidc_subject: subject}) {:ok, user} = Repo.update(changeset) conn |> put_flash(:info, "Successfully linked OIDC.") |> redirect(to: continue_path(conn)) _ -> # TODO: register new user for subject conn |> put_flash(:error, "No matching OIDC subject.") |> redirect(to: Routes.login_path(Endpoint, :login, continue: continue_path(conn))) end user -> put_user_and_redirect(conn, user) end end defp continue_path(conn) do get_session(conn, :continue_path) || Routes.group_path(Endpoint, :index) end defp put_user_and_redirect(conn, user) do user_token = Phoenix.Token.sign(Endpoint, "user token", user.id) conn |> put_session(:user_token, user_token) |> redirect(to: continue_path(conn)) end end