Handle token auth under the same /authenticate route as password (#1104)

* auth token mode routes /authentication

* Update lib/livebook_web/controllers/auth_controller.ex

Co-authored-by: Jonatan Kłosko <jonatanklosko@gmail.com>
This commit is contained in:
ByeongUk Choi 2022-04-14 01:51:28 +09:00 committed by GitHub
parent d031d2b7a3
commit 5606326203
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 40 additions and 64 deletions

View file

@ -1,12 +1,14 @@
defmodule LivebookWeb.AuthController do
use LivebookWeb, :controller
plug :require_unauthenticated_password
plug :require_unauthenticated
alias LivebookWeb.AuthPlug
defp require_unauthenticated_password(conn, _opts) do
if Livebook.Config.auth_mode() != :password or AuthPlug.authenticated?(conn, :password) do
defp require_unauthenticated(conn, _opts) do
auth_mode = Livebook.Config.auth_mode()
if auth_mode not in [:password, :token] or AuthPlug.authenticated?(conn, auth_mode) do
redirect_home(conn)
else
conn
@ -14,7 +16,7 @@ defmodule LivebookWeb.AuthController do
end
def index(conn, _params) do
render(conn, "index.html")
render(conn, "index.html", auth_mode: Livebook.Config.auth_mode())
end
def authenticate(conn, %{"password" => password}) do
@ -27,6 +29,16 @@ defmodule LivebookWeb.AuthController do
end
end
def authenticate(conn, %{"token" => token}) do
conn = AuthPlug.store(conn, :token, token)
if AuthPlug.authenticated?(conn, :token) do
redirect_home(conn)
else
index(conn, %{})
end
end
defp redirect_home(conn) do
conn
|> redirect(to: "/")

View file

@ -1,7 +1,3 @@
defmodule LivebookWeb.InvalidTokenError do
defexception plug_status: 401, message: "invalid token"
end
defmodule LivebookWeb.AuthPlug do
@moduledoc false
@ -55,9 +51,7 @@ defmodule LivebookWeb.AuthPlug do
end
defp authenticate(conn, :password) do
conn
|> redirect(to: "/authenticate")
|> halt()
redirect_to_authenticate(conn)
end
defp authenticate(conn, :token) do
@ -70,10 +64,16 @@ defmodule LivebookWeb.AuthPlug do
|> redirect(to: path_with_query(conn.request_path, query_params))
|> halt()
else
raise LivebookWeb.InvalidTokenError
redirect_to_authenticate(conn)
end
end
defp redirect_to_authenticate(conn) do
conn
|> redirect(to: "/authenticate")
|> halt()
end
defp path_with_query(path, params) when params == %{}, do: path
defp path_with_query(path, params), do: path <> "?" <> URI.encode_query(params)

View file

@ -8,12 +8,21 @@
</div>
<div class="max-w-2xl text-center text-gray-300">
<%= if @auth_mode == :password do %>
Type password to access the Livebook.
<% else %>
Please check out the console for authentication URL
or type the token directly here.
<% end %>
</div>
<div class="text-2xl text-gray-50 w-full pt-2">
<form method="post" class="flex flex-col space-y-4 items-center">
<input type="hidden" value="<%= Phoenix.Controller.get_csrf_token() %>" name="_csrf_token"/>
<input type="password" name="password" class="input" placeholder="Password" autofocus />
<%= if @auth_mode == :password do %>
<input type="password" name="password" class="input" placeholder="Password" autofocus />
<% else %>
<input type="text" name="token" class="input" placeholder="Token" autofocus />
<% end %>
<button type="submit" class="button-base button-blue">
Authenticate
</button>

View file

@ -1,37 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
<title><%= @status %> - Livebook</title>
<link rel="stylesheet" href="<%= Routes.static_path(@conn, "/css/app.css") %>"/>
</head>
<body>
<div class="h-screen flex items-center justify-center bg-gray-900">
<div class="flex flex-col space-y-4 items-center">
<a href="/">
<img src="/images/logo.png" height="128" width="128" alt="livebook" />
</a>
<div class="text-2xl text-gray-50">
Authentication required
</div>
<div class="max-w-2xl text-center text-gray-300">
Please check out the console for authentication URL
or type the token directly here.
</div>
<div class="text-2xl text-gray-50 w-full pt-2">
<form method="get" class="flex flex-col space-y-4 items-center">
<input type="text" name="token" class="input" placeholder="Token" autofocus />
<button type="submit" class="button-base button-blue">
Authenticate
</button>
</form>
</div>
</div>
</div>
</body>
</html>

View file

@ -31,13 +31,9 @@ defmodule LivebookWeb.AuthPlugTest do
end
@tag token: "grumpycat"
test "returns authentication error when token is set and none provided", %{conn: conn} do
{_, _, resp_body} =
assert_error_sent 401, fn ->
get(conn, "/")
end
assert resp_body =~ "Authentication required"
test "redirects to '/authenticate' if not authenticated", %{conn: conn} do
conn = get(conn, "/")
assert redirected_to(conn) == "/authenticate"
end
@tag token: "grumpycat"
@ -48,14 +44,10 @@ defmodule LivebookWeb.AuthPlugTest do
end
@tag token: "grumpycat"
test "returns authentication error when invalid token is provided in query params",
test "redirects to '/authenticate' when invalid token is provided in query params",
%{conn: conn} do
{_, _, resp_body} =
assert_error_sent 401, fn ->
get(conn, "/?token=invalid")
end
assert resp_body =~ "Authentication required"
conn = get(conn, "/")
assert redirected_to(conn) == "/authenticate"
end
@tag token: "grumpycat"