mirror of
https://github.com/livebook-dev/livebook.git
synced 2024-09-25 12:26:05 +08:00
e9766ed7a5
* Add token authentication * Restructure CLI * Allow port configuration * Further refactoring * Make sure livebook node starts with unique name * Improve startup error handling * Further refactoring * Add authentication tests * Add authentication view for entering the token * Fix auth tests * Always use random Livebook name for distribution * Don't enable ANSI on Windows * Define CLI Task behaviour and move generic logic to the main module * Generalize convertion from cli arguments to configuration * Randomly generate secret key base * Update test/livebook_web/plugs/auth_plug_test.exs Co-authored-by: José Valim <jose.valim@dashbit.co> * Override app config in persistent manner * Update lib/litebook_cli.ex Co-authored-by: José Valim <jose.valim@dashbit.co> * Move auth error to ErrorView * Unify node name configuration and allow it via CLI * Set all applications configs at once * Move token generation to application.ex to work outside CLI * Clean up overriding configuration * Store auth token in separate cookies * Update lib/livebook_cli/server.ex Co-authored-by: José Valim <jose.valim@dashbit.co> * Update lib/livebook_web/endpoint.ex Co-authored-by: José Valim <jose.valim@dashbit.co> * Update lib/livebook_web/plugs/auth_plug.ex Co-authored-by: José Valim <jose.valim@dashbit.co> Co-authored-by: José Valim <jose.valim@dashbit.co>
52 lines
1.3 KiB
Elixir
52 lines
1.3 KiB
Elixir
defmodule LivebookWeb.InvalidTokenError do
|
|
defexception plug_status: 401, message: "invalid token"
|
|
end
|
|
|
|
defmodule LivebookWeb.AuthPlug do
|
|
@moduledoc false
|
|
|
|
@behaviour Plug
|
|
|
|
import Plug.Conn
|
|
import Phoenix.Controller
|
|
|
|
@cookie_opts [sign: true, max_age: 2_592_000]
|
|
|
|
@impl true
|
|
def init(opts), do: opts
|
|
|
|
@impl true
|
|
def call(conn, _otps) do
|
|
case Application.get_env(:livebook, :token) do
|
|
nil -> conn
|
|
token -> token_authentication(conn, token)
|
|
end
|
|
end
|
|
|
|
defp token_authentication(conn, token) do
|
|
# The user may run multiple Livebook instances on the same host
|
|
# on different ports, so we scope the cookie name under port
|
|
token_cookie = "#{conn.port}:token"
|
|
|
|
conn = fetch_cookies(conn, signed: [token_cookie])
|
|
|
|
param_token = Map.get(conn.query_params, "token")
|
|
cookie_token = conn.cookies[token_cookie]
|
|
|
|
cond do
|
|
is_binary(param_token) and Plug.Crypto.secure_compare(param_token, token) ->
|
|
conn
|
|
|> put_resp_cookie(token_cookie, param_token, @cookie_opts)
|
|
# Redirect to the same path without query params
|
|
|> redirect(to: conn.request_path)
|
|
|> halt()
|
|
|
|
is_binary(cookie_token) and Plug.Crypto.secure_compare(cookie_token, token) ->
|
|
conn
|
|
|
|
true ->
|
|
raise LivebookWeb.InvalidTokenError
|
|
end
|
|
end
|
|
end
|