Add API key scopes

This commit is contained in:
Uku Taht 2021-04-09 11:53:41 +03:00
parent 2fc136777c
commit d473accf40
4 changed files with 53 additions and 3 deletions

View File

@ -5,6 +5,7 @@ defmodule Plausible.Auth.ApiKey do
@required [:user_id, :key, :name]
schema "api_keys" do
field :name, :string
field :scopes, {:array, :string}, default: ["stats:read:*"]
field :key, :string, virtual: true
field :key_hash, :string

View File

@ -21,14 +21,20 @@ defmodule PlausibleWeb.AuthorizeSitesApiPlug do
{:error, :invalid_api_key} ->
unauthorized(
conn,
"Invalid API key. Please make sure you're using a valid API key with access to the site you've requested."
"Invalid API key. Please make sure you're using a valid API key with access to the resource you've requested."
)
end
end
defp verify_access(api_key) do
hashed_key = ApiKey.do_hash(api_key)
found_key = Repo.get_by(ApiKey, key_hash: hashed_key)
found_key =
Repo.one(
from a in ApiKey,
where: a.key_hash == ^hashed_key,
where: fragment("? @> ?", a.scopes, ["sites:provision:*"])
)
cond do
found_key -> {:ok, found_key}

View File

@ -0,0 +1,24 @@
defmodule Plausible.Repo.Migrations.AddApiKeyScopes do
use Ecto.Migration
def up do
alter table(:api_keys) do
add :scopes, {:array, :text}
end
execute "UPDATE api_keys SET scopes='{stats:read:*}'"
alter table(:api_keys) do
modify :scopes, {:array, :text}, null: false
end
# https://stackoverflow.com/a/4059785
create index(:api_keys, [:scopes], using: "GIN")
end
def down do
alter table(:api_keys) do
remove :scopes
end
end
end

View File

@ -2,7 +2,12 @@ defmodule PlausibleWeb.Api.ExternalSitesControllerTest do
use PlausibleWeb.ConnCase
import Plausible.TestUtils
setup [:create_user, :create_api_key, :use_api_key]
setup %{conn: conn} do
user = insert(:user)
api_key = insert(:api_key, user: user, scopes: ["sites:provision:*"])
conn = Plug.Conn.put_req_header(conn, "authorization", "Bearer #{api_key.key}")
{:ok, user: user, api_key: api_key, conn: conn}
end
describe "POST /api/v1/sites" do
test "can create a site", %{conn: conn} do
@ -41,6 +46,20 @@ defmodule PlausibleWeb.Api.ExternalSitesControllerTest do
"error" => "domain can't be blank"
}
end
test "cannot access with a bad API key scope", %{conn: conn, user: user} do
api_key = insert(:api_key, user: user, scopes: ["stats:read:*"])
conn =
conn
|> Plug.Conn.put_req_header("authorization", "Bearer #{api_key.key}")
|> post("/api/v1/sites", %{"site" => %{"domain" => "domain.com"}})
assert json_response(conn, 401) == %{
"error" =>
"Invalid API key. Please make sure you're using a valid API key with access to the resource you've requested."
}
end
end
describe "PUT /api/v1/sites/shared-links/:link_name" do