webauthn 2.5.2 → 3.0.0.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +0 -56
- data/.travis.yml +39 -0
- data/Appraisals +21 -0
- data/CHANGELOG.md +0 -51
- data/README.md +2 -5
- data/SECURITY.md +3 -6
- data/docs/u2f_migration.md +2 -3
- data/gemfiles/cose_head.gemfile +7 -0
- data/gemfiles/openssl_2_0.gemfile +7 -0
- data/gemfiles/openssl_2_1.gemfile +7 -0
- data/gemfiles/openssl_2_2.gemfile +7 -0
- data/gemfiles/openssl_head.gemfile +7 -0
- data/lib/cose/rsapkcs1_algorithm.rb +0 -7
- data/lib/webauthn/attestation_object.rb +9 -5
- data/lib/webauthn/attestation_statement/android_key.rb +4 -0
- data/lib/webauthn/attestation_statement/android_safetynet.rb +5 -1
- data/lib/webauthn/attestation_statement/base.rb +29 -21
- data/lib/webauthn/attestation_statement/none.rb +1 -7
- data/lib/webauthn/attestation_statement/packed.rb +1 -1
- data/lib/webauthn/attestation_statement/tpm.rb +2 -2
- data/lib/webauthn/attestation_statement.rb +3 -6
- data/lib/webauthn/authenticator_assertion_response.rb +4 -3
- data/lib/webauthn/authenticator_attestation_response.rb +10 -7
- data/lib/webauthn/authenticator_data/attested_credential_data.rb +10 -4
- data/lib/webauthn/authenticator_response.rb +8 -6
- data/lib/webauthn/configuration.rb +36 -38
- data/lib/webauthn/credential.rb +5 -4
- data/lib/webauthn/credential_creation_options.rb +0 -2
- data/lib/webauthn/credential_request_options.rb +0 -2
- data/lib/webauthn/fake_authenticator/authenticator_data.rb +1 -1
- data/lib/webauthn/fake_authenticator.rb +3 -11
- data/lib/webauthn/fake_client.rb +5 -12
- data/lib/webauthn/public_key_credential/creation_options.rb +3 -3
- data/lib/webauthn/public_key_credential/entity.rb +4 -3
- data/lib/webauthn/public_key_credential/options.rb +6 -9
- data/lib/webauthn/public_key_credential/request_options.rb +1 -1
- data/lib/webauthn/public_key_credential.rb +15 -8
- data/lib/webauthn/relying_party.rb +117 -0
- data/lib/webauthn/security_utils.rb +20 -0
- data/lib/webauthn/version.rb +1 -1
- data/script/ci/install-openssl +7 -0
- data/script/ci/install-ruby +13 -0
- data/webauthn.gemspec +7 -6
- metadata +61 -46
- data/.github/workflows/build.yml +0 -32
- data/.github/workflows/git.yml +0 -21
- data/docs/advanced_configuration.md +0 -174
- data/lib/webauthn/attestation_statement/apple.rb +0 -65
@@ -0,0 +1,13 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
set -e
|
4
|
+
|
5
|
+
source "$HOME/.rvm/scripts/rvm"
|
6
|
+
|
7
|
+
if [[ "$LIBSSL" == "1.0" ]]; then
|
8
|
+
rvm use --install $RB --autolibs=read-only --disable-binary
|
9
|
+
elif [[ "$LIBSSL" == "1.1" ]]; then
|
10
|
+
rvm use --install $RB --binary --fuzzy
|
11
|
+
fi
|
12
|
+
|
13
|
+
[[ "`ruby -ropenssl -e 'puts OpenSSL::OPENSSL_VERSION'`" =~ "OpenSSL $LIBSSL" ]] || { echo "Wrong libssl version"; exit 1; }
|
data/webauthn.gemspec
CHANGED
@@ -37,16 +37,17 @@ Gem::Specification.new do |spec|
|
|
37
37
|
spec.add_dependency "awrence", "~> 1.1"
|
38
38
|
spec.add_dependency "bindata", "~> 2.4"
|
39
39
|
spec.add_dependency "cbor", "~> 0.5.9"
|
40
|
-
spec.add_dependency "cose", "~> 1.
|
41
|
-
spec.add_dependency "openssl", "
|
40
|
+
spec.add_dependency "cose", "~> 1.0"
|
41
|
+
spec.add_dependency "openssl", "~> 2.0"
|
42
42
|
spec.add_dependency "safety_net_attestation", "~> 0.4.0"
|
43
|
-
spec.add_dependency "
|
43
|
+
spec.add_dependency "securecompare", "~> 1.0"
|
44
|
+
spec.add_dependency "tpm-key_attestation", "~> 0.9.0"
|
44
45
|
|
46
|
+
spec.add_development_dependency "appraisal", "~> 2.3.0"
|
45
47
|
spec.add_development_dependency "bundler", ">= 1.17", "< 3.0"
|
46
48
|
spec.add_development_dependency "byebug", "~> 11.0"
|
47
49
|
spec.add_development_dependency "rake", "~> 13.0"
|
48
50
|
spec.add_development_dependency "rspec", "~> 3.8"
|
49
|
-
spec.add_development_dependency "rubocop", "
|
50
|
-
spec.add_development_dependency "rubocop-
|
51
|
-
spec.add_development_dependency "rubocop-rspec", "~> 2.2.0"
|
51
|
+
spec.add_development_dependency "rubocop", "0.80.1"
|
52
|
+
spec.add_development_dependency "rubocop-rspec", "~> 1.38.1"
|
52
53
|
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: webauthn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0.alpha1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gonzalo Rodriguez
|
8
8
|
- Braulio Martinez
|
9
|
-
autorequire:
|
9
|
+
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2020-06-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: android_key_attestation
|
@@ -73,34 +73,28 @@ dependencies:
|
|
73
73
|
requirements:
|
74
74
|
- - "~>"
|
75
75
|
- !ruby/object:Gem::Version
|
76
|
-
version: '1.
|
76
|
+
version: '1.0'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
79
|
version_requirements: !ruby/object:Gem::Requirement
|
80
80
|
requirements:
|
81
81
|
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
|
-
version: '1.
|
83
|
+
version: '1.0'
|
84
84
|
- !ruby/object:Gem::Dependency
|
85
85
|
name: openssl
|
86
86
|
requirement: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
|
-
- - "
|
89
|
-
- !ruby/object:Gem::Version
|
90
|
-
version: '2.2'
|
91
|
-
- - "<"
|
88
|
+
- - "~>"
|
92
89
|
- !ruby/object:Gem::Version
|
93
|
-
version: '
|
90
|
+
version: '2.0'
|
94
91
|
type: :runtime
|
95
92
|
prerelease: false
|
96
93
|
version_requirements: !ruby/object:Gem::Requirement
|
97
94
|
requirements:
|
98
|
-
- - "
|
99
|
-
- !ruby/object:Gem::Version
|
100
|
-
version: '2.2'
|
101
|
-
- - "<"
|
95
|
+
- - "~>"
|
102
96
|
- !ruby/object:Gem::Version
|
103
|
-
version: '
|
97
|
+
version: '2.0'
|
104
98
|
- !ruby/object:Gem::Dependency
|
105
99
|
name: safety_net_attestation
|
106
100
|
requirement: !ruby/object:Gem::Requirement
|
@@ -115,20 +109,48 @@ dependencies:
|
|
115
109
|
- - "~>"
|
116
110
|
- !ruby/object:Gem::Version
|
117
111
|
version: 0.4.0
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: securecompare
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - "~>"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '1.0'
|
119
|
+
type: :runtime
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - "~>"
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '1.0'
|
118
126
|
- !ruby/object:Gem::Dependency
|
119
127
|
name: tpm-key_attestation
|
120
128
|
requirement: !ruby/object:Gem::Requirement
|
121
129
|
requirements:
|
122
130
|
- - "~>"
|
123
131
|
- !ruby/object:Gem::Version
|
124
|
-
version: 0.
|
132
|
+
version: 0.9.0
|
125
133
|
type: :runtime
|
126
134
|
prerelease: false
|
127
135
|
version_requirements: !ruby/object:Gem::Requirement
|
128
136
|
requirements:
|
129
137
|
- - "~>"
|
130
138
|
- !ruby/object:Gem::Version
|
131
|
-
version: 0.
|
139
|
+
version: 0.9.0
|
140
|
+
- !ruby/object:Gem::Dependency
|
141
|
+
name: appraisal
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - "~>"
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: 2.3.0
|
147
|
+
type: :development
|
148
|
+
prerelease: false
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - "~>"
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: 2.3.0
|
132
154
|
- !ruby/object:Gem::Dependency
|
133
155
|
name: bundler
|
134
156
|
requirement: !ruby/object:Gem::Requirement
|
@@ -195,44 +217,30 @@ dependencies:
|
|
195
217
|
name: rubocop
|
196
218
|
requirement: !ruby/object:Gem::Requirement
|
197
219
|
requirements:
|
198
|
-
- -
|
220
|
+
- - '='
|
199
221
|
- !ruby/object:Gem::Version
|
200
|
-
version:
|
222
|
+
version: 0.80.1
|
201
223
|
type: :development
|
202
224
|
prerelease: false
|
203
225
|
version_requirements: !ruby/object:Gem::Requirement
|
204
226
|
requirements:
|
205
|
-
- -
|
227
|
+
- - '='
|
206
228
|
- !ruby/object:Gem::Version
|
207
|
-
version:
|
208
|
-
- !ruby/object:Gem::Dependency
|
209
|
-
name: rubocop-rake
|
210
|
-
requirement: !ruby/object:Gem::Requirement
|
211
|
-
requirements:
|
212
|
-
- - "~>"
|
213
|
-
- !ruby/object:Gem::Version
|
214
|
-
version: 0.5.1
|
215
|
-
type: :development
|
216
|
-
prerelease: false
|
217
|
-
version_requirements: !ruby/object:Gem::Requirement
|
218
|
-
requirements:
|
219
|
-
- - "~>"
|
220
|
-
- !ruby/object:Gem::Version
|
221
|
-
version: 0.5.1
|
229
|
+
version: 0.80.1
|
222
230
|
- !ruby/object:Gem::Dependency
|
223
231
|
name: rubocop-rspec
|
224
232
|
requirement: !ruby/object:Gem::Requirement
|
225
233
|
requirements:
|
226
234
|
- - "~>"
|
227
235
|
- !ruby/object:Gem::Version
|
228
|
-
version:
|
236
|
+
version: 1.38.1
|
229
237
|
type: :development
|
230
238
|
prerelease: false
|
231
239
|
version_requirements: !ruby/object:Gem::Requirement
|
232
240
|
requirements:
|
233
241
|
- - "~>"
|
234
242
|
- !ruby/object:Gem::Version
|
235
|
-
version:
|
243
|
+
version: 1.38.1
|
236
244
|
description: |-
|
237
245
|
WebAuthn ruby server library ― Make your application a W3C Web Authentication conformant
|
238
246
|
Relying Party and allow your users to authenticate with U2F and FIDO2 authenticators.
|
@@ -243,11 +251,11 @@ executables: []
|
|
243
251
|
extensions: []
|
244
252
|
extra_rdoc_files: []
|
245
253
|
files:
|
246
|
-
- ".github/workflows/build.yml"
|
247
|
-
- ".github/workflows/git.yml"
|
248
254
|
- ".gitignore"
|
249
255
|
- ".rspec"
|
250
256
|
- ".rubocop.yml"
|
257
|
+
- ".travis.yml"
|
258
|
+
- Appraisals
|
251
259
|
- CHANGELOG.md
|
252
260
|
- CONTRIBUTING.md
|
253
261
|
- Gemfile
|
@@ -257,15 +265,18 @@ files:
|
|
257
265
|
- SECURITY.md
|
258
266
|
- bin/console
|
259
267
|
- bin/setup
|
260
|
-
- docs/advanced_configuration.md
|
261
268
|
- docs/u2f_migration.md
|
269
|
+
- gemfiles/cose_head.gemfile
|
270
|
+
- gemfiles/openssl_2_0.gemfile
|
271
|
+
- gemfiles/openssl_2_1.gemfile
|
272
|
+
- gemfiles/openssl_2_2.gemfile
|
273
|
+
- gemfiles/openssl_head.gemfile
|
262
274
|
- lib/cose/rsapkcs1_algorithm.rb
|
263
275
|
- lib/webauthn.rb
|
264
276
|
- lib/webauthn/attestation_object.rb
|
265
277
|
- lib/webauthn/attestation_statement.rb
|
266
278
|
- lib/webauthn/attestation_statement/android_key.rb
|
267
279
|
- lib/webauthn/attestation_statement/android_safetynet.rb
|
268
|
-
- lib/webauthn/attestation_statement/apple.rb
|
269
280
|
- lib/webauthn/attestation_statement/base.rb
|
270
281
|
- lib/webauthn/attestation_statement/fido_u2f.rb
|
271
282
|
- lib/webauthn/attestation_statement/fido_u2f/public_key.rb
|
@@ -302,8 +313,12 @@ files:
|
|
302
313
|
- lib/webauthn/public_key_credential/user_entity.rb
|
303
314
|
- lib/webauthn/public_key_credential_with_assertion.rb
|
304
315
|
- lib/webauthn/public_key_credential_with_attestation.rb
|
316
|
+
- lib/webauthn/relying_party.rb
|
317
|
+
- lib/webauthn/security_utils.rb
|
305
318
|
- lib/webauthn/u2f_migrator.rb
|
306
319
|
- lib/webauthn/version.rb
|
320
|
+
- script/ci/install-openssl
|
321
|
+
- script/ci/install-ruby
|
307
322
|
- webauthn.gemspec
|
308
323
|
homepage: https://github.com/cedarcode/webauthn-ruby
|
309
324
|
licenses:
|
@@ -312,7 +327,7 @@ metadata:
|
|
312
327
|
bug_tracker_uri: https://github.com/cedarcode/webauthn-ruby/issues
|
313
328
|
changelog_uri: https://github.com/cedarcode/webauthn-ruby/blob/master/CHANGELOG.md
|
314
329
|
source_code_uri: https://github.com/cedarcode/webauthn-ruby
|
315
|
-
post_install_message:
|
330
|
+
post_install_message:
|
316
331
|
rdoc_options: []
|
317
332
|
require_paths:
|
318
333
|
- lib
|
@@ -323,12 +338,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
323
338
|
version: '2.4'
|
324
339
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
325
340
|
requirements:
|
326
|
-
- - "
|
341
|
+
- - ">"
|
327
342
|
- !ruby/object:Gem::Version
|
328
|
-
version:
|
343
|
+
version: 1.3.1
|
329
344
|
requirements: []
|
330
|
-
rubygems_version: 3.
|
331
|
-
signing_key:
|
345
|
+
rubygems_version: 3.1.4
|
346
|
+
signing_key:
|
332
347
|
specification_version: 4
|
333
348
|
summary: WebAuthn ruby server library
|
334
349
|
test_files: []
|
data/.github/workflows/build.yml
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
# This workflow uses actions that are not certified by GitHub.
|
2
|
-
# They are provided by a third-party and are governed by
|
3
|
-
# separate terms of service, privacy policy, and support
|
4
|
-
# documentation.
|
5
|
-
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
-
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
-
|
8
|
-
name: build
|
9
|
-
|
10
|
-
on: push
|
11
|
-
|
12
|
-
jobs:
|
13
|
-
test:
|
14
|
-
runs-on: ubuntu-20.04
|
15
|
-
strategy:
|
16
|
-
fail-fast: false
|
17
|
-
matrix:
|
18
|
-
ruby:
|
19
|
-
- '3.1'
|
20
|
-
- '3.0'
|
21
|
-
- '2.7'
|
22
|
-
- '2.6'
|
23
|
-
- '2.5'
|
24
|
-
- '2.4'
|
25
|
-
- truffleruby
|
26
|
-
steps:
|
27
|
-
- uses: actions/checkout@v2
|
28
|
-
- uses: ruby/setup-ruby@v1
|
29
|
-
with:
|
30
|
-
ruby-version: ${{ matrix.ruby }}
|
31
|
-
bundler-cache: true
|
32
|
-
- run: bundle exec rake
|
data/.github/workflows/git.yml
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
# Syntax reference:
|
2
|
-
# https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions
|
3
|
-
name: Git Checks
|
4
|
-
|
5
|
-
on:
|
6
|
-
pull_request:
|
7
|
-
types: [opened, synchronize]
|
8
|
-
|
9
|
-
jobs:
|
10
|
-
# Fixup commits are OK in pull requests, but should generally be squashed
|
11
|
-
# before merging to master, e.g. using `git rebase -i --autosquash master`.
|
12
|
-
# See https://github.com/marketplace/actions/block-autosquash-commits
|
13
|
-
block-fixup:
|
14
|
-
runs-on: ubuntu-latest
|
15
|
-
|
16
|
-
steps:
|
17
|
-
- uses: actions/checkout@v2.0.0
|
18
|
-
- name: Block autosquash commits
|
19
|
-
uses: xt0rted/block-autosquash-commits-action@v2
|
20
|
-
with:
|
21
|
-
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
@@ -1,174 +0,0 @@
|
|
1
|
-
# Advanced Configuration
|
2
|
-
|
3
|
-
## Global vs Instance Based Configuration
|
4
|
-
|
5
|
-
Which approach suits best your needs will depend on the architecture of your application and how do your users need to register and authenticate to it.
|
6
|
-
|
7
|
-
If you have a multi-tenant application, or any application segmenation, where your users register and authenticate to each of these tenants or segments individuallly using different hostnames, or with different security needs, you need to go through [Instance Based Configuration](#instance-based-configuration).
|
8
|
-
|
9
|
-
However, if your application is served for just one hostname, or else if your users authenticate to only one subdmain (e.g. your application serves www.example.com and admin.example.com but all you users authenticate through auth.example.com) you can still rely on one [Global Configuration](../README.md#configuration).
|
10
|
-
|
11
|
-
If you are still not sure, or want to keep your options open, be aware that [Instance Based Configuration](#instance-based-configuration) is also a valid way of defining a single instance configuration and how you share such configuration across your application, it's up to you.
|
12
|
-
|
13
|
-
|
14
|
-
## Instance Based Configuration
|
15
|
-
|
16
|
-
Intead of the [Global Configuration](../README.md#configuration) you place in `config/initializers/webauthn.rb`,
|
17
|
-
you can now have an on-demand instance of `WebAuthn::RelyingParty` with the same configuration options, that
|
18
|
-
you can build anywhere in you application, in the following way:
|
19
|
-
|
20
|
-
```ruby
|
21
|
-
relying_party = WebAuthn::RelyingParty.new(
|
22
|
-
# This value needs to match `window.location.origin` evaluated by
|
23
|
-
# the User Agent during registration and authentication ceremonies.
|
24
|
-
origin: "https://admin.example.com"
|
25
|
-
|
26
|
-
# Relying Party name for display purposes
|
27
|
-
name: "Admin Site for Example Inc."
|
28
|
-
|
29
|
-
# Optionally configure a client timeout hint, in milliseconds.
|
30
|
-
# This hint specifies how long the browser should wait for any
|
31
|
-
# interaction with the user.
|
32
|
-
# This hint may be overridden by the browser.
|
33
|
-
# https://www.w3.org/TR/webauthn/#dom-publickeycredentialcreationoptions-timeout
|
34
|
-
# credential_options_timeout: 120_000
|
35
|
-
|
36
|
-
# You can optionally specify a different Relying Party ID
|
37
|
-
# (https://www.w3.org/TR/webauthn/#relying-party-identifier)
|
38
|
-
# if it differs from the default one.
|
39
|
-
#
|
40
|
-
# In this case the default would be "admin.example.com", but you can set it to
|
41
|
-
# the suffix "example.com"
|
42
|
-
#
|
43
|
-
# rp_id: "example.com"
|
44
|
-
|
45
|
-
# Configure preferred binary-to-text encoding scheme. This should match the encoding scheme
|
46
|
-
# used in your client-side (user agent) code before sending the credential to the server.
|
47
|
-
# Supported values: `:base64url` (default), `:base64` or `false` to disable all encoding.
|
48
|
-
#
|
49
|
-
# encoding: :base64url
|
50
|
-
|
51
|
-
# Possible values: "ES256", "ES384", "ES512", "PS256", "PS384", "PS512", "RS256", "RS384", "RS512", "RS1"
|
52
|
-
# Default: ["ES256", "PS256", "RS256"]
|
53
|
-
#
|
54
|
-
# algorithms: ["ES384"]
|
55
|
-
)
|
56
|
-
```
|
57
|
-
|
58
|
-
## Instance Based API
|
59
|
-
|
60
|
-
**DISCLAIMER: This API was released on version 3.0.0.alpha1 and is still under evaluation. Although it has been throughly tested and it is fully functional it might be changed until the final release of version 3.0.0.**
|
61
|
-
|
62
|
-
The explanation for each ceremony can be found in depth in [Credential Registration](../README.md#credential-registration) and [Credential Authentication](../README.md#credential-authentication) but if you choose this instance based approach to define your WebAuthn configurations and assuming `relying_party` is the result of an instance you get through `WebAuthn::RelytingParty.new(...)` the code in those explanations needs to be updated to:
|
63
|
-
|
64
|
-
### Credential Registration
|
65
|
-
|
66
|
-
#### Initiation phase
|
67
|
-
|
68
|
-
```ruby
|
69
|
-
# Generate and store the WebAuthn User ID the first time the user registers a credential
|
70
|
-
if !user.webauthn_id
|
71
|
-
user.update!(webauthn_id: WebAuthn.generate_user_id)
|
72
|
-
end
|
73
|
-
|
74
|
-
options = relying_party.options_for_create(
|
75
|
-
user: { id: user.webauthn_id, name: user.name },
|
76
|
-
exclude: user.credentials.map { |c| c.webauthn_id }
|
77
|
-
)
|
78
|
-
|
79
|
-
# Store the newly generated challenge somewhere so you can have it
|
80
|
-
# for the verification phase.
|
81
|
-
session[:creation_challenge] = options.challenge
|
82
|
-
|
83
|
-
# Send `options` back to the browser, so that they can be used
|
84
|
-
# to call `navigator.credentials.create({ "publicKey": options })`
|
85
|
-
#
|
86
|
-
# You can call `options.as_json` to get a ruby hash with a JSON representation if needed.
|
87
|
-
|
88
|
-
# If inside a Rails controller, `render json: options` will just work.
|
89
|
-
# I.e. it will encode and convert the options to JSON automatically.
|
90
|
-
|
91
|
-
# For your frontend code, you might find @github/webauthn-json npm package useful.
|
92
|
-
# Especially for handling the necessary decoding of the options, and sending the
|
93
|
-
# `PublicKeyCredential` object back to the server.
|
94
|
-
```
|
95
|
-
|
96
|
-
#### Verification phase
|
97
|
-
|
98
|
-
```ruby
|
99
|
-
# Assuming you're using @github/webauthn-json package to send the `PublicKeyCredential` object back
|
100
|
-
# in params[:publicKeyCredential]:
|
101
|
-
begin
|
102
|
-
webauthn_credential = relying_party.verify_registration(
|
103
|
-
params[:publicKeyCredential],
|
104
|
-
params[:create_challenge]
|
105
|
-
)
|
106
|
-
|
107
|
-
# Store Credential ID, Credential Public Key and Sign Count for future authentications
|
108
|
-
user.credentials.create!(
|
109
|
-
webauthn_id: webauthn_credential.id,
|
110
|
-
public_key: webauthn_credential.public_key,
|
111
|
-
sign_count: webauthn_credential.sign_count
|
112
|
-
)
|
113
|
-
rescue WebAuthn::Error => e
|
114
|
-
# Handle error
|
115
|
-
end
|
116
|
-
```
|
117
|
-
|
118
|
-
### Credential Authentication
|
119
|
-
|
120
|
-
#### Initiation phase
|
121
|
-
|
122
|
-
```ruby
|
123
|
-
options = relying_party.options_for_get(allow: user.credentials.map { |c| c.webauthn_id })
|
124
|
-
|
125
|
-
# Store the newly generated challenge somewhere so you can have it
|
126
|
-
# for the verification phase.
|
127
|
-
session[:authentication_challenge] = options.challenge
|
128
|
-
|
129
|
-
# Send `options` back to the browser, so that they can be used
|
130
|
-
# to call `navigator.credentials.get({ "publicKey": options })`
|
131
|
-
|
132
|
-
# You can call `options.as_json` to get a ruby hash with a JSON representation if needed.
|
133
|
-
|
134
|
-
# If inside a Rails controller, `render json: options` will just work.
|
135
|
-
# I.e. it will encode and convert the options to JSON automatically.
|
136
|
-
|
137
|
-
# For your frontend code, you might find @github/webauthn-json npm package useful.
|
138
|
-
# Especially for handling the necessary decoding of the options, and sending the
|
139
|
-
# `PublicKeyCredential` object back to the server.
|
140
|
-
```
|
141
|
-
|
142
|
-
#### Verification phase
|
143
|
-
|
144
|
-
```ruby
|
145
|
-
begin
|
146
|
-
# Assuming you're using @github/webauthn-json package to send the `PublicKeyCredential` object back
|
147
|
-
# in params[:publicKeyCredential]:
|
148
|
-
webauthn_credential, stored_credential = relying_party.verify_authentication(
|
149
|
-
params[:publicKeyCredential],
|
150
|
-
session[:authentication_challenge]
|
151
|
-
) do
|
152
|
-
# the returned object needs to respond to #public_key and #sign_count
|
153
|
-
user.credentials.find_by(webauthn_id: webauthn_credential.id)
|
154
|
-
end
|
155
|
-
|
156
|
-
# Update the stored credential sign count with the value from `webauthn_credential.sign_count`
|
157
|
-
stored_credential.update!(sign_count: webauthn_credential.sign_count)
|
158
|
-
|
159
|
-
# Continue with successful sign in or 2FA verification...
|
160
|
-
|
161
|
-
rescue WebAuthn::SignCountVerificationError => e
|
162
|
-
# Cryptographic verification of the authenticator data succeeded, but the signature counter was less then or equal
|
163
|
-
# to the stored value. This can have several reasons and depending on your risk tolerance you can choose to fail or
|
164
|
-
# pass authentication. For more information see https://www.w3.org/TR/webauthn/#sign-counter
|
165
|
-
rescue WebAuthn::Error => e
|
166
|
-
# Handle error
|
167
|
-
end
|
168
|
-
```
|
169
|
-
|
170
|
-
## Moving from Global to Instance Based Configuration
|
171
|
-
|
172
|
-
Adding a configuration for a new instance does not mean you need to get rid of your Global configuration. They can co-exist in your application and be both available for the different usages you might have. `WebAuthn.configuration.relying_party` will always return the global one while `WebAuthn::RelyingParty.new`, executed anywhere in your codebase, will allow you to create a different instance as you see the need. They will not collide and instead operate in isolation without any shared state.
|
173
|
-
|
174
|
-
The gem API described in the current [Usage](../README.md#usage) section for the [Global Configuration](../README.md#configuration) approach will still valid but the [Instance Based API](#instance-based-api) also works with the global `relying_party` that is maintain globally at `WebAuthn.configuration.relying_party`.
|
@@ -1,65 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "openssl"
|
4
|
-
require "webauthn/attestation_statement/base"
|
5
|
-
|
6
|
-
module WebAuthn
|
7
|
-
module AttestationStatement
|
8
|
-
class Apple < Base
|
9
|
-
# Source: https://www.apple.com/certificateauthority/private/
|
10
|
-
ROOT_CERTIFICATE =
|
11
|
-
OpenSSL::X509::Certificate.new(<<~PEM)
|
12
|
-
-----BEGIN CERTIFICATE-----
|
13
|
-
MIICEjCCAZmgAwIBAgIQaB0BbHo84wIlpQGUKEdXcTAKBggqhkjOPQQDAzBLMR8w
|
14
|
-
HQYDVQQDDBZBcHBsZSBXZWJBdXRobiBSb290IENBMRMwEQYDVQQKDApBcHBsZSBJ
|
15
|
-
bmMuMRMwEQYDVQQIDApDYWxpZm9ybmlhMB4XDTIwMDMxODE4MjEzMloXDTQ1MDMx
|
16
|
-
NTAwMDAwMFowSzEfMB0GA1UEAwwWQXBwbGUgV2ViQXV0aG4gUm9vdCBDQTETMBEG
|
17
|
-
A1UECgwKQXBwbGUgSW5jLjETMBEGA1UECAwKQ2FsaWZvcm5pYTB2MBAGByqGSM49
|
18
|
-
AgEGBSuBBAAiA2IABCJCQ2pTVhzjl4Wo6IhHtMSAzO2cv+H9DQKev3//fG59G11k
|
19
|
-
xu9eI0/7o6V5uShBpe1u6l6mS19S1FEh6yGljnZAJ+2GNP1mi/YK2kSXIuTHjxA/
|
20
|
-
pcoRf7XkOtO4o1qlcaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUJtdk
|
21
|
-
2cV4wlpn0afeaxLQG2PxxtcwDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA
|
22
|
-
MGQCMFrZ+9DsJ1PW9hfNdBywZDsWDbWFp28it1d/5w2RPkRX3Bbn/UbDTNLx7Jr3
|
23
|
-
jAGGiQIwHFj+dJZYUJR786osByBelJYsVZd2GbHQu209b5RCmGQ21gpSAk9QZW4B
|
24
|
-
1bWeT0vT
|
25
|
-
-----END CERTIFICATE-----
|
26
|
-
PEM
|
27
|
-
|
28
|
-
NONCE_EXTENSION_OID = "1.2.840.113635.100.8.2"
|
29
|
-
|
30
|
-
def valid?(authenticator_data, client_data_hash)
|
31
|
-
valid_nonce?(authenticator_data, client_data_hash) &&
|
32
|
-
matching_public_key?(authenticator_data) &&
|
33
|
-
trustworthy? &&
|
34
|
-
[attestation_type, attestation_trust_path]
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
def valid_nonce?(authenticator_data, client_data_hash)
|
40
|
-
extension = cred_cert&.find_extension(NONCE_EXTENSION_OID)
|
41
|
-
|
42
|
-
if extension
|
43
|
-
sequence = OpenSSL::ASN1.decode(extension.value_der)
|
44
|
-
|
45
|
-
sequence.tag == OpenSSL::ASN1::SEQUENCE &&
|
46
|
-
sequence.value.size == 1 &&
|
47
|
-
sequence.value[0].value[0].value ==
|
48
|
-
OpenSSL::Digest::SHA256.digest(authenticator_data.data + client_data_hash)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def attestation_type
|
53
|
-
WebAuthn::AttestationStatement::ATTESTATION_TYPE_ANONCA
|
54
|
-
end
|
55
|
-
|
56
|
-
def cred_cert
|
57
|
-
attestation_certificate
|
58
|
-
end
|
59
|
-
|
60
|
-
def default_root_certificates
|
61
|
-
[ROOT_CERTIFICATE]
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|