diff --git a/lib/skate_web/controllers/auth_controller.ex b/lib/skate_web/controllers/auth_controller.ex index c7f328500..29d191c7c 100644 --- a/lib/skate_web/controllers/auth_controller.ex +++ b/lib/skate_web/controllers/auth_controller.ex @@ -70,6 +70,34 @@ defmodule SkateWeb.AuthController do |> redirect(to: ~p"/") end + def callback( + %{ + assigns: %{ + ueberauth_failure: + %Ueberauth.Failure{ + provider: :keycloak, + errors: [%Ueberauth.Failure.Error{message_key: "csrf_attack"}] + } = auth_struct + } + } = conn, + _params + ) do + Logger.error( + "#{__MODULE__} keycloak callback csrf ueberauth_failure struct=#{Kernel.inspect(auth_struct)}" + ) + + if get_session(conn, :keycloak_csrf_retry) == 1 do + conn + |> delete_session(:keycloak_csrf_retry) + |> send_resp(:unauthorized, "unauthenticated") + else + conn + |> put_session(:keycloak_csrf_retry, 1) + |> Guardian.Plug.sign_out(AuthManager, []) + |> redirect(to: ~p"/auth/keycloak") + end + end + def callback( %{assigns: %{ueberauth_failure: %{provider: :keycloak} = auth_struct}} = conn, _params diff --git a/test/skate_web/controllers/auth_controller_test.exs b/test/skate_web/controllers/auth_controller_test.exs index b41415050..3976707d4 100644 --- a/test/skate_web/controllers/auth_controller_test.exs +++ b/test/skate_web/controllers/auth_controller_test.exs @@ -134,6 +134,32 @@ defmodule SkateWeb.AuthControllerTest do assert response(conn, :unauthorized) == "unauthenticated" end + + @ueberauth_csrf_failure %Ueberauth.Failure{ + provider: :keycloak, + errors: [%Ueberauth.Failure.Error{message_key: "csrf_attack"}] + } + + test "retries login on first ueberauth CSRF failure", %{conn: conn} do + conn = + conn + |> init_test_session(%{username: "test_username"}) + |> assign(:ueberauth_failure, @ueberauth_csrf_failure) + |> get(~p"/auth/keycloak/callback") + + assert redirected_to(conn, :found) == ~p"/auth/keycloak" + end + + test "when CSRF error is encountered again, returns unauthenticated", %{conn: conn} do + conn = + conn + |> init_test_session(%{username: "test_username"}) + |> assign(:ueberauth_failure, @ueberauth_csrf_failure) + |> put_session(:keycloak_csrf_retry, 1) + |> get(~p"/auth/keycloak/callback") + + assert response(conn, :unauthorized) == "unauthenticated" + end end describe "GET /auth/keycloak/logout" do