017bcc9ce1
- Fix indentation - Split awkward initializer into separate methods - Rename credentials to passkeys - Simplify authenticator registry loading - Flatten nested errors under ActionPack::WebAuthn - Set passkey current params only requests that use it - Inline anemic methods - Replace custom validation with ActiveModel::Validation - Rename identity to holder in Passkey - Rename credentials to passkeys in JS - Extract framework library out of controllers - Pass params hashes down to ActionPack - Attempt to simplify public interface - Push data decoding down to the classes representing the data - Introduce has_passkeys - Add CBOR bigint support - Rename ActionPack::WebAuthn::Passkey to ActionPack::Passkey - Add create_passkey_button helper - Rename public-key to creation-options - Add sign_in_with_passkey_button helper - Dispatch events for the whole Passkey lifecycle - Add ED25519 support - Prevent crash on missing meta tag - Validate resident key options - Don't clobber existing ActionPack config options - Validate cryptographic params - Move CurrentWebAuthnRequest into ActionPack::Passkey - Use ActiveModel::Attributes for Options objects - Implement expiring challanges - Add lifecycle events - Extract param helpers into Request - Add passkey_creation_options and passkey_request_options helpers - Add create_passkey_challenge to make it easier to override the create method if needed - Prefix all view helpers with passkey_ - Auto-include ActionPack::Passkey::Holder - Make the passkey challange url configurable - Add a reminder about Passkeys to the magic link email
102 lines
3.0 KiB
Ruby
102 lines
3.0 KiB
Ruby
require "test_helper"
|
|
|
|
class Sessions::PasskeysControllerTest < ActionDispatch::IntegrationTest
|
|
include WebauthnTestHelper
|
|
|
|
setup do
|
|
@identity = identities(:kevin)
|
|
|
|
@credential = @identity.passkeys.create!(
|
|
name: "Test Passkey",
|
|
credential_id: Base64.urlsafe_encode64(SecureRandom.random_bytes(32), padding: false),
|
|
public_key: webauthn_private_key.public_to_der,
|
|
sign_count: 0,
|
|
transports: [ "internal" ]
|
|
)
|
|
end
|
|
|
|
test "successful authentication" do
|
|
untenanted do
|
|
challenge = request_webauthn_challenge
|
|
|
|
post session_passkey_url, params: build_assertion_params(challenge: challenge, credential: @credential)
|
|
|
|
assert_response :redirect
|
|
assert cookies[:session_token].present?
|
|
assert_redirected_to landing_path
|
|
end
|
|
end
|
|
|
|
test "updates sign count" do
|
|
untenanted do
|
|
challenge = request_webauthn_challenge
|
|
|
|
post session_passkey_url, params: build_assertion_params(challenge: challenge, credential: @credential, sign_count: 1)
|
|
|
|
assert_equal 1, @credential.reload.sign_count
|
|
end
|
|
end
|
|
|
|
test "rejects invalid signature" do
|
|
untenanted do
|
|
challenge = request_webauthn_challenge
|
|
|
|
params = build_assertion_params(challenge: challenge, credential: @credential)
|
|
params[:passkey][:signature] = Base64.urlsafe_encode64("invalid", padding: false)
|
|
|
|
post session_passkey_url, params: params
|
|
|
|
assert_redirected_to new_session_path
|
|
assert_not cookies[:session_token].present?
|
|
assert_equal "That passkey didn't work. Try again.", flash[:alert]
|
|
end
|
|
end
|
|
|
|
test "rejects unknown credential" do
|
|
untenanted do
|
|
request_webauthn_challenge
|
|
|
|
post session_passkey_url, params: {
|
|
passkey: {
|
|
id: "nonexistent",
|
|
client_data_json: Base64.urlsafe_encode64("{}", padding: false),
|
|
authenticator_data: Base64.urlsafe_encode64("x", padding: false),
|
|
signature: Base64.urlsafe_encode64("x", padding: false)
|
|
}
|
|
}
|
|
|
|
assert_redirected_to new_session_path
|
|
assert_not cookies[:session_token].present?
|
|
end
|
|
end
|
|
|
|
test "successful authentication via JSON" do
|
|
untenanted do
|
|
challenge = request_webauthn_challenge
|
|
|
|
post session_passkey_url(format: :json), params: build_assertion_params(challenge: challenge, credential: @credential)
|
|
|
|
assert_response :success
|
|
assert @response.parsed_body["session_token"].present?
|
|
end
|
|
end
|
|
|
|
test "failed authentication via JSON" do
|
|
untenanted do
|
|
request_webauthn_challenge
|
|
|
|
post session_passkey_url(format: :json), params: {
|
|
passkey: {
|
|
id: "nonexistent",
|
|
client_data_json: Base64.urlsafe_encode64("{}", padding: false),
|
|
authenticator_data: Base64.urlsafe_encode64("x", padding: false),
|
|
signature: Base64.urlsafe_encode64("x", padding: false)
|
|
}
|
|
}
|
|
|
|
assert_response :unauthorized
|
|
assert_equal "That passkey didn't work. Try again.", @response.parsed_body["message"]
|
|
end
|
|
end
|
|
end
|