Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
4.4 kB · 144 lines
Elixir
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145defmodule GitSyncWeb.SessionControllerTest do use GitSyncWeb.ConnCase
alias GitSync.Connections alias GitSync.Forge.Token alias GitSync.Forgejo.Provider alias GitSync.OidcProvider
setup :configure_forgejo
test "GET /login renders the sign-in page", %{conn: conn} do conn = get(conn, ~p"/login") assert html_response(conn, 200) =~ "Sign in with Forgejo" end
test "the page does not offer a Forgejo that cannot be an issuer", %{ conn: conn, connection: connection } do connection |> Ecto.Changeset.change(base_url: "file:///srv/dev_repos/forgejo") |> GitSync.Repo.update!()
conn = get(conn, ~p"/login")
refute html_response(conn, 200) =~ "Sign in with Forgejo" end
describe "with a live provider" do setup %{connection: connection} do issuer = OidcProvider.start(subject: "alice", client_id: connection.client_id)
:ok = Provider.stop() on_exit(&Provider.stop/0)
start_supervised!( {Oidcc.ProviderConfiguration.Worker, %{ issuer: issuer, name: Provider.name(), provider_configuration_opts: %{quirks: %{allow_unsafe_http: true}} }} )
:ok end
test "the authorization request carries an S256 PKCE challenge", %{conn: conn} do conn = post(conn, ~p"/auth/forgejo")
%{query: query} = conn |> redirected_to(302) |> URI.parse() params = URI.decode_query(query)
assert params["code_challenge_method"] == "S256" assert byte_size(params["code_challenge"]) > 0 end
test "the redirect URI follows the host the operator is using", %{conn: conn} do for host <- ["localhost", "kale.v.robins.wtf"] do params = %{conn | host: host} |> post(~p"/auth/forgejo") |> redirected_to(302) |> URI.parse() |> Map.fetch!(:query) |> URI.decode_query()
assert params["redirect_uri"] == "http://#{host}/auth/forgejo/callback" end end
test "a full code flow claims the operator seat and stores the token", %{conn: conn} do conn = sign_in(conn)
assert redirected_to(conn) == ~p"/" assert get_session(conn, "operator") == "alice"
connection = Connections.forgejo() assert connection.operator == "alice" assert connection.token == "forgejo-access-token" assert connection.refresh_token == "forgejo-refresh-token" assert DateTime.diff(connection.token_expires_at, DateTime.utc_now()) > 3500 end
test "the token request proves possession of the PKCE verifier", %{conn: conn} do sign_in(conn)
verifier = OidcProvider.code_verifier()
assert Base.url_encode64(:crypto.hash(:sha256, verifier), padding: false) == OidcProvider.code_challenge() end
test "a second Forgejo user is refused", %{conn: conn, connection: connection} do {:ok, _connection} = Connections.record_login(connection, "bob", Token.new("bobs-token", nil, nil))
conn = sign_in(conn)
assert redirected_to(conn) == ~p"/login" assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "already claimed by bob" refute get_session(conn, "operator") end end
test "the callback refuses a code with no authorization session", %{conn: conn} do conn = get(conn, ~p"/auth/forgejo/callback", %{"code" => "c", "state" => "s"})
assert redirected_to(conn) == ~p"/login" assert Phoenix.Flash.get(conn.assigns.flash, :error) =~ "missing_authorize_session" end
test "DELETE /logout clears the session", %{conn: conn} do conn = conn |> init_test_session(%{"operator" => "alice"}) |> delete(~p"/logout")
assert redirected_to(conn) == ~p"/login" refute get_session(conn, "operator") end
test "signed-out visitors are sent to the login page", %{conn: conn} do assert redirected_to(get(conn, ~p"/")) == ~p"/login" assert redirected_to(get(conn, ~p"/connections")) == ~p"/login" end
defp sign_in(conn) do conn = post(conn, ~p"/auth/forgejo")
callback = conn |> redirected_to(302) |> Req.get!(redirect: false) |> Req.Response.get_header("location") |> List.first() |> URI.parse()
conn |> recycle() |> Map.put(:secret_key_base, conn.secret_key_base) |> get(callback.path <> "?" <> callback.query) endend