Skip to content

Commit 0e92b58

Browse files
Merge remote-tracking branch 'origin/master' into nt--remove-token-binding
2 parents 27897e9 + 0be0492 commit 0e92b58

36 files changed

Lines changed: 878 additions & 393 deletions
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Install OpenSSL
2+
3+
inputs:
4+
version:
5+
description: 'The version of OpenSSL to install'
6+
required: true
7+
8+
runs:
9+
using: 'composite'
10+
steps:
11+
- name: Restore cached OpenSSL library
12+
id: cache-openssl-restore
13+
uses: actions/cache/restore@v4
14+
with:
15+
path: ~/openssl
16+
key: openssl-${{ inputs.version }}
17+
18+
- name: Compile OpenSSL library
19+
if: steps.cache-openssl-restore.outputs.cache-hit != 'true'
20+
shell: bash
21+
run: |
22+
mkdir -p tmp/build-openssl && cd tmp/build-openssl
23+
case ${{ inputs.version }} in
24+
1.1.*)
25+
OPENSSL_COMMIT=OpenSSL_
26+
OPENSSL_COMMIT+=$(echo ${{ inputs.version }} | sed -e 's/\./_/g')
27+
git clone -b $OPENSSL_COMMIT --depth 1 https://github.com/openssl/openssl.git .
28+
echo "Git commit: $(git rev-parse HEAD)"
29+
./Configure --prefix=$HOME/openssl --libdir=lib linux-x86_64
30+
make depend && make -j4 && make install_sw
31+
;;
32+
3.*)
33+
OPENSSL_COMMIT=openssl-
34+
OPENSSL_COMMIT+=$(echo ${{ inputs.version }})
35+
git clone -b $OPENSSL_COMMIT --depth 1 https://github.com/openssl/openssl.git .
36+
echo "Git commit: $(git rev-parse HEAD)"
37+
if [[ ${{ inputs.version }} == 3.5* ]]; then
38+
./Configure --prefix=$HOME/openssl --libdir=lib enable-fips no-tests no-legacy
39+
else
40+
./Configure --prefix=$HOME/openssl --libdir=lib enable-fips no-tests
41+
fi
42+
make -j4 && make install_sw && make install_fips
43+
;;
44+
*)
45+
echo "Don't know how to build OpenSSL ${{ inputs.version }}"
46+
;;
47+
esac
48+
49+
- name: Save OpenSSL library cache
50+
if: steps.cache-openssl-restore.outputs.cache-hit != 'true'
51+
id: cache-openssl-save
52+
uses: actions/cache/save@v4
53+
with:
54+
path: ~/openssl
55+
key: ${{ steps.cache-openssl-restore.outputs.cache-primary-key }}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
name: Install Ruby
2+
3+
inputs:
4+
version:
5+
description: 'The version of Ruby to install'
6+
required: true
7+
openssl-version:
8+
description: 'The version of OpenSSL used'
9+
required: true
10+
11+
runs:
12+
using: 'composite'
13+
steps:
14+
- name: Restore cached Ruby installation
15+
id: cache-ruby-restore
16+
uses: actions/cache/restore@v4
17+
with:
18+
path: ~/rubies/ruby-${{ inputs.version }}
19+
key: ruby-${{ inputs.version }}-with-openssl-${{ inputs.openssl-version }}
20+
21+
- name: Install Ruby
22+
if: steps.cache-ruby-restore.outputs.cache-hit != 'true'
23+
shell: bash
24+
run: |
25+
latest_patch=$(curl -s https://cache.ruby-lang.org/pub/ruby/${{ inputs.version }}/ \
26+
| grep -oP "ruby-${{ inputs.version }}\.\d+\.tar\.xz" \
27+
| grep -oP "\d+(?=\.tar\.xz)" \
28+
| sort -V | tail -n 1)
29+
wget https://cache.ruby-lang.org/pub/ruby/${{ inputs.version }}/ruby-${{ inputs.version }}.${latest_patch}.tar.xz
30+
tar -xJvf ruby-${{ inputs.version }}.${latest_patch}.tar.xz
31+
cd ruby-${{ inputs.version }}.${latest_patch}
32+
./configure --prefix=$HOME/rubies/ruby-${{ inputs.version }} --with-openssl-dir=$HOME/openssl
33+
make
34+
make install
35+
36+
- name: Update PATH
37+
shell: bash
38+
run: |
39+
echo "~/rubies/ruby-${{ inputs.version }}/bin" >> $GITHUB_PATH
40+
41+
- name: Install Bundler
42+
shell: bash
43+
run: |
44+
case ${{ inputs.version }} in
45+
2.7* | 3.*)
46+
echo "Skipping Bundler installation for Ruby ${{ inputs.version }}"
47+
;;
48+
2.5* | 2.6*)
49+
gem install bundler -v '~> 2.3.0'
50+
;;
51+
*)
52+
echo "Don't know how to install Bundler for Ruby ${{ inputs.version }}"
53+
;;
54+
esac
55+
56+
- name: Save Ruby installation cache
57+
if: steps.cache-ruby-restore.outputs.cache-hit != 'true'
58+
id: cache-ruby-save
59+
uses: actions/cache/save@v4
60+
with:
61+
path: ~/rubies/ruby-${{ inputs.version }}
62+
key: ${{ steps.cache-ruby-restore.outputs.cache-primary-key }}
63+
64+
- name: Cache Bundler Install
65+
id: cache-bundler-restore
66+
uses: actions/cache/restore@v4
67+
env:
68+
GEMFILE: ${{ env.BUNDLE_GEMFILE || 'Gemfile' }}
69+
with:
70+
path: ~/bundler/cache
71+
key: bundler-ruby-${{ inputs.version }}-${{ inputs.openssl-version }}-${{ hashFiles(env.Gemfile, 'webauthn.gemspec') }}
72+
73+
- name: Install dependencies
74+
shell: bash
75+
run: |
76+
bundle config set --local path ~/bundler/cache
77+
bundle install
78+
79+
- name: Save Bundler Install cache
80+
id: cache-bundler-save
81+
uses: actions/cache/save@v4
82+
with:
83+
path: ~/bundler/cache
84+
key: ${{ steps.cache-bundler-restore.outputs.cache-primary-key }}

.github/workflows/build.yml

Lines changed: 42 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,34 +15,66 @@ on:
1515

1616
jobs:
1717
test:
18-
runs-on: ubuntu-20.04
18+
name: 'Test Ruby ${{ matrix.ruby }} with OpenSSL ${{ matrix.openssl }}'
19+
runs-on: ubuntu-24.04
1920
strategy:
2021
fail-fast: false
2122
matrix:
2223
ruby:
23-
- '3.4.0-preview2'
24+
- '3.4'
2425
- '3.3'
2526
- '3.2'
2627
- '3.1'
27-
- '3.0'
28-
- '2.7'
29-
- '2.6'
30-
- '2.5'
31-
- truffleruby
28+
openssl:
29+
- '3.5.3'
30+
- '3.4.2'
31+
- '3.3.4'
32+
- '3.2.5'
33+
- '3.1.8'
34+
- '3.0.17'
35+
- '1.1.1w'
36+
include:
37+
- ruby: truffleruby
38+
- ruby: '3.0'
39+
openssl: '1.1.1w'
40+
- ruby: '2.7'
41+
openssl: '1.1.1w'
42+
- ruby: '2.6'
43+
openssl: '1.1.1w'
44+
- ruby: '2.5'
45+
openssl: '1.1.1w'
46+
3247
steps:
33-
- uses: actions/checkout@v4
34-
- uses: ruby/setup-ruby@v1
48+
- uses: actions/checkout@v5
49+
50+
- name: Install OpenSSL
51+
if: matrix.ruby != 'truffleruby'
52+
uses: ./.github/actions/install-openssl
53+
with:
54+
version: ${{ matrix.openssl }}
55+
56+
- name: Manually set up Ruby
57+
if: matrix.ruby != 'truffleruby'
58+
uses: ./.github/actions/install-ruby
59+
with:
60+
version: ${{ matrix.ruby }}
61+
openssl-version: ${{ matrix.openssl }}
62+
63+
- name: Set up Ruby
64+
if: matrix.ruby == 'truffleruby'
65+
uses: ruby/setup-ruby@v1
3566
with:
3667
ruby-version: ${{ matrix.ruby }}
3768
bundler-cache: true
69+
3870
- run: bundle exec rspec
3971
env:
4072
RUBYOPT: ${{ startsWith(matrix.ruby, '3.4') && '--enable=frozen-string-literal' || '' }}
4173

4274
lint:
4375
runs-on: ubuntu-latest
4476
steps:
45-
- uses: actions/checkout@v4
77+
- uses: actions/checkout@v5
4678
- uses: ruby/setup-ruby@v1
4779
with:
4880
ruby-version: '3.3'

.github/workflows/git.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
runs-on: ubuntu-latest
1515

1616
steps:
17-
- uses: actions/checkout@v4
17+
- uses: actions/checkout@v5
1818
- name: Block autosquash commits
1919
uses: xt0rted/block-autosquash-commits-action@v2
2020
with:

.rubocop.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
require:
1+
plugins:
22
- rubocop-rspec
33
- rubocop-rake
44

CHANGELOG.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
11
# Changelog
22

3+
## Unreleased
4+
5+
### Fixed
6+
7+
- Update `RelyingParty#origin` and `WebAuthn.configuration.origin` to return the allowed origin if allowed origins has only one element.
8+
9+
## [v3.4.2] - 2025-09-22
10+
11+
### Added
12+
13+
- Updated `safety_net_attestation` dependency from `~> 0.4.0` to `~> 0.5.0`.
14+
15+
## [v3.4.1] - 2025-06-06
16+
17+
- Avoid requiring `base64` as it's not a direct dependency. [#459](https://github.com/cedarcode/webauthn-ruby/pull/459)[@santiagorodriguez96]
18+
19+
## [v3.4.0] - 2025-02-17
20+
21+
- Added support for Webauthn.config and RelayingParty to accept multiple allowed_origins. [#431](https://github.com/cedarcode/webauthn-ruby/pull/431)[@obroshnij]
22+
23+
## [v3.3.0] - 2025-02-06
24+
25+
### Added
26+
27+
- Updated `tpm-key_attestation` dependency from `~> 0.12.0` to `~> 0.14.0`. [#449](https://github.com/cedarcode/webauthn-ruby/pull/449) [@brauliomartinezlm], [@nicolastemciuc]
28+
329
## [v3.2.2] - 2024-11-14
430

531
### Fixed
@@ -407,6 +433,13 @@ Note: Both additions should help making it compatible with Chrome for Android 70
407433
- `WebAuthn::AuthenticatorAttestationResponse.valid?` can be used to validate fido-u2f attestations returned by the browser
408434
- Works with ruby 2.5
409435

436+
[v3.4.2]: https://github.com/cedarcode/webauthn-ruby/compare/v3.4.1...v3.4.2/
437+
[v3.4.1]: https://github.com/cedarcode/webauthn-ruby/compare/v3.4.0...v3.4.1/
438+
[v3.4.0]: https://github.com/cedarcode/webauthn-ruby/compare/v3.3.0...v3.4.0/
439+
[v3.3.0]: https://github.com/cedarcode/webauthn-ruby/compare/v3.2.2...v3.3.0/
440+
[v3.2.2]: https://github.com/cedarcode/webauthn-ruby/compare/v3.2.1...v3.2.2/
441+
[v3.2.1]: https://github.com/cedarcode/webauthn-ruby/compare/v3.2.0...v3.2.1/
442+
[v3.2.0]: https://github.com/cedarcode/webauthn-ruby/compare/v3.1.0...v3.2.0/
410443
[v3.1.0]: https://github.com/cedarcode/webauthn-ruby/compare/v3.0.0...v3.1.0/
411444
[v3.0.0]: https://github.com/cedarcode/webauthn-ruby/compare/2-stable...v3.0.0/
412445
[v3.0.0.alpha2]: https://github.com/cedarcode/webauthn-ruby/compare/2-stable...v3.0.0.alpha2/

README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
__Note__: You are viewing the README for the development version of webauthn-ruby.
2-
For the current release version see https://github.com/cedarcode/webauthn-ruby/blob/2-stable/README.md.
3-
41
# webauthn-ruby
52

63
![banner](assets/webauthn-ruby.png)
@@ -104,7 +101,8 @@ For a Rails application this would go in `config/initializers/webauthn.rb`.
104101
WebAuthn.configure do |config|
105102
# This value needs to match `window.location.origin` evaluated by
106103
# the User Agent during registration and authentication ceremonies.
107-
config.origin = "https://auth.example.com"
104+
# Multiple origins can be used when needed. Using more than one will imply you MUST configure rp_id explicitely. If you need your credentials to be bound to a single origin but you have more than one tenant, please see [our Advanced Configuration section](https://github.com/cedarcode/webauthn-ruby/blob/master/docs/advanced_configuration.md) instead of adding multiple origins.
105+
config.allowed_origins = ["https://auth.example.com"]
108106

109107
# Relying Party name for display purposes
110108
config.rp_name = "Example Inc."

docs/advanced_configuration.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,25 @@
44

55
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.
66

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).
7+
If you have a multi-tenant application, or any application segmentation, where your users register and authenticate to each of these tenants or segments individually using different hostnames, or with different security needs, you need to go through [Instance Based Configuration](#instance-based-configuration).
88

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).
9+
However, if your application is served for just one hostname, or else if your users authenticate to only one subdomain (e.g. your application serves www.example.com and admin.example.com but all your users authenticate through auth.example.com) you can still rely on one [Global Configuration](../README.md#configuration).
1010

1111
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.
1212

1313

1414
## Instance Based Configuration
1515

16-
Intead of the [Global Configuration](../README.md#configuration) you place in `config/initializers/webauthn.rb`,
16+
Instead of the [Global Configuration](../README.md#configuration) you place in `config/initializers/webauthn.rb`,
1717
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:
18+
you can build anywhere in your application, in the following way:
1919

2020
```ruby
2121
relying_party = WebAuthn::RelyingParty.new(
2222
# This value needs to match `window.location.origin` evaluated by
2323
# the User Agent during registration and authentication ceremonies.
24-
origin: "https://admin.example.com",
24+
# Multiple origins can be used when needed. Using more than one will imply you MUST configure rp_id explicitely. If you need your credentials to be bound to a single origin but you have more than one tenant, please see [our Advanced Configuration section](https://github.com/cedarcode/webauthn-ruby/blob/master/docs/advanced_configuration.md) instead of adding multiple origins.
25+
allowed_origins: ["https://admin.example.com"],
2526

2627
# Relying Party name for display purposes
2728
name: "Admin Site for Example Inc."
@@ -57,7 +58,7 @@ Intead of the [Global Configuration](../README.md#configuration) you place in `c
5758

5859
## Instance Based API
5960

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+
**DISCLAIMER: This API was released on version 3.0.0.alpha1 and is still under evaluation. Although it has been thoroughly tested and it is fully functional it might be changed until the final release of version 3.0.0.**
6162

6263
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::RelyingParty.new(...)` the code in those explanations needs to be updated to:
6364

@@ -101,7 +102,7 @@ session[:creation_challenge] = options.challenge
101102
begin
102103
webauthn_credential = relying_party.verify_registration(
103104
params[:publicKeyCredential],
104-
params[:create_challenge]
105+
session[:creation_challenge]
105106
)
106107

107108
# Store Credential ID, Credential Public Key and Sign Count for future authentications
@@ -159,7 +160,7 @@ begin
159160
# Continue with successful sign in or 2FA verification...
160161

161162
rescue WebAuthn::SignCountVerificationError => e
162-
# Cryptographic verification of the authenticator data succeeded, but the signature counter was less then or equal
163+
# Cryptographic verification of the authenticator data succeeded, but the signature counter was less than or equal
163164
# to the stored value. This can have several reasons and depending on your risk tolerance you can choose to fail or
164165
# pass authentication. For more information see https://www.w3.org/TR/webauthn/#sign-counter
165166
rescue WebAuthn::Error => e
@@ -171,4 +172,4 @@ end
171172

172173
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.
173174

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`.
175+
The gem API described in the current [Usage](../README.md#usage) section for the [Global Configuration](../README.md#configuration) approach will still be valid but the [Instance Based API](#instance-based-api) also works with the global `relying_party` that is maintained globally at `WebAuthn.configuration.relying_party`.

lib/webauthn/attestation_statement/base.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ def attestation_certificate
4646
end
4747

4848
def attestation_certificate_key_id
49-
attestation_certificate.subject_key_identifier&.unpack("H*")&.[](0)
49+
attestation_certificate.subject_key_identifier&.unpack1("H*")
5050
end
5151

5252
private

0 commit comments

Comments
 (0)