diff --git a/lib/auth/apikey.ex b/lib/auth/apikey.ex index 46854a77..8e0e783f 100644 --- a/lib/auth/apikey.ex +++ b/lib/auth/apikey.ex @@ -47,6 +47,8 @@ defmodule Auth.Apikey do rescue ArgumentError -> 0 + ArithmeticError -> + 0 end end diff --git a/lib/auth/role.ex b/lib/auth/role.ex index 5bae5490..86ec4580 100644 --- a/lib/auth/role.ex +++ b/lib/auth/role.ex @@ -39,6 +39,12 @@ defmodule Auth.Role do Repo.all(__MODULE__) end + def list_roles_for_app(app_id) do + __MODULE__ + |> where([r], r.app_id == ^app_id or is_nil(r.app_id)) # and a.status != 6) + |> Repo.all() + end + @doc """ Gets a single role. diff --git a/lib/auth_web/controllers/app_controller.ex b/lib/auth_web/controllers/app_controller.ex index 4ec22c99..6fe48e03 100644 --- a/lib/auth_web/controllers/app_controller.ex +++ b/lib/auth_web/controllers/app_controller.ex @@ -123,11 +123,18 @@ defmodule AuthWeb.AppController do approles/2 Return the (JSON) List of Roles for a given App based on apikey.client_id """ def approles(conn, %{"client_id" => client_id}) do - IO.inspect(client_id) + IO.inspect(client_id, label: "client_id:126") # return empty JSON list with 401 status if client_id is invalid + app_id = Auth.Apikey.decode_decrypt(client_id) + IO.inspect(app_id, label: "app_id:129") - roles = Auth.Role.list_roles() - roles = Enum.map(roles, fn role -> Auth.Role.strip_meta(role) end) - json(conn, roles) + if app_id == 0 or is_nil(app_id) do + # invalid client_id > 401 + AuthWeb.AuthController.unauthorized(conn) + else + roles = Auth.Role.list_roles_for_app(app_id) + roles = Enum.map(roles, fn role -> Auth.Role.strip_meta(role) end) + json(conn, roles) + end end end diff --git a/test/auth/apikey_test.exs b/test/auth/apikey_test.exs index b0832a3b..c100228a 100644 --- a/test/auth/apikey_test.exs +++ b/test/auth/apikey_test.exs @@ -17,10 +17,10 @@ defmodule Auth.ApikeyTest do end test "decode_decrypt/1 reverses the operation of encrypt_encode/1" do - person_id = 4_869_234_521 - key = Auth.Apikey.encrypt_encode(person_id) + app_id = 4_869_234_521 + key = Auth.Apikey.encrypt_encode(app_id) id = Auth.Apikey.decode_decrypt(key) - assert person_id == id + assert app_id == id end test "create_api_key/1 creates an AUTH_API_KEY" do @@ -32,16 +32,16 @@ defmodule Auth.ApikeyTest do end test "decrypt_api_key/1 decrypts an AUTH_API_KEY" do - person_id = 1234 - key = Auth.Apikey.create_api_key(person_id) + app_id = 1234 + key = Auth.Apikey.create_api_key(app_id) decrypted = Auth.Apikey.decrypt_api_key(key) - assert decrypted == person_id + assert decrypted == app_id end test "decode_decrypt/1 with invalid client_id" do valid_key = Auth.Apikey.encrypt_encode(1) - person_id = Auth.Apikey.decode_decrypt(valid_key) - assert person_id == 1 + app_id = Auth.Apikey.decode_decrypt(valid_key) + assert app_id == 1 invalid_key = String.slice(valid_key, 0..-2) error = Auth.Apikey.decode_decrypt(invalid_key) diff --git a/test/auth_web/controllers/app_controller_test.exs b/test/auth_web/controllers/app_controller_test.exs index 90f78f4a..86d8d980 100644 --- a/test/auth_web/controllers/app_controller_test.exs +++ b/test/auth_web/controllers/app_controller_test.exs @@ -1,7 +1,7 @@ defmodule AuthWeb.AppControllerTest do use AuthWeb.ConnCase - alias Auth.App + alias Auth.{App, Role} @create_attrs %{ desc: "some description", @@ -164,9 +164,18 @@ defmodule AuthWeb.AppControllerTest do describe "GET /approles/:client_id" do setup [:create_app] + test "returns 401 if client_id is invalid", %{conn: conn} do + conn = conn + |> put_req_header("accept", "application/json") + |> get("/approles/invalid") + + assert html_response(conn, 401) =~ "invalid" + end + test "returns (JSON) list of roles", %{conn: conn, app: app} do + roles = Auth.Role.list_roles_for_app(app.id) key = List.first(app.apikeys) - IO.inspect(app, label: "app") + # IO.inspect(app, label: "app") conn = conn |> admin_login() |> put_req_header("accept", "application/json") @@ -174,8 +183,58 @@ defmodule AuthWeb.AppControllerTest do assert conn.status == 200 {:ok, json} = Jason.decode(conn.resp_body) - IO.inspect(json) + # IO.inspect(json) + assert length(roles) == length(json) # assert html_response(conn, 200) =~ "successfully reset" end + + test "returns only relevant roles", %{conn: conn, app: app} do + roles = Role.list_roles_for_app(app.id) + # admin create role: + admin_role = %{desc: "admin role", name: "new admin role", app_id: app.id} + {:ok, %Role{} = admin_role} = Role.create_role(admin_role) + # check that the new role was added to the admin app role list: + roles2 = Role.list_roles_for_app(app.id) + assert length(roles) < length(roles2) + last = List.last(roles2) + assert last.name == admin_role.name + + + # login as non-admin person + conn2 = non_admin_login(conn) + + # create non-admin app (to get API Key) + {:ok, non_admin_app} = Auth.App.create_app(%{ + "name" => "default system app", + "desc" => "Demo App", + "url" => "localhost:4000", + "person_id" => conn2.assigns.person.id, + "status" => 3 + }) + # create non-admin role: + role_data = %{ + desc: "non-admin role", name: "non-admin role", + app_id: non_admin_app.id + } + {:ok, %Role{} = role2} = Role.create_role(role_data) + key = List.first(non_admin_app.apikeys) + + conn3 = conn2 + |> admin_login() + |> put_req_header("accept", "application/json") + |> get("/approles/#{key.client_id}") + + assert conn3.status == 200 + {:ok, json} = Jason.decode(conn3.resp_body) + last_role = List.last(json) + # confirm the last role in the list is the new non-admin role: + assert Map.get(last_role, "name") == role2.name + + # confirm the admin_role is NOT in the JSON reponse: + should_be_empty = Enum.filter(json, fn r -> + Map.get(r, "name") == admin_role.name + end) + assert length(should_be_empty) == 0 + end end end