Skip to content

Commit

Permalink
Merge pull request #76 from fleetyards/feat/auth/userinfo
Browse files Browse the repository at this point in the history
Feat/auth/userinfo
  • Loading branch information
kloenk authored Apr 9, 2023
2 parents 1d77af4 + dabefc0 commit 866df4b
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ defmodule ExFleetYards.Oauth.ResourceOwners do
[
{"nickname", user.username},
{"hangar_updated_at", user.hangar_updated_at},
{"public_hangar", user.public_hangar}
{"publicHangar", user.public_hangar}
| add_claims(resource_owner, user, scopes)
]
end
Expand Down
6 changes: 6 additions & 0 deletions apps/ex_fleet_yards_api/lib/ex_fleet_yards_api/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ defmodule ExFleetYardsApi.Router do
delete "/delete-account", RegisterController, :delete
end
end

scope "/openid/userinfo" do
pipe_through :require_authenticated

get "/", UserinfoController, :userinfo
end
end

# scope "/v2", ExFleetYardsApi do
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
defmodule ExFleetYardsApi.Routes.UserinfoController do
use ExFleetYardsApi, :controller

@behaviour Boruta.Openid.UserinfoApplication

plug :put_view, ExFleetYardsApi.Routes.UserinfoJson
plug(:authorize, ["openid"] when action in [:userinfo])

tags ["user"]

def openid_module, do: Application.get_env(:ex_fleet_yards_auth, :openid_module, Boruta.Openid)

operation :userinfo,
summary: "Get user info",
responses: [
ok: {"Userinfo", "application/json", ExFleetYardsApi.Schemas.Single.Userinfo},
unauthorized: {"Error", "application/json", Error}
],
security: [%{"authorization" => ["openid"]}]

def userinfo(conn, _params) do
openid_module().userinfo(conn, __MODULE__)
end

@impl Boruta.Openid.UserinfoApplication
def userinfo_fetched(conn, userinfo) do
conn
|> render(:userinfo, userinfo: userinfo)
end

@impl Boruta.Openid.UserinfoApplication
def unauthorized(conn, error) do
conn
|> put_resp_header(
"www-authenticate",
"error=\"#{error.error}\", error_description=\"#{error.error_description}\""
)
|> send_resp(:unauthorized, "")
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
defmodule ExFleetYardsApi.Routes.UserinfoJson do
use ExFleetYardsApi, :json

def userinfo(%{userinfo: userinfo}) do
userinfo
end
end
18 changes: 18 additions & 0 deletions apps/ex_fleet_yards_api/lib/ex_fleet_yards_api/schemas/single.ex
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,24 @@ defmodule ExFleetYardsApi.Schemas.Single do
})
end

defmodule Userinfo do
@moduledoc "Userinfo Schema"
require OpenApiSpex

OpenApiSpex.schema(%{
description: "Userinfo Schema",
type: :object,
properties: %{
sub: %Schema{type: :string, format: :uuid},
email: %Schema{type: :string, format: :email},
hangar_updated_at: %Schema{type: :string, format: :"date-time"},
nickname: %Schema{type: :string},
publicHangar: %Schema{type: :boolean}
},
required: [:sub]
})
end

defmodule Version do
require OpenApiSpex

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
defmodule ExFleetYardsApi.Routes.UserinfoTest do
use ExFleetYardsApi.ConnCase, async: true
use ExFleetYardsApi.Mox

import OpenApiSpex.TestAssertions

describe "userinfo" do
test "return userinfo response", %{conn: conn, api_spec: spec} do
login_user("testuser", ["openid"])

userinfo = %{
"sub" => SecureRandom.uuid()
}

Boruta.OpenidMock
|> expect(:userinfo, fn conn, module ->
module.userinfo_fetched(conn, userinfo)
end)

json =
conn
|> get("/v2/openid/userinfo")
|> json_response(200)

assert_schema json, "Userinfo", spec
assert json == userinfo
end
end
end
2 changes: 2 additions & 0 deletions apps/ex_fleet_yards_api/test/test_helper.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(ExFleetYards.Repo, :manual)

Mox.defmock(ExFleetYardsApi.Plugs.AuthorizationMock, for: ExFleetYardsApi.Plugs.Authorization)
Mox.defmock(Boruta.OauthMock, for: Boruta.OauthModule)
Mox.defmock(Boruta.OpenidMock, for: Boruta.OpenidModule)
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ defmodule ExFleetYardsAuth.Openid.ConfigurationController do
issuer: issuer,
auth_endpoint: base_url <> ~p"/oauth/authorize",
token_endpoint: base_url <> ~p"/oauth/token",
userinfo_endpoint: userinfo_endpoint(),
jwks_url: base_url <> ~p"/openid/certs",
scopes_supported: scope_list(),
response_types_supported: ["id_token", "code id_token", "id_token token"],
Expand All @@ -28,4 +29,18 @@ defmodule ExFleetYardsAuth.Openid.ConfigurationController do
ExFleetYards.Scopes.scope_list()
|> Enum.map(fn {scope, _} -> scope end)
end

defp api_host do
case Code.ensure_compiled(ExFleetYardsApi.Endpoint) do
{:module, _} ->
ExFleetYardsApi.Endpoint.host()

{:error, _} ->
"https://" <> Application.get_env(:ex_fleet_yards_auth, :api_domain)
end
end

defp userinfo_endpoint do
api_host() <> "/v2/openid/userinfo"
end
end
7 changes: 6 additions & 1 deletion apps/ex_fleet_yards_auth/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ defmodule ExFleetYardsAuth.MixProject do
compilers: [] ++ Mix.compilers(),
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps()
deps: deps(),
xref: xref()
]
end

Expand Down Expand Up @@ -55,6 +56,10 @@ defmodule ExFleetYardsAuth.MixProject do
]
end

defp xref do
[exclude: [ExFleetYardsApi.Endpoint]]
end

def aliases do
[
"assets.deploy": ["tailwind auth --minify", "esbuild auth --minify", "phx.digest"]
Expand Down

0 comments on commit 866df4b

Please sign in to comment.