webauthn-rails 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5bf8803deeac8d925eef701fa4b9a25b3ecea1288e5af2b07dad81e60b16574d
4
- data.tar.gz: ad28b85f03d4d693ec12d94c6702e6a8a6a0fbdd9226303efa520e61bc6c1000
3
+ metadata.gz: 20ded36acb2b7a3f4d67cdd4e860dc41e6f8490bb9143be6a0575117e1e7a84e
4
+ data.tar.gz: 8b2d46393c0d24e340b82f7f5d908e34fdd7cedb30501b8e8ba9663f217c23b9
5
5
  SHA512:
6
- metadata.gz: 7d10d95538f98bfd0375159c3bd7acba311992cf06062aecfae5fe1f1c4bdf57de6494fd6c5ade9e70a5d5e096be723a768d330ec3722fe1f659904f4842d834
7
- data.tar.gz: c81deb6084edc784f72d1cda4189e651a4748a75af71d80ad15e942a4ca6bd497f5f3211930b3416bb0ea474577fe7481850226938a9b725d1933bcbec652031
6
+ metadata.gz: 89c27f2bd69320aef0d3a36207788478ce85e7eea4b1f722950ec12749fa3fdcaa5a3eed1f322b77425d5d8b8e1d848cf912d84cd55c7872fa2142750626b345
7
+ data.tar.gz: d125c6229d26da7d19794479091ec59b706e10166a70a5e3f228a4d3571906a5b3d3a3db23c81cfb2c735e56c91c9bdf1ee01f249689761641d46aad1319f8ff
@@ -7,7 +7,7 @@ class PasskeysControllerTest < ActionDispatch::IntegrationTest
7
7
  @client = WebAuthn::FakeClient.new(WebAuthn.configuration.allowed_origins.first)
8
8
  end
9
9
 
10
- test "initiates Passkey creation when user is authenticated" do
10
+ test "create_options" do
11
11
  sign_in_as @user
12
12
  post create_options_passkeys_url
13
13
 
@@ -20,14 +20,14 @@ class PasskeysControllerTest < ActionDispatch::IntegrationTest
20
20
  assert_equal session[:current_registration][:challenge], body["challenge"]
21
21
  end
22
22
 
23
- test "requires authentication to initiate Passkey creation" do
23
+ test "create_options unauthenticated" do
24
24
  post create_options_passkeys_url
25
25
 
26
26
  assert_response :redirect
27
27
  assert_redirected_to new_session_url
28
28
  end
29
29
 
30
- test "creates passkey when user is authenticated" do
30
+ test "create" do
31
31
  sign_in_as @user
32
32
 
33
33
  post create_options_passkeys_url
@@ -52,7 +52,7 @@ class PasskeysControllerTest < ActionDispatch::IntegrationTest
52
52
  assert_nil session[:current_registration]
53
53
  end
54
54
 
55
- test "does not create passkey when there is a Webauthn error" do
55
+ test "create with WebAuthn error" do
56
56
  sign_in_as @user
57
57
 
58
58
  post create_options_passkeys_url
@@ -77,34 +77,26 @@ class PasskeysControllerTest < ActionDispatch::IntegrationTest
77
77
  assert_nil session[:current_registration]
78
78
  end
79
79
 
80
- test "requires authentication to create passkey" do
81
- post passkeys_url, params: {
82
- credential: {
83
- nickname: "My Passkey",
84
- public_key_credential: "{}"
85
- }
86
- }
80
+ test "create unauthenticated" do
81
+ post passkeys_url
87
82
 
88
83
  assert_response :redirect
89
84
  assert_redirected_to new_session_url
90
85
  end
91
86
 
92
- test "deletes passkey when user is authenticated" do
93
- 2.times do |i|
94
- WebauthnCredential.create!(
95
- nickname: "My Passkey #{i}",
96
- user: @user,
97
- external_id: "external-id-#{i}",
98
- public_key: "public-key-#{i}",
99
- sign_count: 0,
100
- authentication_factor: 0
101
- )
102
- end
87
+ test "destroy" do
88
+ credential = WebauthnCredential.passkey.create!(
89
+ nickname: "My Passkey",
90
+ user: @user,
91
+ external_id: "external-id",
92
+ public_key: "public-key",
93
+ sign_count: 0,
94
+ )
103
95
 
104
96
  sign_in_as @user
105
97
 
106
98
  assert_difference("WebauthnCredential.count", -1) do
107
- delete passkey_url(@user.webauthn_credentials.first)
99
+ delete passkey_url(credential)
108
100
  end
109
101
  assert_redirected_to root_path
110
102
  end
@@ -0,0 +1,131 @@
1
+ require "test_helper"
2
+ require "webauthn/fake_client"
3
+
4
+ class SecondFactorAuthenticationsControllerTest < ActionDispatch::IntegrationTest
5
+ setup do
6
+ @user = users(:one)
7
+ @client = WebAuthn::FakeClient.new(WebAuthn.configuration.allowed_origins.first)
8
+
9
+ creation_options = WebAuthn::Credential.options_for_create(
10
+ user: { id: @user.webauthn_id, name: @user.email_address },
11
+ authenticator_selection: { resident_key: "discouraged", user_verification: "discouraged" }
12
+ )
13
+ create_options = @client.create(challenge: creation_options.challenge)
14
+ credential = WebAuthn::Credential.from_create(create_options)
15
+
16
+ WebauthnCredential.second_factor.create!(
17
+ nickname: "My Security Key",
18
+ user: @user,
19
+ external_id: credential.id,
20
+ public_key: credential.public_key,
21
+ sign_count: 0
22
+ )
23
+ end
24
+
25
+ test "get_options" do
26
+ post session_path, params: { email_address: @user.email_address, password: "password" }
27
+
28
+ post get_options_second_factor_authentication_url
29
+
30
+ assert_response :success
31
+ body = JSON.parse(response.body)
32
+ assert body["challenge"].present?
33
+ assert body["userVerification"] == "discouraged"
34
+
35
+ assert_equal session[:current_authentication][:challenge], body["challenge"]
36
+ end
37
+
38
+ test "create" do
39
+ post session_path, params: { email_address: @user.email_address, password: "password" }
40
+
41
+ post get_options_second_factor_authentication_url
42
+ challenge = session[:current_authentication][:challenge]
43
+
44
+ public_key_credential = @client.get(challenge: challenge, user_verified: false)
45
+
46
+ post second_factor_authentication_url, params: {
47
+ session: {
48
+ public_key_credential: public_key_credential.to_json
49
+ }
50
+ }
51
+
52
+ assert_redirected_to root_path
53
+ assert_nil session[:current_authentication]
54
+ end
55
+
56
+ test "create with a passkey" do
57
+ client = WebAuthn::FakeClient.new(WebAuthn.configuration.allowed_origins.first)
58
+
59
+ creation_options = WebAuthn::Credential.options_for_create(
60
+ user: { id: @user.webauthn_id, name: @user.email_address },
61
+ authenticator_selection: { resident_key: "discouraged", user_verification: "discouraged" }
62
+ )
63
+ create_options = client.create(challenge: creation_options.challenge)
64
+ credential = WebAuthn::Credential.from_create(create_options)
65
+
66
+
67
+ WebauthnCredential.passkey.create!(
68
+ nickname: "My Security Key",
69
+ user: @user,
70
+ external_id: credential.id,
71
+ public_key: credential.public_key,
72
+ sign_count: 0
73
+ )
74
+
75
+ post session_path, params: { email_address: @user.email_address, password: "password" }
76
+
77
+ post get_options_second_factor_authentication_url
78
+ challenge = session[:current_authentication][:challenge]
79
+
80
+ public_key_credential = client.get(challenge: challenge, user_verified: false)
81
+
82
+ post second_factor_authentication_url, params: {
83
+ session: {
84
+ public_key_credential: public_key_credential.to_json
85
+ }
86
+ }
87
+
88
+ assert_redirected_to root_path
89
+ assert_nil session[:current_authentication]
90
+ end
91
+
92
+ test "create with WebAuthn error" do
93
+ post session_path, params: { email_address: @user.email_address, password: "password" }
94
+
95
+ post get_options_second_factor_authentication_url
96
+
97
+ public_key_credential = @client.get(
98
+ user_verified: false
99
+ )
100
+
101
+ post second_factor_authentication_url, params: {
102
+ session: {
103
+ public_key_credential: public_key_credential.to_json
104
+ }
105
+ }
106
+
107
+ assert_redirected_to new_second_factor_authentication_path
108
+ assert_match (/Verification failed/), flash[:alert]
109
+ assert_nil session[:current_authentication]
110
+ end
111
+
112
+ test "create with unrecognized credential" do
113
+ post session_path, params: { email_address: @user.email_address, password: "password" }
114
+
115
+ post get_options_second_factor_authentication_url
116
+ challenge = session[:current_authentication][:challenge]
117
+
118
+ public_key_credential = @client.get(challenge: challenge, user_verified: false)
119
+ public_key_credential["id"]= "invalid-id"
120
+
121
+ post second_factor_authentication_url, params: {
122
+ session: {
123
+ public_key_credential: public_key_credential.to_json
124
+ }
125
+ }
126
+
127
+ assert_redirected_to new_second_factor_authentication_path
128
+ assert_match (/Credential not recognized/), flash[:alert]
129
+ assert_nil session[:current_authentication]
130
+ end
131
+ end
@@ -0,0 +1,103 @@
1
+ require "test_helper"
2
+ require "webauthn/fake_client"
3
+
4
+ class SecondFactorWebauthnCredentialsControllerTest < ActionDispatch::IntegrationTest
5
+ setup do
6
+ @user = users(:one)
7
+ @client = WebAuthn::FakeClient.new(WebAuthn.configuration.allowed_origins.first)
8
+ end
9
+
10
+ test "create_options" do
11
+ sign_in_as @user
12
+ post create_options_second_factor_webauthn_credentials_url
13
+
14
+ assert_response :success
15
+ body = JSON.parse(response.body)
16
+ assert body["challenge"].present?
17
+ assert body["authenticatorSelection"]["residentKey"] == "discouraged"
18
+ assert body["authenticatorSelection"]["userVerification"] == "discouraged"
19
+
20
+ assert_equal session[:current_registration][:challenge], body["challenge"]
21
+ end
22
+
23
+ test "create_options unauthenticated" do
24
+ post create_options_second_factor_webauthn_credentials_url
25
+
26
+ assert_response :redirect
27
+ assert_redirected_to new_session_url
28
+ end
29
+
30
+ test "create" do
31
+ sign_in_as @user
32
+
33
+ post create_options_second_factor_webauthn_credentials_url
34
+ challenge = session[:current_registration][:challenge]
35
+
36
+ public_key_credential = @client.create(
37
+ challenge: challenge,
38
+ user_verified: false,
39
+ )
40
+
41
+ assert_difference("WebauthnCredential.second_factor.count", 1) do
42
+ post second_factor_webauthn_credentials_url, params: {
43
+ credential: {
44
+ nickname: "My Security Key",
45
+ public_key_credential: public_key_credential.to_json
46
+ }
47
+ }
48
+ end
49
+
50
+ assert_redirected_to root_path
51
+ assert_match (/Security Key registered successfully/), flash[:notice]
52
+ assert_nil session[:current_registration]
53
+ end
54
+
55
+ test "create with WebAuthn error" do
56
+ sign_in_as @user
57
+
58
+ post create_options_second_factor_webauthn_credentials_url
59
+
60
+ public_key_credential = @client.create(
61
+ user_verified: false,
62
+ )
63
+
64
+ assert_no_difference("WebauthnCredential.count") do
65
+ post second_factor_webauthn_credentials_url, params: {
66
+ credential: {
67
+ nickname: "My Security Key",
68
+ public_key_credential: public_key_credential.to_json
69
+ }
70
+ }
71
+ end
72
+
73
+ assert_redirected_to new_second_factor_webauthn_credential_path
74
+ assert_match (/Verification failed/), flash[:alert]
75
+ assert_nil session[:current_registration]
76
+ end
77
+
78
+ test "create unauthenticated" do
79
+ post second_factor_webauthn_credentials_url
80
+
81
+ assert_response :redirect
82
+ assert_redirected_to new_session_url
83
+ end
84
+
85
+ test "destroy" do
86
+ credential = WebauthnCredential.second_factor.create!(
87
+ user: @user,
88
+ nickname: "My Security Key",
89
+ external_id: "external_id",
90
+ public_key: "public_key",
91
+ sign_count: 0
92
+ )
93
+
94
+ sign_in_as @user
95
+
96
+ assert_difference("WebauthnCredential.second_factor.count", -1) do
97
+ delete second_factor_webauthn_credential_url(credential)
98
+ end
99
+
100
+ assert_redirected_to root_path
101
+ assert_match (/Security Key deleted successfully/), flash[:notice]
102
+ end
103
+ end
@@ -12,17 +12,16 @@ class WebauthnSessionsControllerTest < ActionDispatch::IntegrationTest
12
12
  create_options = @client.create(challenge: creation_options.challenge)
13
13
  credential = WebAuthn::Credential.from_create(create_options)
14
14
 
15
- WebauthnCredential.create!(
15
+ WebauthnCredential.passkey.create!(
16
16
  nickname: "My Passkey",
17
17
  user: @user,
18
18
  external_id: credential.id,
19
19
  public_key: credential.public_key,
20
20
  sign_count: 0,
21
- authentication_factor: 0
22
21
  )
23
22
  end
24
23
 
25
- test "should return get_options" do
24
+ test "get_options" do
26
25
  post get_options_webauthn_session_url
27
26
 
28
27
  assert_response :success
@@ -33,7 +32,7 @@ class WebauthnSessionsControllerTest < ActionDispatch::IntegrationTest
33
32
  assert_equal session[:current_authentication][:challenge], body["challenge"]
34
33
  end
35
34
 
36
- test "should create session with valid credential" do
35
+ test "create" do
37
36
  post get_options_webauthn_session_url
38
37
  challenge = session[:current_authentication][:challenge]
39
38
 
@@ -49,7 +48,7 @@ class WebauthnSessionsControllerTest < ActionDispatch::IntegrationTest
49
48
  assert_nil session[:current_authentication]
50
49
  end
51
50
 
52
- test "should not create session when there is a Webauthn error" do
51
+ test "create with WebAuthn error" do
53
52
  post get_options_webauthn_session_url
54
53
  challenge = session[:current_authentication][:challenge]
55
54
 
@@ -66,7 +65,7 @@ class WebauthnSessionsControllerTest < ActionDispatch::IntegrationTest
66
65
  assert_nil session[:current_authentication]
67
66
  end
68
67
 
69
- test "should not create session with unrecognized credential" do
68
+ test "create with unrecognized credential" do
70
69
  post get_options_webauthn_session_url
71
70
  challenge = session[:current_authentication][:challenge]
72
71
 
@@ -84,7 +83,7 @@ class WebauthnSessionsControllerTest < ActionDispatch::IntegrationTest
84
83
  assert_nil session[:current_authentication]
85
84
  end
86
85
 
87
- test "should not create session with a second factor credential" do
86
+ test "create with a second factor credential" do
88
87
  client = WebAuthn::FakeClient.new(WebAuthn.configuration.allowed_origins.first)
89
88
 
90
89
  creation_options = WebAuthn::Credential.options_for_create(
@@ -93,13 +92,12 @@ class WebauthnSessionsControllerTest < ActionDispatch::IntegrationTest
93
92
  create_options = client.create(challenge: creation_options.challenge)
94
93
  credential = WebAuthn::Credential.from_create(create_options)
95
94
 
96
- WebauthnCredential.create!(
95
+ WebauthnCredential.second_factor.create!(
97
96
  nickname: "Second Factor Key",
98
97
  user: @user,
99
98
  external_id: credential.id,
100
99
  public_key: credential.public_key,
101
100
  sign_count: 0,
102
- authentication_factor: 1
103
101
  )
104
102
 
105
103
  post get_options_webauthn_session_url
@@ -118,7 +116,7 @@ class WebauthnSessionsControllerTest < ActionDispatch::IntegrationTest
118
116
  assert_nil session[:current_authentication]
119
117
  end
120
118
 
121
- test "should destroy session" do
119
+ test "destroy" do
122
120
  delete webauthn_session_url
123
121
  assert_redirected_to new_session_path
124
122
  end
@@ -9,6 +9,8 @@ module TestUnit
9
9
  def create_controller_test_files
10
10
  template "test/controllers/passkeys_controller_test.rb"
11
11
  template "test/controllers/webauthn_sessions_controller_test.rb"
12
+ template "test/controllers/second_factor_authentications_controller_test.rb"
13
+ template "test/controllers/second_factor_webauthn_credentials_controller_test.rb"
12
14
  end
13
15
 
14
16
  def create_system_test_files
@@ -35,9 +35,9 @@ class SecondFactorAuthenticationsController < ApplicationController
35
35
  redirect_to after_authentication_url
36
36
  rescue WebAuthn::Error => e
37
37
  redirect_to new_second_factor_authentication_path, alert: "Verification failed: #{e.message}"
38
- ensure
39
- session.delete(:current_authentication)
40
38
  end
39
+ ensure
40
+ session.delete(:current_authentication)
41
41
  end
42
42
 
43
43
  private
@@ -57,6 +57,6 @@ class SecondFactorAuthenticationsController < ApplicationController
57
57
  end
58
58
 
59
59
  def current_authentication_user_id
60
- session[:current_authentication][:user_id] || session[:current_authentication]["user_id"]
60
+ session.dig(:current_authentication, :user_id) || session.dig(:current_authentication, "user_id")
61
61
  end
62
62
  end
@@ -40,9 +40,9 @@ class SecondFactorWebauthnCredentialsController < ApplicationController
40
40
  end
41
41
  rescue WebAuthn::Error => e
42
42
  redirect_to new_second_factor_webauthn_credential_path, alert: "Verification failed: #{e.message}"
43
- ensure
44
- session.delete(:current_registration)
45
43
  end
44
+ ensure
45
+ session.delete(:current_registration)
46
46
  end
47
47
 
48
48
  def destroy
@@ -8,7 +8,11 @@ end
8
8
 
9
9
  class WebauthnAuthenticationGenerator < ::Rails::Generators::Base
10
10
  include ActiveRecord::Generators::Migration
11
- include BundleHelper
11
+ if Rails.version >= "8.1"
12
+ include Rails::Generators::BundleHelper
13
+ else
14
+ include BundleHelper
15
+ end
12
16
 
13
17
  source_root File.expand_path("../templates", __FILE__)
14
18
 
@@ -54,9 +58,7 @@ class WebauthnAuthenticationGenerator < ::Rails::Generators::Base
54
58
  <<-RUBY.strip_heredoc.indent(4)
55
59
 
56
60
  def require_no_authentication
57
- if Current.user
58
- redirect_to root_path
59
- end
61
+ redirect_to root_path if find_session_by_cookie
60
62
  end
61
63
  RUBY
62
64
  end
@@ -1,5 +1,5 @@
1
1
  module Webauthn
2
2
  module Rails
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.1"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: webauthn-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cedarcode
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-09-26 00:00:00.000000000 Z
11
+ date: 2025-10-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -41,6 +41,8 @@ files:
41
41
  - lib/generators/erb/webauthn_authentication/templates/app/views/second_factor_webauthn_credentials/new.html.erb.tt
42
42
  - lib/generators/erb/webauthn_authentication/webauthn_authentication_generator.rb
43
43
  - lib/generators/test_unit/webauthn_authentication/templates/test/controllers/passkeys_controller_test.rb
44
+ - lib/generators/test_unit/webauthn_authentication/templates/test/controllers/second_factor_authentications_controller_test.rb
45
+ - lib/generators/test_unit/webauthn_authentication/templates/test/controllers/second_factor_webauthn_credentials_controller_test.rb
44
46
  - lib/generators/test_unit/webauthn_authentication/templates/test/controllers/webauthn_sessions_controller_test.rb
45
47
  - lib/generators/test_unit/webauthn_authentication/templates/test/system/manage_webauthn_credentials_test.rb
46
48
  - lib/generators/test_unit/webauthn_authentication/templates/test/test_helpers/virtual_authenticator_test_helper.rb