Skip to content

Commit

Permalink
feat: add TryApiToken.Local with clause for dependabot/gtfs_creator_c…
Browse files Browse the repository at this point in the history
…i user for read-only access
  • Loading branch information
meagharty committed Feb 8, 2024
1 parent e47922d commit e6e14bf
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 0 deletions.
1 change: 1 addition & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ config :arrow,
},
ueberauth_provider: :cognito,
api_login_module: ArrowWeb.TryApiTokenAuth.Cognito,
local_token_allowed_domain: "@mbta.com",
required_roles: %{
view_disruption: ["read-only", "admin"],
create_disruption: ["admin"],
Expand Down
4 changes: 4 additions & 0 deletions lib/arrow_web/try_api_token_auth.ex
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ defmodule ArrowWeb.TryApiTokenAuth do
ArrowWeb.TryApiTokenAuth.Cognito
end

defp api_login_module_for_token(%Arrow.AuthToken{username: "[email protected]"}) do
ArrowWeb.TryApiTokenAuth.Local
end

defp api_login_module_for_token(_token) do
Application.get_env(:arrow, :api_login_module)
end
Expand Down
30 changes: 30 additions & 0 deletions lib/arrow_web/try_api_token_auth/local.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
defmodule ArrowWeb.TryApiTokenAuth.Local do
@moduledoc """
Signs in an API client from a database token for read-only access.
"""

alias Plug.Conn
require Logger

@spec sign_in(Conn.t(), Arrow.AuthToken.t()) :: Conn.t()
def sign_in(%Conn{} = conn, %Arrow.AuthToken{} = auth_token) do
if String.ends_with?(
auth_token.username,
Application.get_env(:arrow, :local_token_allowed_domain)
) do
conn
|> Guardian.Plug.sign_in(
ArrowWeb.AuthManager,
auth_token.username,
%{roles: ["read-only"]},
ttl: {0, :second}
)
else
Logger.warn(
"refusing to login in API client username=#{inspect(auth_token.username)} reason=unexpected username"
)

conn
end
end
end
49 changes: 49 additions & 0 deletions test/arrow_web/try_api_token_auth/local_test.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
defmodule ArrowWeb.TryApiTokenAuth.LocalTest do
use ArrowWeb.ConnCase
import ExUnit.CaptureLog

alias ArrowWeb.TryApiTokenAuth.Local

describe "sign_in/2" do
test "signs in a read-only token user", %{conn: conn} do
local_token_email = "[email protected]"
auth_token = auth_token_for(local_token_email)

conn = Local.sign_in(conn, auth_token)

assert Guardian.Plug.authenticated?(conn)
claims = Guardian.Plug.current_claims(conn)

assert claims["sub"] == local_token_email
assert claims["typ"] == "access"
assert claims["roles"] == ["read-only"]
assert Guardian.Plug.current_resource(conn) == local_token_email
end

test "does not sign in a token user who does not exist", %{conn: conn} do
auth_token = auth_token_for("[email protected]")

assert_raise FunctionClauseError, fn ->
Local.sign_in(conn, auth_token)
end

refute Guardian.Plug.authenticated?(conn)
end

test "does not sign in a token user who does not have an @mbta.com email", %{conn: conn} do
unknown_domain = "[email protected]"
Arrow.AuthToken.get_or_create_token_for_user(unknown_domain)
auth_token = auth_token_for(unknown_domain)

{conn, log} = with_log(fn -> Local.sign_in(conn, auth_token) end)

refute Guardian.Plug.authenticated?(conn)

assert log =~ "refusing to login"
end
end

defp auth_token_for(username) do
Arrow.Repo.get_by(Arrow.AuthToken, username: username)
end
end
14 changes: 14 additions & 0 deletions test/arrow_web/try_api_token_auth_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,20 @@ defmodule ArrowWeb.TryApiTokenAuthTest do
assert Guardian.Plug.current_resource(conn) == "[email protected]"
end

test "handles API token with local database token from gtfs_creator user", %{conn: conn} do
token = Arrow.AuthToken.get_or_create_token_for_user("[email protected]")

conn =
conn
|> put_req_header("x-api-key", token)
|> ArrowWeb.TryApiTokenAuth.call([])

claims = Guardian.Plug.current_claims(conn)

assert claims["roles"] == ["read-only"]
assert Guardian.Plug.current_resource(conn) == "[email protected]"
end

test "handles unexpected response from Cognito API", %{conn: conn} do
reassign_env(:ex_aws_requester, {Fake.ExAws, :unexpected_response})

Expand Down

0 comments on commit e6e14bf

Please sign in to comment.