Skip to content

Commit

Permalink
Add support for basic auth in OAuth endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
geekingfrog committed Jul 27, 2024
1 parent 1c25e05 commit d265368
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 14 deletions.
30 changes: 20 additions & 10 deletions lib/teiserver_web/controllers/o_auth/code_controller.ex
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,12 @@ defmodule TeiserverWeb.OAuth.CodeController do
end

def token(conn, %{"grant_type" => "client_credentials"} = params) do
case Enum.find(
["grant_type", "client_id", "client_secret"],
fn key -> not Map.has_key?(params, key) end
) do
nil ->
get_token_from_credentials(conn, params)
case get_credentials(conn, params) do
{:ok, client_id, client_secret} ->
get_token_from_credentials(conn, client_id, client_secret)

missing_key ->
conn |> put_status(400) |> render(:error, error_description: "missing #{missing_key}")
{:error, msg} ->
conn |> put_status(400) |> render(:error, error_description: msg)
end
end

Expand Down Expand Up @@ -71,8 +68,21 @@ defmodule TeiserverWeb.OAuth.CodeController do
end
end

defp get_token_from_credentials(conn, params) do
with {:ok, cred} <- OAuth.get_valid_credentials(params["client_id"], params["client_secret"]),
defp get_credentials(conn, params) do
basic = Plug.BasicAuth.parse_basic_auth(conn)
post_params = {Map.get(params, "client_id"), Map.get(params, "client_secret")}

case {basic, post_params} do
{:error, {nil, nil}} -> {:error, "unauthorized"}
{{user, pass}, _} -> {:ok, user, pass}
{_, {nil, _}} -> {:error, "missing client_id"}
{_, {_, nil}} -> {:error, "missing client_secret"}
{_, {client_id, client_secret}} -> {:ok, client_id, client_secret}
end
end

defp get_token_from_credentials(conn, client_id, client_secret) do
with {:ok, cred} <- OAuth.get_valid_credentials(client_id, client_secret),
{:ok, token} <- OAuth.get_token_from_credentials(cred) do
conn |> put_status(200) |> render(:token, token: token)
else
Expand Down
2 changes: 1 addition & 1 deletion lib/teiserver_web/views/api/o_auth/code_view.ex
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ defmodule TeiserverWeb.OAuth.CodeView do
issuer: base,
authorization_endpoint: base <> ~p"/oauth/authorize",
token_endpoint: base <> ~p"/oauth/token",
token_endpoint_auth_methods_supported: ["none", "client_secret_post"],
token_endpoint_auth_methods_supported: ["none", "client_secret_post", "client_secret_basic"],
grant_types_supported: [
"authorization_code",
"refresh_token",
Expand Down
40 changes: 37 additions & 3 deletions test/teiserver_web/controllers/o_auth/code_controller_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ defmodule TeiserverWeb.OAuth.CodeControllerTest do
end

defp setup_conn(_context) do
GeneralTestLib.conn_setup(Teiserver.TeiserverTestLib.player_permissions())
|> Teiserver.TeiserverTestLib.conn_setup()
conn = Phoenix.ConnTest.build_conn()
user = GeneralTestLib.make_user()
{:ok, conn: conn, user: user}
end

defp setup_app(context) do
Expand Down Expand Up @@ -154,6 +155,35 @@ defmodule TeiserverWeb.OAuth.CodeControllerTest do
resp = post(conn, ~p"/oauth/token", data)
json_resp = json_response(resp, 400)
end

test "can also use basic auth",
%{conn: conn, credential: credential, credential_secret: secret} = setup_data do
data = %{grant_type: "client_credentials"}
auth_header = Plug.BasicAuth.encode_basic_auth(credential.client_id, secret)

conn =
conn
|> put_req_header("authorization", auth_header)

resp = post(conn, ~p"/oauth/token", data)
json_resp = json_response(resp, 200)
assert is_binary(json_resp["access_token"]), "has access_token"
assert is_integer(json_resp["expires_in"]), "has expires_in"
assert is_binary(json_resp["refresh_token"]), "has refresh_token"
assert json_resp["token_type"] == "Bearer", "bearer token type"
end

test "basic auth check", %{conn: conn, credential: credential} = setup_data do
data = %{grant_type: "client_credentials"}
auth_header = Plug.BasicAuth.encode_basic_auth(credential.client_id, "lolnope")

conn =
conn
|> put_req_header("authorization", auth_header)

resp = post(conn, ~p"/oauth/token", data)
json_resp = json_response(resp, 400)
end
end

describe "refresh token" do
Expand Down Expand Up @@ -213,7 +243,11 @@ defmodule TeiserverWeb.OAuth.CodeControllerTest do
"issuer" => "https://beyondallreason.info",
"authorization_endpoint" => "https://beyondallreason.info/oauth/authorize",
"token_endpoint" => "https://beyondallreason.info/oauth/token",
"token_endpoint_auth_methods_supported" => ["none", "client_secret_post"],
"token_endpoint_auth_methods_supported" => [
"none",
"client_secret_post",
"client_secret_basic"
],
"grant_types_supported" => [
"authorization_code",
"refresh_token",
Expand Down

0 comments on commit d265368

Please sign in to comment.