Skip to content

Commit

Permalink
Refactor: use fixture for oauth objects
Browse files Browse the repository at this point in the history
Also put code hash and verifier there
  • Loading branch information
geekingfrog committed Jul 27, 2024
1 parent 24d3a3d commit 8a1d4df
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 62 deletions.
19 changes: 17 additions & 2 deletions test/support/fixtures/o_auth/o_auth_fixtures.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ defmodule Teiserver.OAuthFixtures do

def code_attrs(user_id, app) do
now = DateTime.utc_now()
{verifier, challenge, method} = generate_challenge()

%{
value: Base.hex_encode32(:crypto.strong_rand_bytes(32)),
Expand All @@ -27,8 +28,9 @@ defmodule Teiserver.OAuthFixtures do
scopes: app.scopes,
expires_at: Timex.add(now, Timex.Duration.from_minutes(5)),
redirect_uri: hd(app.redirect_uris),
challenge: "TODO",
challenge_method: :plain
challenge: challenge,
challenge_method: method,
_verifier: verifier
}
end

Expand Down Expand Up @@ -66,4 +68,17 @@ defmodule Teiserver.OAuthFixtures do
def create_credential(attrs) do
%Credential{} |> Credential.changeset(attrs) |> Repo.insert!()
end

defp generate_challenge() do
# A-Z,a-z,0-9 and -._~ are authorized, but can't be bothered to cover all
# of that. hex encoding will fit
verifier = Base.hex_encode32(:crypto.strong_rand_bytes(40), padding: false)

challenge = hash_verifier(verifier)

{verifier, challenge, "S256"}
end

def hash_verifier(verifier),
do: Base.url_encode64(:crypto.hash(:sha256, verifier), padding: false)
end
45 changes: 0 additions & 45 deletions test/support/o_auth.ex

This file was deleted.

2 changes: 1 addition & 1 deletion test/teiserver/o_auth/application_query_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule Teiserver.OAuth.ApplicationQueryTest do
use Teiserver.DataCase
alias Teiserver.Repo

alias Teiserver.OAuth.{Application, Code, ApplicationQueries, Token, Credential}
alias Teiserver.OAuth.ApplicationQueries
alias Teiserver.OAuthFixtures

defp setup_app(_context) do
Expand Down
36 changes: 25 additions & 11 deletions test/teiserver/o_auth/code_test.exs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
defmodule Teiserver.OAuth.CodeTest do
use Teiserver.DataCase, async: true
alias Teiserver.OAuth
alias Teiserver.Test.Support.OAuth, as: OAuthTest
alias Teiserver.OAuthFixtures

setup do
user = Teiserver.TeiserverTestLib.new_user()
Expand All @@ -11,27 +11,28 @@ defmodule Teiserver.OAuth.CodeTest do
name: "Testing app",
uid: "test_app_uid",
owner_id: user.id,
scopes: ["tachyon.lobby"]
scopes: ["tachyon.lobby"],
redirect_uris: ["http://localhost/foo"]
})

{:ok, user: user, app: app}
end

test "can get valid code", %{user: user, app: app} do
assert {:ok, code, _} = OAuthTest.create_code(user, app)
assert {:ok, code, _} = create_code(user, app)
assert {:ok, ^code} = OAuth.get_valid_code(code.value)
assert {:error, :no_code} = OAuth.get_valid_code(nil)
end

test "cannot retrieve expired code", %{user: user, app: app} do
yesterday = Timex.shift(Timex.now(), days: -1)
assert {:ok, code, _} = OAuthTest.create_code(user, app, now: yesterday)
assert {:ok, code, _} = create_code(user, app, expires_at: yesterday)
assert {:error, :expired} = OAuth.get_valid_code(code.value)
end

test "can exchange valid code for token", %{user: user, app: app} do
assert {:ok, code, attrs} = OAuthTest.create_code(user, app)
assert {:ok, token} = OAuth.exchange_code(code, attrs.verifier, attrs.redirect_uri)
assert {:ok, code, attrs} = create_code(user, app)
assert {:ok, token} = OAuth.exchange_code(code, attrs._verifier, attrs.redirect_uri)
assert token.scopes == code.scopes
assert token.owner_id == user.id
# the code is now consumed and not available anymore
Expand All @@ -40,23 +41,36 @@ defmodule Teiserver.OAuth.CodeTest do

test "cannot exchange expired code for token", %{user: user, app: app} do
yesterday = Timex.shift(Timex.now(), days: -1)
assert {:ok, code, attrs} = OAuthTest.create_code(user, app, now: yesterday)
assert {:error, :expired} = OAuth.exchange_code(code, attrs.verifier)
assert {:ok, code, attrs} = create_code(user, app, expires_at: yesterday)
assert {:error, :expired} = OAuth.exchange_code(code, attrs._verifier)
end

test "must use valid verifier", %{user: user, app: app} do
assert {:ok, code, attrs} = OAuthTest.create_code(user, app)
assert {:ok, code, attrs} = create_code(user, app)
attrs = Map.put(attrs, :id, app.id)
no_match = Base.hex_encode32(:crypto.strong_rand_bytes(38), padding: false)
assert {:error, _} = OAuth.exchange_code(code, no_match)

verifier = "TOO_SHORT"
challenge = OAuthTest.hash_verifier(verifier)
challenge = OAuthFixtures.hash_verifier(verifier)
{:ok, code} = OAuth.create_code(user, %{attrs | challenge: challenge})
assert {:error, _} = OAuth.exchange_code(code, verifier)

verifier = String.duplicate("a", 129)
challenge = OAuthTest.hash_verifier(verifier)
challenge = OAuthFixtures.hash_verifier(verifier)
{:ok, code} = OAuth.create_code(user, %{attrs | challenge: challenge})
assert {:error, _} = OAuth.exchange_code(code, verifier)
end

defp create_code(user, app, opts \\ []) do
expires_at =
Keyword.get(opts, :expires_at, Timex.add(DateTime.utc_now(), Timex.Duration.from_days(1)))

attrs =
OAuthFixtures.code_attrs(user.id, app)
|> Map.put(:expires_at, expires_at)

code = OAuthFixtures.create_code(attrs)
{:ok, code, attrs}
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ defmodule TeiserverWeb.OAuth.CodeControllerTest do
use TeiserverWeb.ConnCase
alias Central.Helpers.GeneralTestLib
alias Teiserver.OAuth
alias Teiserver.Test.Support.OAuth, as: OAuthTest
alias Teiserver.OAuthFixtures

defp get_valid_data(%{app: app, code: code, code_attrs: code_attrs}) do
%{
grant_type: "authorization_code",
code: code.value,
redirect_uri: code.redirect_uri,
client_id: app.uid,
code_verifier: code_attrs.verifier
code_verifier: code_attrs._verifier
}
end

Expand All @@ -34,7 +34,8 @@ defmodule TeiserverWeb.OAuth.CodeControllerTest do
end

defp setup_code(context) do
{:ok, code, attrs} = OAuthTest.create_code(context[:user], context[:app])
attrs = OAuthFixtures.code_attrs(context[:user].id, context[:app])
code = OAuthFixtures.create_code(attrs)

%{code: code, code_attrs: attrs}
end
Expand Down

0 comments on commit 8a1d4df

Please sign in to comment.