Fix tests - add missing files
This commit is contained in:
19
test/fixtures/oidc_access_tokens.yml
vendored
19
test/fixtures/oidc_access_tokens.yml
vendored
@@ -1,16 +1,27 @@
|
||||
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
|
||||
|
||||
<%
|
||||
# Generate a random token and compute HMAC
|
||||
def generate_token_hmac
|
||||
token = SecureRandom.urlsafe_base64(48)
|
||||
hmac_key = Rails.application.key_generator.generate_key('oidc_token_prefix', 32)
|
||||
hmac = OpenSSL::HMAC.hexdigest('SHA256', hmac_key, token)
|
||||
[token, hmac]
|
||||
end
|
||||
|
||||
token_one, hmac_one = generate_token_hmac
|
||||
token_two, hmac_two = generate_token_hmac
|
||||
%>
|
||||
|
||||
one:
|
||||
token_digest: <%= BCrypt::Password.create(SecureRandom.urlsafe_base64(48)) %>
|
||||
token_prefix: <%= SecureRandom.urlsafe_base64(8)[0..7] %>
|
||||
token_hmac: <%= hmac_one %>
|
||||
application: kavita_app
|
||||
user: alice
|
||||
scope: "openid profile email"
|
||||
expires_at: 2025-12-31 23:59:59
|
||||
|
||||
two:
|
||||
token_digest: <%= BCrypt::Password.create(SecureRandom.urlsafe_base64(48)) %>
|
||||
token_prefix: <%= SecureRandom.urlsafe_base64(8)[0..7] %>
|
||||
token_hmac: <%= hmac_two %>
|
||||
application: another_app
|
||||
user: bob
|
||||
scope: "openid profile email"
|
||||
|
||||
17
test/fixtures/oidc_authorization_codes.yml
vendored
17
test/fixtures/oidc_authorization_codes.yml
vendored
@@ -1,7 +1,20 @@
|
||||
# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
|
||||
|
||||
<%
|
||||
# Generate a random code and compute HMAC
|
||||
def generate_code_hmac
|
||||
code = SecureRandom.urlsafe_base64(32)
|
||||
hmac_key = Rails.application.key_generator.generate_key('oidc_token_prefix', 32)
|
||||
hmac = OpenSSL::HMAC.hexdigest('SHA256', hmac_key, code)
|
||||
[code, hmac]
|
||||
end
|
||||
|
||||
code_one, hmac_one = generate_code_hmac
|
||||
code_two, hmac_two = generate_code_hmac
|
||||
%>
|
||||
|
||||
one:
|
||||
code: <%= SecureRandom.urlsafe_base64(32) %>
|
||||
code_hmac: <%= hmac_one %>
|
||||
application: kavita_app
|
||||
user: alice
|
||||
redirect_uri: "https://kavita.example.com/signin-oidc"
|
||||
@@ -10,7 +23,7 @@ one:
|
||||
used: false
|
||||
|
||||
two:
|
||||
code: <%= SecureRandom.urlsafe_base64(32) %>
|
||||
code_hmac: <%= hmac_two %>
|
||||
application: another_app
|
||||
user: bob
|
||||
redirect_uri: "https://app.example.com/auth/callback"
|
||||
|
||||
107
test/integration/webauthn_credential_enumeration_test.rb
Normal file
107
test/integration/webauthn_credential_enumeration_test.rb
Normal file
@@ -0,0 +1,107 @@
|
||||
require "test_helper"
|
||||
|
||||
class WebauthnCredentialEnumerationTest < ActionDispatch::IntegrationTest
|
||||
# ====================
|
||||
# CREDENTIAL ENUMERATION PREVENTION TESTS
|
||||
# ====================
|
||||
|
||||
test "prevents credential enumeration via delete endpoint" do
|
||||
user1 = User.create!(email_address: "user1@example.com", password: "password123")
|
||||
user2 = User.create!(email_address: "user2@example.com", password: "password123")
|
||||
|
||||
# Create a credential for user1
|
||||
credential1 = user1.webauthn_credentials.create!(
|
||||
external_id: Base64.urlsafe_encode64("user1_credential"),
|
||||
public_key: Base64.urlsafe_encode64("public_key_1"),
|
||||
sign_count: 0,
|
||||
nickname: "User1 Key",
|
||||
authenticator_type: "platform"
|
||||
)
|
||||
|
||||
# Create a credential for user2
|
||||
credential2 = user2.webauthn_credentials.create!(
|
||||
external_id: Base64.urlsafe_encode64("user2_credential"),
|
||||
public_key: Base64.urlsafe_encode64("public_key_2"),
|
||||
sign_count: 0,
|
||||
nickname: "User2 Key",
|
||||
authenticator_type: "platform"
|
||||
)
|
||||
|
||||
# Sign in as user1
|
||||
post signin_path, params: { email_address: "user1@example.com", password: "password123" }
|
||||
assert_response :redirect
|
||||
follow_redirect!
|
||||
|
||||
# Try to delete user2's credential while authenticated as user1
|
||||
# This should return 404 (not 403) to prevent enumeration
|
||||
delete webauthn_credential_path(credential2.id), as: :json
|
||||
|
||||
assert_response :not_found
|
||||
assert_includes JSON.parse(@response.body)["error"], "not found"
|
||||
|
||||
# Verify both credentials still exist
|
||||
assert_equal 1, user1.webauthn_credentials.count
|
||||
assert_equal 1, user2.webauthn_credentials.count
|
||||
|
||||
# Verify trying to delete a non-existent credential also returns 404
|
||||
# This confirms identical responses for enumeration prevention
|
||||
delete webauthn_credential_path(99999), as: :json
|
||||
|
||||
assert_response :not_found
|
||||
assert_includes JSON.parse(@response.body)["error"], "not found"
|
||||
|
||||
user1.destroy
|
||||
user2.destroy
|
||||
end
|
||||
|
||||
test "allows users to delete their own credentials" do
|
||||
user = User.create!(email_address: "user@example.com", password: "password123")
|
||||
|
||||
credential = user.webauthn_credentials.create!(
|
||||
external_id: Base64.urlsafe_encode64("user_credential"),
|
||||
public_key: Base64.urlsafe_encode64("public_key"),
|
||||
sign_count: 0,
|
||||
nickname: "My Key",
|
||||
authenticator_type: "platform"
|
||||
)
|
||||
|
||||
# Sign in
|
||||
post signin_path, params: { email_address: "user@example.com", password: "password123" }
|
||||
assert_response :redirect
|
||||
follow_redirect!
|
||||
|
||||
# Delete own credential - should succeed
|
||||
assert_difference "user.webauthn_credentials.count", -1 do
|
||||
delete webauthn_credential_path(credential.id), as: :json
|
||||
end
|
||||
|
||||
assert_response :success
|
||||
assert_includes JSON.parse(@response.body)["message"], "has been removed"
|
||||
|
||||
user.destroy
|
||||
end
|
||||
|
||||
test "unauthenticated user cannot delete credentials" do
|
||||
user = User.create!(email_address: "user@example.com", password: "password123")
|
||||
|
||||
credential = user.webauthn_credentials.create!(
|
||||
external_id: Base64.urlsafe_encode64("user_credential"),
|
||||
public_key: Base64.urlsafe_encode64("public_key"),
|
||||
sign_count: 0,
|
||||
nickname: "My Key",
|
||||
authenticator_type: "platform"
|
||||
)
|
||||
|
||||
# Try to delete without authentication
|
||||
delete webauthn_credential_path(credential.id), as: :json
|
||||
|
||||
# Should get redirect to signin (require_authentication before_action runs first)
|
||||
assert_response :redirect
|
||||
assert_redirected_to signin_path
|
||||
|
||||
# Verify credential still exists
|
||||
assert_equal 1, user.webauthn_credentials.count
|
||||
|
||||
user.destroy
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user