add oidc tests
This commit is contained in:
parent
b8afaff2c2
commit
7f5839a120
3 changed files with 730 additions and 4 deletions
|
|
@ -54,10 +54,130 @@ defmodule MvWeb.OidcIntegrationTest do
|
|||
end
|
||||
end
|
||||
|
||||
describe "OIDC sign-in security tests" do
|
||||
@tag :test_proposal
|
||||
test "sign_in_with_rauthy does NOT match user with only email (no oidc_id)" do
|
||||
# SECURITY TEST: Ensure password-only users cannot be accessed via OIDC
|
||||
# Create a password-only user (no oidc_id)
|
||||
_password_user =
|
||||
create_test_user(%{
|
||||
email: "password.only@example.com",
|
||||
password: "securepassword123",
|
||||
oidc_id: nil
|
||||
})
|
||||
|
||||
# Try to sign in with OIDC using the same email
|
||||
user_info = %{
|
||||
"sub" => "attacker_oidc_456",
|
||||
"preferred_username" => "password.only@example.com"
|
||||
}
|
||||
|
||||
# Should NOT find any user (security requirement)
|
||||
result =
|
||||
Mv.Accounts.read_sign_in_with_rauthy(%{
|
||||
user_info: user_info,
|
||||
oauth_tokens: %{}
|
||||
})
|
||||
|
||||
# Either returns empty list OR authentication error - both mean "user not found"
|
||||
case result do
|
||||
{:ok, []} ->
|
||||
:ok
|
||||
|
||||
{:error, %Ash.Error.Forbidden{errors: [%AshAuthentication.Errors.AuthenticationFailed{}]}} ->
|
||||
:ok
|
||||
|
||||
other ->
|
||||
flunk("Expected no user match, got: #{inspect(other)}")
|
||||
end
|
||||
end
|
||||
|
||||
@tag :test_proposal
|
||||
test "sign_in_with_rauthy only matches when oidc_id matches" do
|
||||
# Create user with specific OIDC ID
|
||||
user =
|
||||
create_test_user(%{
|
||||
email: "oidc.user@example.com",
|
||||
oidc_id: "correct_oidc_789"
|
||||
})
|
||||
|
||||
# Try with correct oidc_id
|
||||
correct_user_info = %{
|
||||
"sub" => "correct_oidc_789",
|
||||
"preferred_username" => "oidc.user@example.com"
|
||||
}
|
||||
|
||||
{:ok, [found_user]} =
|
||||
Mv.Accounts.read_sign_in_with_rauthy(%{
|
||||
user_info: correct_user_info,
|
||||
oauth_tokens: %{}
|
||||
})
|
||||
|
||||
assert found_user.id == user.id
|
||||
|
||||
# Try with wrong oidc_id but correct email
|
||||
wrong_user_info = %{
|
||||
"sub" => "wrong_oidc_999",
|
||||
"preferred_username" => "oidc.user@example.com"
|
||||
}
|
||||
|
||||
result =
|
||||
Mv.Accounts.read_sign_in_with_rauthy(%{
|
||||
user_info: wrong_user_info,
|
||||
oauth_tokens: %{}
|
||||
})
|
||||
|
||||
# Either returns empty list OR authentication error - both mean "user not found"
|
||||
case result do
|
||||
{:ok, []} ->
|
||||
:ok
|
||||
|
||||
{:error, %Ash.Error.Forbidden{errors: [%AshAuthentication.Errors.AuthenticationFailed{}]}} ->
|
||||
:ok
|
||||
|
||||
other ->
|
||||
flunk("Expected no user match when oidc_id differs, got: #{inspect(other)}")
|
||||
end
|
||||
end
|
||||
|
||||
@tag :test_proposal
|
||||
test "sign_in_with_rauthy does not match user with empty string oidc_id" do
|
||||
# Edge case: empty string should be treated like nil
|
||||
_user =
|
||||
create_test_user(%{
|
||||
email: "empty.oidc@example.com",
|
||||
oidc_id: ""
|
||||
})
|
||||
|
||||
user_info = %{
|
||||
"sub" => "new_oidc_111",
|
||||
"preferred_username" => "empty.oidc@example.com"
|
||||
}
|
||||
|
||||
result =
|
||||
Mv.Accounts.read_sign_in_with_rauthy(%{
|
||||
user_info: user_info,
|
||||
oauth_tokens: %{}
|
||||
})
|
||||
|
||||
# Either returns empty list OR authentication error - both mean "user not found"
|
||||
case result do
|
||||
{:ok, []} ->
|
||||
:ok
|
||||
|
||||
{:error, %Ash.Error.Forbidden{errors: [%AshAuthentication.Errors.AuthenticationFailed{}]}} ->
|
||||
:ok
|
||||
|
||||
other ->
|
||||
flunk("Expected no user match with empty oidc_id, got: #{inspect(other)}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "OIDC error and edge case scenarios" do
|
||||
test "OIDC registration with conflicting email and OIDC ID shows error" do
|
||||
# Create user with email and OIDC ID
|
||||
_existing_user =
|
||||
existing_user =
|
||||
create_test_user(%{
|
||||
email: "conflict@example.com",
|
||||
oidc_id: "oidc_conflict_1"
|
||||
|
|
@ -75,12 +195,15 @@ defmodule MvWeb.OidcIntegrationTest do
|
|||
oauth_tokens: %{}
|
||||
})
|
||||
|
||||
# Should fail due to unique constraint
|
||||
# Should fail with PasswordVerificationRequired (account conflict)
|
||||
# This prevents someone with OIDC provider B from taking over an account
|
||||
# that's already linked to OIDC provider A
|
||||
assert {:error, %Ash.Error.Invalid{errors: errors}} = result
|
||||
|
||||
# Should contain PasswordVerificationRequired error
|
||||
assert Enum.any?(errors, fn
|
||||
%Ash.Error.Changes.InvalidAttribute{field: :email, message: message} ->
|
||||
String.contains?(message, "has already been taken")
|
||||
%Mv.Accounts.User.Errors.PasswordVerificationRequired{user_id: user_id} ->
|
||||
user_id == existing_user.id
|
||||
|
||||
_ ->
|
||||
false
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue