omniauth-auth0 2.3.1 → 2.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 735b9218b77206e4e3c8d2a3e0aa983fa4b5fc41591a593ea681d5bcaa8c12d6
4
- data.tar.gz: d66683b025e4dbe28c3986e5f271b71087145d1f3b9f8c425b89bc139a77750f
3
+ metadata.gz: baf9ee46a227506a7f43d571bbf9b6afd3639f8bf83cb32cc8ef8a55af5041ab
4
+ data.tar.gz: a7529eca35711ab1217e9946c4c5872a4a8d5296773bc49425f63a2792bf40f0
5
5
  SHA512:
6
- metadata.gz: '02885a905400e376c738b6fd01892e372902f8394b10d5c1436d6105127e28055827c4ca2b09f3d31df0d163dd01ea8f5dd8d53fdf2f8fc1201ba116cdcb6b9f'
7
- data.tar.gz: e7b50a03c9ed21e981d89a4fa36f220da3bac9e963999fc56762ada02b19873e3452d6084198595924fa4e2be8480bfac6150e56d4536c5cf93b53369ded3253
6
+ metadata.gz: b315bd912671314bcb0fd2f3bb19878ee1029fe3738c7887b732c3c346794011e23c26a39d0d77f9644846c302480469d00d1b307d6d72e6be61d9a6aa8b9e37
7
+ data.tar.gz: e29b464b82e4d4c3ef8870d06e1eee5f279afaf3330afa8a1167dbf4bfe0795ae4c966006c8bc6ebd993ac579ffe1cbd9cecb4aceb827a153af9e651020ea8cd
data/.circleci/config.yml CHANGED
@@ -2,7 +2,7 @@ version: 2.1
2
2
  jobs:
3
3
  run-tests:
4
4
  docker:
5
- - image: circleci/ruby:2.4.6-jessie
5
+ - image: circleci/ruby:2.5.7-buster
6
6
  steps:
7
7
  - checkout
8
8
  - restore_cache:
@@ -10,12 +10,6 @@ jobs:
10
10
  - gems-v2-{{ checksum "Gemfile.lock" }}
11
11
  - gems-v2-
12
12
  - run: bundle check || bundle install
13
- - persist_to_workspace:
14
- root: .
15
- paths:
16
- - Gemfile
17
- - Gemfile.lock
18
- - .snyk
19
13
  - save_cache:
20
14
  key: gems-v2--{{ checksum "Gemfile.lock" }}
21
15
  paths:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Change Log
2
2
 
3
+ ## [v2.4.1](https://github.com/auth0/omniauth-auth0/tree/v2.4.1) (2020-10-08)
4
+
5
+ [Full Changelog](https://github.com/auth0/omniauth-auth0/compare/v2.4.0...v2.4.1)
6
+
7
+ **Fixed**
8
+ - Verify the JWT Signature [\#109](https://github.com/auth0/omniauth-auth0/pull/109) ([jimmyjames](https://github.com/jimmyjames))
9
+
10
+
11
+ ## [v2.4.0](https://github.com/auth0/omniauth-auth0/tree/v2.4.0) (2020-09-22)
12
+
13
+ [Full Changelog](https://github.com/auth0/omniauth-auth0/compare/v2.3.1...v2.4.0)
14
+
15
+ **Security**
16
+ - Bump rack from 2.2.2 to 2.2.3 [\#107](https://github.com/auth0/omniauth-auth0/pull/107) ([dependabot](https://github.com/dependabot))
17
+ - Update dependencies [\#100](https://github.com/auth0/omniauth-auth0/pull/100) ([Albalmaceda](https://github.com/Albalmaceda))
18
+
19
+ **Added**
20
+ - Add support for screen_hint=signup param [\#103](https://github.com/auth0/omniauth-auth0/pull/103) ([bbean86](https://github.com/bbean86))
21
+ - Add support for `connection_scope` in params [\#99](https://github.com/auth0/omniauth-auth0/pull/99) ([felixclack](https://github.com/felixclack))
22
+
23
+
3
24
  ## [v2.3.1](https://github.com/auth0/omniauth-auth0/tree/v2.3.1) (2020-03-27)
4
25
 
5
26
  [Full Changelog](https://github.com/auth0/omniauth-auth0/compare/v2.3.0...v2.3.1)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- omniauth-auth0 (2.3.1)
4
+ omniauth-auth0 (2.4.1)
5
5
  omniauth-oauth2 (~> 1.5)
6
6
 
7
7
  GEM
@@ -9,22 +9,20 @@ GEM
9
9
  specs:
10
10
  addressable (2.7.0)
11
11
  public_suffix (>= 2.0.2, < 5.0)
12
- ast (2.4.0)
13
- codecov (0.1.16)
12
+ ast (2.4.1)
13
+ codecov (0.2.11)
14
14
  json
15
15
  simplecov
16
- url
17
- coderay (1.1.2)
18
- crack (0.4.3)
19
- safe_yaml (~> 1.0.0)
16
+ coderay (1.1.3)
17
+ crack (0.4.4)
20
18
  daemons (1.3.1)
21
- diff-lcs (1.3)
19
+ diff-lcs (1.4.4)
22
20
  docile (1.3.2)
23
- dotenv (2.7.5)
21
+ dotenv (2.7.6)
24
22
  eventmachine (1.2.7)
25
- faraday (1.0.0)
23
+ faraday (1.0.1)
26
24
  multipart-post (>= 1.2, < 3)
27
- ffi (1.12.2)
25
+ ffi (1.13.1)
28
26
  formatador (0.2.5)
29
27
  gem-release (2.1.1)
30
28
  guard (2.16.2)
@@ -43,16 +41,15 @@ GEM
43
41
  rspec (>= 2.99.0, < 4.0)
44
42
  hashdiff (1.0.1)
45
43
  hashie (4.1.0)
46
- jaro_winkler (1.5.4)
47
- json (2.3.0)
48
- jwt (2.2.1)
44
+ json (2.3.1)
45
+ jwt (2.2.2)
49
46
  listen (3.1.5)
50
47
  rb-fsevent (~> 0.9, >= 0.9.4)
51
48
  rb-inotify (~> 0.9, >= 0.9.7)
52
49
  ruby_dep (~> 1.2)
53
- lumberjack (1.2.4)
50
+ lumberjack (1.2.8)
54
51
  method_source (1.0.0)
55
- multi_json (1.14.1)
52
+ multi_json (1.15.0)
56
53
  multi_xml (0.6.0)
57
54
  multipart-post (2.1.1)
58
55
  mustermann (1.1.1)
@@ -70,63 +67,66 @@ GEM
70
67
  omniauth (1.9.1)
71
68
  hashie (>= 3.4.6)
72
69
  rack (>= 1.6.2, < 3)
73
- omniauth-oauth2 (1.6.0)
74
- oauth2 (~> 1.1)
70
+ omniauth-oauth2 (1.7.0)
71
+ oauth2 (~> 1.4)
75
72
  omniauth (~> 1.9)
76
- parallel (1.19.1)
77
- parser (2.7.0.5)
78
- ast (~> 2.4.0)
79
- pry (0.13.0)
73
+ parallel (1.19.2)
74
+ parser (2.7.2.0)
75
+ ast (~> 2.4.1)
76
+ pry (0.13.1)
80
77
  coderay (~> 1.1)
81
78
  method_source (~> 1.0)
82
- public_suffix (4.0.3)
83
- rack (2.2.2)
84
- rack-protection (2.0.8.1)
79
+ public_suffix (4.0.6)
80
+ rack (2.2.3)
81
+ rack-protection (2.1.0)
85
82
  rack
86
83
  rack-test (1.1.0)
87
84
  rack (>= 1.0, < 3)
88
85
  rainbow (3.0.0)
89
86
  rake (13.0.1)
90
- rb-fsevent (0.10.3)
87
+ rb-fsevent (0.10.4)
91
88
  rb-inotify (0.10.1)
92
89
  ffi (~> 1.0)
90
+ regexp_parser (1.8.1)
93
91
  rexml (3.2.4)
94
92
  rspec (3.9.0)
95
93
  rspec-core (~> 3.9.0)
96
94
  rspec-expectations (~> 3.9.0)
97
95
  rspec-mocks (~> 3.9.0)
98
- rspec-core (3.9.1)
99
- rspec-support (~> 3.9.1)
100
- rspec-expectations (3.9.1)
96
+ rspec-core (3.9.3)
97
+ rspec-support (~> 3.9.3)
98
+ rspec-expectations (3.9.2)
101
99
  diff-lcs (>= 1.2.0, < 2.0)
102
100
  rspec-support (~> 3.9.0)
103
101
  rspec-mocks (3.9.1)
104
102
  diff-lcs (>= 1.2.0, < 2.0)
105
103
  rspec-support (~> 3.9.0)
106
- rspec-support (3.9.2)
107
- rubocop (0.80.1)
108
- jaro_winkler (~> 1.5.1)
104
+ rspec-support (3.9.3)
105
+ rubocop (0.93.0)
109
106
  parallel (~> 1.10)
110
- parser (>= 2.7.0.1)
107
+ parser (>= 2.7.1.5)
111
108
  rainbow (>= 2.2.2, < 4.0)
109
+ regexp_parser (>= 1.8)
112
110
  rexml
111
+ rubocop-ast (>= 0.6.0)
113
112
  ruby-progressbar (~> 1.7)
114
- unicode-display_width (>= 1.4.0, < 1.7)
113
+ unicode-display_width (>= 1.4.0, < 2.0)
114
+ rubocop-ast (0.7.1)
115
+ parser (>= 2.7.1.5)
115
116
  ruby-progressbar (1.10.1)
116
117
  ruby2_keywords (0.0.2)
117
118
  ruby_dep (1.5.0)
118
- safe_yaml (1.0.5)
119
119
  shellany (0.0.1)
120
120
  shotgun (0.9.2)
121
121
  rack (>= 1.0)
122
- simplecov (0.18.5)
122
+ simplecov (0.19.0)
123
123
  docile (~> 1.1)
124
124
  simplecov-html (~> 0.11)
125
- simplecov-html (0.12.2)
126
- sinatra (2.0.8.1)
125
+ simplecov-html (0.12.3)
126
+ sinatra (2.1.0)
127
127
  mustermann (~> 1.0)
128
- rack (~> 2.0)
129
- rack-protection (= 2.0.8.1)
128
+ rack (~> 2.2)
129
+ rack-protection (= 2.1.0)
130
130
  tilt (~> 2.0)
131
131
  thin (1.7.2)
132
132
  daemons (~> 1.0, >= 1.0.9)
@@ -134,9 +134,8 @@ GEM
134
134
  rack (>= 1, < 3)
135
135
  thor (1.0.1)
136
136
  tilt (2.0.10)
137
- unicode-display_width (1.6.1)
138
- url (0.3.2)
139
- webmock (3.8.3)
137
+ unicode-display_width (1.7.0)
138
+ webmock (3.9.1)
140
139
  addressable (>= 2.3.6)
141
140
  crack (>= 0.3.2)
142
141
  hashdiff (>= 0.4.0, < 2.0.0)
data/README.md CHANGED
@@ -1,13 +1,14 @@
1
1
  # OmniAuth Auth0
2
2
 
3
- An [OmniAuth](https://github.com/intridea/omniauth) strategy for authenticating with [Auth0](https://auth0.com). This strategy is based on the [OmniAuth OAuth2](https://github.com/omniauth/omniauth-oauth2) strategy.
3
+ An [OmniAuth](https://github.com/intridea/omniauth) strategy for authenticating with [Auth0](https://auth0.com). This strategy is based on the [OmniAuth OAuth2](https://github.com/omniauth/omniauth-oauth2) strategy.
4
4
 
5
- **Important security note:** The parent library for this strategy currently has an unresolved security issue. Please see the discussion, including mitigations for Rails and non-Rails applications, [here](https://github.com/auth0/omniauth-auth0/issues/82).
5
+ > :warning: **Important security note:** This solution uses a 3rd party library with an unresolved [security issue(s)](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-9284). Please review the details of the vulnerability, including [Auth0](https://github.com/auth0/omniauth-auth0/issues/82 ) and other recommended [mitigations](https://github.com/omniauth/omniauth/wiki/Resolving-CVE-2015-9284), before implementing the solution.
6
6
 
7
7
  [![CircleCI](https://img.shields.io/circleci/project/github/auth0/omniauth-auth0/master.svg)](https://circleci.com/gh/auth0/omniauth-auth0)
8
8
  [![codecov](https://codecov.io/gh/auth0/omniauth-auth0/branch/master/graph/badge.svg)](https://codecov.io/gh/auth0/omniauth-auth0)
9
9
  [![Gem Version](https://badge.fury.io/rb/omniauth-auth0.svg)](https://badge.fury.io/rb/omniauth-auth0)
10
10
  [![MIT licensed](https://img.shields.io/dub/l/vibe-d.svg?style=flat)](https://github.com/auth0/omniauth-auth0/blob/master/LICENSE)
11
+ [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Fomniauth-auth0.svg?type=shield)](https://app.fossa.com/projects/git%2Bgithub.com%2Fauth0%2Fomniauth-auth0?ref=badge_shield)
11
12
 
12
13
  ## Table of Contents
13
14
 
@@ -45,7 +46,7 @@ Then install:
45
46
  $ bundle install
46
47
  ```
47
48
 
48
- See our [contributing guide](CONTRIBUTING.md) for information on local installation for development.
49
+ See our [contributing guide](CONTRIBUTING.md) for information on local installation for development.
49
50
 
50
51
  ## Getting Started
51
52
 
@@ -63,7 +64,7 @@ All of these tasks and more are covered in our [Ruby on Rails Quickstart](https:
63
64
  To send additional parameters during login, you can specify them when you register the provider:
64
65
 
65
66
  ```ruby
66
- provider
67
+ provider
67
68
  :auth0,
68
69
  ENV['AUTH0_CLIENT_ID'],
69
70
  ENV['AUTH0_CLIENT_SECRET'],
@@ -121,6 +122,17 @@ The Auth0 strategy will provide the standard OmniAuth hash attributes:
121
122
  }
122
123
  ```
123
124
 
125
+ ### Query Parameter Options
126
+
127
+ In some scenarios, you may need to pass specific query parameters to `/authorize`. The following parameters are available to enable this:
128
+
129
+ - `connection`
130
+ - `connection_scope`
131
+ - `prompt`
132
+ - `screen_hint` (only relevant to New Universal Login Experience)
133
+
134
+ Simply pass these query parameters to your OmniAuth redirect endpoint to enable their behavior.
135
+
124
136
  ## Contribution
125
137
 
126
138
  We appreciate feedback and contribution to this repo! Before you get started, please see the following:
@@ -133,7 +145,7 @@ We appreciate feedback and contribution to this repo! Before you get started, pl
133
145
 
134
146
  - Use [Community](https://community.auth0.com/) for usage, questions, specific cases.
135
147
  - Use [Issues](https://github.com/auth0/omniauth-auth0/issues) here for code-level support and bug reports.
136
- - Paid customers can use [Support](https://support.auth0.com/) to submit a trouble ticket for production-affecting issues.
148
+ - Paid customers can use [Support](https://support.auth0.com/) to submit a trouble ticket for production-affecting issues.
137
149
 
138
150
  ## Vulnerability Reporting
139
151
 
@@ -155,3 +167,6 @@ Auth0 helps you to easily:
155
167
  ## License
156
168
 
157
169
  The OmniAuth Auth0 strategy is licensed under MIT - [LICENSE](LICENSE)
170
+
171
+
172
+ [![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fauth0%2Fomniauth-auth0.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fauth0%2Fomniauth-auth0?ref=badge_large)
@@ -1,5 +1,5 @@
1
1
  module OmniAuth
2
2
  module Auth0
3
- VERSION = '2.3.1'.freeze
3
+ VERSION = '2.4.1'.freeze
4
4
  end
5
5
  end
@@ -28,17 +28,24 @@ module OmniAuth
28
28
  @client_secret = options.client_secret
29
29
  end
30
30
 
31
+ # Verify a token's signature. Only tokens signed with the RS256 or HS256 signatures are supported.
32
+ # @return array - The token's key and signing algorithm
31
33
  def verify_signature(jwt)
32
34
  head = token_head(jwt)
33
35
 
34
36
  # Make sure the algorithm is supported and get the decode key.
35
37
  if head[:alg] == 'RS256'
36
- [rs256_decode_key(head[:kid]), head[:alg]]
38
+ key, alg = [rs256_decode_key(head[:kid]), head[:alg]]
37
39
  elsif head[:alg] == 'HS256'
38
- [@client_secret, head[:alg]]
40
+ key, alg = [@client_secret, head[:alg]]
39
41
  else
40
42
  raise OmniAuth::Auth0::TokenValidationError.new("Signature algorithm of #{head[:alg]} is not supported. Expected the ID token to be signed with RS256 or HS256")
41
43
  end
44
+
45
+ # Call decode to verify the signature
46
+ JWT.decode(jwt, key, true, decode_opts(alg))
47
+
48
+ return key, alg
42
49
  end
43
50
 
44
51
  # Verify a JWT.
@@ -93,11 +100,27 @@ module OmniAuth
93
100
  end
94
101
 
95
102
  private
103
+ # Get the JWT decode options. We disable the claim checks since we perform our claim validation logic
104
+ # Docs: https://github.com/jwt/ruby-jwt
105
+ # @return hash
106
+ def decode_opts(alg)
107
+ {
108
+ algorithm: alg,
109
+ verify_expiration: false,
110
+ verify_iat: false,
111
+ verify_iss: false,
112
+ verify_aud: false,
113
+ verify_jti: false,
114
+ verify_subj: false,
115
+ verify_not_before: false
116
+ }
117
+ end
118
+
96
119
  def rs256_decode_key(kid)
97
120
  jwks_x5c = jwks_key(:x5c, kid)
98
121
 
99
122
  if jwks_x5c.nil?
100
- raise OmniAuth::Auth0::TokenValidationError.new("Could not find a public key for Key ID (kid) '#{kid}''")
123
+ raise OmniAuth::Auth0::TokenValidationError.new("Could not find a public key for Key ID (kid) '#{kid}'")
101
124
  end
102
125
 
103
126
  jwks_public_cert(jwks_x5c.first)
@@ -86,7 +86,7 @@ module OmniAuth
86
86
  def authorize_params
87
87
  params = super
88
88
  parsed_query = Rack::Utils.parse_query(request.query_string)
89
- %w[connection prompt].each do |key|
89
+ %w[connection connection_scope prompt screen_hint].each do |key|
90
90
  params[key] = parsed_query[key] if parsed_query.key?(key)
91
91
  end
92
92
 
@@ -94,7 +94,7 @@ module OmniAuth
94
94
  params[:nonce] = SecureRandom.hex
95
95
  # Generate leeway if none exists
96
96
  params[:leeway] = 60 unless params[:leeway]
97
-
97
+
98
98
  # Store authorize params in the session for token verification
99
99
  session['authorize_params'] = params
100
100
 
@@ -12,17 +12,17 @@ describe OmniAuth::Auth0::JWTValidator do
12
12
  let(:domain) { 'samples.auth0.com' }
13
13
  let(:future_timecode) { 32_503_680_000 }
14
14
  let(:past_timecode) { 303_912_000 }
15
- let(:jwks_kid) { 'NkJCQzIyQzRBMEU4NjhGNUU4MzU4RkY0M0ZDQzkwOUQ0Q0VGNUMwQg' }
15
+ let(:valid_jwks_kid) { 'NkJCQzIyQzRBMEU4NjhGNUU4MzU4RkY0M0ZDQzkwOUQ0Q0VGNUMwQg' }
16
16
 
17
17
  let(:rsa_private_key) do
18
18
  OpenSSL::PKey::RSA.generate 2048
19
19
  end
20
20
 
21
- let(:rsa_token_jwks) do
21
+ let(:valid_jwks) do
22
22
  {
23
23
  keys: [
24
24
  {
25
- kid: jwks_kid,
25
+ kid: valid_jwks_kid,
26
26
  x5c: [Base64.encode64(make_cert(rsa_private_key).to_der)]
27
27
  }
28
28
  ]
@@ -91,29 +91,29 @@ describe OmniAuth::Auth0::JWTValidator do
91
91
  end
92
92
  end
93
93
 
94
- describe 'JWT verifier jwks_key' do
94
+ describe 'JWT verifier jwks key parsing' do
95
95
  let(:jwt_validator) do
96
96
  make_jwt_validator
97
97
  end
98
98
 
99
99
  before do
100
- stub_jwks
100
+ stub_complete_jwks
101
101
  end
102
102
 
103
103
  it 'should return a key' do
104
- expect(jwt_validator.jwks_key(:alg, jwks_kid)).to eq('RS256')
104
+ expect(jwt_validator.jwks_key(:alg, valid_jwks_kid)).to eq('RS256')
105
105
  end
106
106
 
107
107
  it 'should return an x5c key' do
108
- expect(jwt_validator.jwks_key(:x5c, jwks_kid).length).to eq(1)
108
+ expect(jwt_validator.jwks_key(:x5c, valid_jwks_kid).length).to eq(1)
109
109
  end
110
110
 
111
111
  it 'should return nil if there is not key' do
112
- expect(jwt_validator.jwks_key(:auth0, jwks_kid)).to eq(nil)
112
+ expect(jwt_validator.jwks_key(:auth0, valid_jwks_kid)).to eq(nil)
113
113
  end
114
114
 
115
115
  it 'should return nil if the key ID is invalid' do
116
- expect(jwt_validator.jwks_key(:alg, "#{jwks_kid}_invalid")).to eq(nil)
116
+ expect(jwt_validator.jwks_key(:alg, "#{valid_jwks_kid}_invalid")).to eq(nil)
117
117
  end
118
118
  end
119
119
 
@@ -153,8 +153,24 @@ describe OmniAuth::Auth0::JWTValidator do
153
153
  end
154
154
 
155
155
  before do
156
- stub_jwks
157
- stub_dummy_jwks
156
+ stub_complete_jwks
157
+ stub_expected_jwks
158
+ end
159
+
160
+ it 'should fail when JWT is nil' do
161
+ expect do
162
+ jwt_validator.verify(nil)
163
+ end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and having_attributes({
164
+ message: "ID token is required but missing"
165
+ }))
166
+ end
167
+
168
+ it 'should fail when JWT is not well-formed' do
169
+ expect do
170
+ jwt_validator.verify('abc.123')
171
+ end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and having_attributes({
172
+ message: "ID token could not be decoded"
173
+ }))
158
174
  end
159
175
 
160
176
  it 'should fail with missing issuer' do
@@ -248,6 +264,39 @@ describe OmniAuth::Auth0::JWTValidator do
248
264
  }))
249
265
  end
250
266
 
267
+ it 'should pass when past expiration but within default leeway' do
268
+ exp = Time.now.to_i - 59
269
+ payload = {
270
+ iss: "https://#{domain}/",
271
+ sub: 'sub',
272
+ aud: client_id,
273
+ exp: exp,
274
+ iat: past_timecode
275
+ }
276
+
277
+ token = make_hs256_token(payload)
278
+ id_token = jwt_validator.verify(token)
279
+ expect(id_token['exp']).to eq(exp)
280
+ end
281
+
282
+ it 'should fail when past expiration and outside default leeway' do
283
+ exp = Time.now.to_i - 61
284
+ payload = {
285
+ iss: "https://#{domain}/",
286
+ sub: 'sub',
287
+ aud: client_id,
288
+ exp: exp,
289
+ iat: past_timecode
290
+ }
291
+
292
+ token = make_hs256_token(payload)
293
+ expect do
294
+ jwt_validator.verify(token)
295
+ end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and having_attributes({
296
+ message: "Expiration time (exp) claim error in the ID token; current time (#{Time.now}) is after expiration time (#{Time.at(exp + 60)})"
297
+ }))
298
+ end
299
+
251
300
  it 'should fail when missing iat' do
252
301
  payload = {
253
302
  iss: "https://#{domain}/",
@@ -377,6 +426,114 @@ describe OmniAuth::Auth0::JWTValidator do
377
426
  }))
378
427
  end
379
428
 
429
+ it 'should fail when “max_age” sent on the authentication request and this claim added the “max_age” value doesn’t represent a date in the future, outside the default leeway' do
430
+ now = Time.now.to_i
431
+ auth_time = now - 121
432
+ max_age = 60
433
+ payload = {
434
+ iss: "https://#{domain}/",
435
+ sub: 'sub',
436
+ aud: client_id,
437
+ exp: future_timecode,
438
+ iat: past_timecode,
439
+ auth_time: auth_time
440
+ }
441
+
442
+ token = make_hs256_token(payload)
443
+ expect do
444
+ jwt_validator.verify(token, { max_age: max_age })
445
+ # Time.at(auth_time + max_age + leeway
446
+ end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and having_attributes({
447
+ message: "Authentication Time (auth_time) claim in the ID token indicates that too much time has passed since the last end-user authentication. Current time (#{Time.now}) is after last auth time (#{Time.at(auth_time + max_age + 60)})"
448
+ }))
449
+ end
450
+
451
+ it 'should verify when “max_age” sent on the authentication request and this claim added the “max_age” value doesn’t represent a date in the future, outside the default leeway' do
452
+ now = Time.now.to_i
453
+ auth_time = now - 119
454
+ max_age = 60
455
+ payload = {
456
+ iss: "https://#{domain}/",
457
+ sub: 'sub',
458
+ aud: client_id,
459
+ exp: future_timecode,
460
+ iat: past_timecode,
461
+ auth_time: auth_time
462
+ }
463
+
464
+ token = make_hs256_token(payload)
465
+ id_token = jwt_validator.verify(token, { max_age: max_age })
466
+ expect(id_token['auth_time']).to eq(auth_time)
467
+ end
468
+
469
+ it 'should fail for RS256 token when kid is incorrect' do
470
+ domain = 'example.org'
471
+ sub = 'abc123'
472
+ payload = {
473
+ sub: sub,
474
+ exp: future_timecode,
475
+ iss: "https://#{domain}/",
476
+ iat: past_timecode,
477
+ aud: client_id
478
+ }
479
+ invalid_kid = 'invalid-kid'
480
+ token = make_rs256_token(payload, invalid_kid)
481
+ expect do
482
+ verified_token = make_jwt_validator(opt_domain: domain).verify(token)
483
+ end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and having_attributes({
484
+ message: "Could not find a public key for Key ID (kid) 'invalid-kid'"
485
+ }))
486
+ end
487
+
488
+ it 'should fail when RS256 token has invalid signature' do
489
+ domain = 'example.org'
490
+ sub = 'abc123'
491
+ payload = {
492
+ sub: sub,
493
+ exp: future_timecode,
494
+ iss: "https://#{domain}/",
495
+ iat: past_timecode,
496
+ aud: client_id
497
+ }
498
+ token = make_rs256_token(payload) + 'bad'
499
+ expect do
500
+ verified_token = make_jwt_validator(opt_domain: domain).verify(token)
501
+ end.to raise_error(an_instance_of(JWT::VerificationError).and having_attributes({
502
+ message: "Signature verification raised"
503
+ }))
504
+ end
505
+
506
+ it 'should fail when algorithm is not RS256 or HS256' do
507
+ payload = {
508
+ iss: "https://#{domain}/",
509
+ sub: 'abc123',
510
+ aud: client_id,
511
+ exp: future_timecode,
512
+ iat: past_timecode
513
+ }
514
+ token = JWT.encode payload, 'secret', 'HS384'
515
+ expect do
516
+ jwt_validator.verify(token)
517
+ end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and having_attributes({
518
+ message: "Signature algorithm of HS384 is not supported. Expected the ID token to be signed with RS256 or HS256"
519
+ }))
520
+ end
521
+
522
+ it 'should fail when HS256 token has invalid signature' do
523
+ payload = {
524
+ iss: "https://#{domain}/",
525
+ sub: 'abc123',
526
+ aud: client_id,
527
+ exp: future_timecode,
528
+ iat: past_timecode
529
+ }
530
+ token = make_hs256_token(payload, 'bad_secret')
531
+ expect do
532
+ # validator is configured to use "CLIENT_SECRET" by default
533
+ jwt_validator.verify(token)
534
+ end.to raise_error(an_instance_of(JWT::VerificationError))
535
+ end
536
+
380
537
  it 'should verify a valid HS256 token with multiple audiences' do
381
538
  audience = [
382
539
  client_id,
@@ -417,13 +574,44 @@ describe OmniAuth::Auth0::JWTValidator do
417
574
  exp: future_timecode,
418
575
  iss: "https://#{domain}/",
419
576
  iat: past_timecode,
420
- aud: client_id,
421
- kid: jwks_kid
577
+ aud: client_id
422
578
  }
423
579
  token = make_rs256_token(payload)
424
580
  verified_token = make_jwt_validator(opt_domain: domain).verify(token)
425
581
  expect(verified_token['sub']).to eq(sub)
426
582
  end
583
+
584
+ it 'should verify a HS256 JWT signature when calling verify signature directly' do
585
+ sub = 'abc123'
586
+ payload = {
587
+ iss: "https://#{domain}/",
588
+ sub: sub,
589
+ aud: client_id,
590
+ exp: future_timecode,
591
+ iat: past_timecode
592
+ }
593
+ token = make_hs256_token(payload)
594
+ verified_token_signature = jwt_validator.verify_signature(token)
595
+ expect(verified_token_signature[0]).to eq('CLIENT_SECRET')
596
+ expect(verified_token_signature[1]).to eq('HS256')
597
+ end
598
+
599
+ it 'should verify a RS256 JWT signature verify signature directly' do
600
+ domain = 'example.org'
601
+ sub = 'abc123'
602
+ payload = {
603
+ sub: sub,
604
+ exp: future_timecode,
605
+ iss: "https://#{domain}/",
606
+ iat: past_timecode,
607
+ aud: client_id
608
+ }
609
+ token = make_rs256_token(payload)
610
+ verified_token_signature = make_jwt_validator(opt_domain: domain).verify_signature(token)
611
+ expect(verified_token_signature.length).to be(2)
612
+ expect(verified_token_signature[0]).to be_a(OpenSSL::PKey::RSA)
613
+ expect(verified_token_signature[1]).to eq('RS256')
614
+ end
427
615
  end
428
616
 
429
617
  private
@@ -439,14 +627,16 @@ describe OmniAuth::Auth0::JWTValidator do
439
627
  OmniAuth::Auth0::JWTValidator.new(opts)
440
628
  end
441
629
 
442
- def make_hs256_token(payload = nil)
630
+ def make_hs256_token(payload = nil, secret = nil)
443
631
  payload = { sub: 'abc123' } if payload.nil?
444
- JWT.encode payload, client_secret, 'HS256'
632
+ secret = client_secret if secret.nil?
633
+ JWT.encode payload, secret, 'HS256'
445
634
  end
446
635
 
447
- def make_rs256_token(payload = nil)
636
+ def make_rs256_token(payload = nil, kid = nil)
448
637
  payload = { sub: 'abc123' } if payload.nil?
449
- JWT.encode payload, rsa_private_key, 'RS256', kid: jwks_kid
638
+ kid = valid_jwks_kid if kid.nil?
639
+ JWT.encode payload, rsa_private_key, 'RS256', kid: kid
450
640
  end
451
641
 
452
642
  def make_cert(private_key)
@@ -474,7 +664,7 @@ describe OmniAuth::Auth0::JWTValidator do
474
664
  cert.sign private_key, OpenSSL::Digest::SHA1.new
475
665
  end
476
666
 
477
- def stub_jwks
667
+ def stub_complete_jwks
478
668
  stub_request(:get, 'https://samples.auth0.com/.well-known/jwks.json')
479
669
  .to_return(
480
670
  headers: { 'Content-Type' => 'application/json' },
@@ -483,18 +673,11 @@ describe OmniAuth::Auth0::JWTValidator do
483
673
  )
484
674
  end
485
675
 
486
- def stub_bad_jwks
487
- stub_request(:get, 'https://samples.auth0.com/.well-known/jwks-bad.json')
488
- .to_return(
489
- status: 404
490
- )
491
- end
492
-
493
- def stub_dummy_jwks
676
+ def stub_expected_jwks
494
677
  stub_request(:get, 'https://example.org/.well-known/jwks.json')
495
678
  .to_return(
496
679
  headers: { 'Content-Type' => 'application/json' },
497
- body: rsa_token_jwks,
680
+ body: valid_jwks,
498
681
  status: 200
499
682
  )
500
683
  end
@@ -83,7 +83,9 @@ describe OmniAuth::Strategies::Auth0 do
83
83
  expect(redirect_url).to have_query('redirect_uri')
84
84
  expect(redirect_url).not_to have_query('auth0Client')
85
85
  expect(redirect_url).not_to have_query('connection')
86
+ expect(redirect_url).not_to have_query('connection_scope')
86
87
  expect(redirect_url).not_to have_query('prompt')
88
+ expect(redirect_url).not_to have_query('screen_hint')
87
89
  end
88
90
 
89
91
  it 'redirects to hosted login page' do
@@ -97,7 +99,18 @@ describe OmniAuth::Strategies::Auth0 do
97
99
  expect(redirect_url).to have_query('redirect_uri')
98
100
  expect(redirect_url).to have_query('connection', 'abcd')
99
101
  expect(redirect_url).not_to have_query('auth0Client')
102
+ expect(redirect_url).not_to have_query('connection_scope')
100
103
  expect(redirect_url).not_to have_query('prompt')
104
+ expect(redirect_url).not_to have_query('screen_hint')
105
+ end
106
+
107
+ it 'redirects to the hosted login page with connection_scope' do
108
+ get 'auth/auth0?connection_scope=identity_provider_scope'
109
+ expect(last_response.status).to eq(302)
110
+ redirect_url = last_response.headers['Location']
111
+ expect(redirect_url).to start_with('https://samples.auth0.com/authorize')
112
+ expect(redirect_url)
113
+ .to have_query('connection_scope', 'identity_provider_scope')
101
114
  end
102
115
 
103
116
  it 'redirects to hosted login page with prompt=login' do
@@ -114,6 +127,20 @@ describe OmniAuth::Strategies::Auth0 do
114
127
  expect(redirect_url).not_to have_query('connection')
115
128
  end
116
129
 
130
+ it 'redirects to hosted login page with screen_hint=signup' do
131
+ get 'auth/auth0?screen_hint=signup'
132
+ expect(last_response.status).to eq(302)
133
+ redirect_url = last_response.headers['Location']
134
+ expect(redirect_url).to start_with('https://samples.auth0.com/authorize')
135
+ expect(redirect_url).to have_query('response_type', 'code')
136
+ expect(redirect_url).to have_query('state')
137
+ expect(redirect_url).to have_query('client_id')
138
+ expect(redirect_url).to have_query('redirect_uri')
139
+ expect(redirect_url).to have_query('screen_hint', 'signup')
140
+ expect(redirect_url).not_to have_query('auth0Client')
141
+ expect(redirect_url).not_to have_query('connection')
142
+ end
143
+
117
144
  describe 'callback' do
118
145
  let(:access_token) { 'access token' }
119
146
  let(:expires_in) { 2000 }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-auth0
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.1
4
+ version: 2.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Auth0
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-27 00:00:00.000000000 Z
11
+ date: 2020-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: omniauth-oauth2
@@ -103,7 +103,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
103
  - !ruby/object:Gem::Version
104
104
  version: '0'
105
105
  requirements: []
106
- rubygems_version: 3.0.1
106
+ rubygems_version: 3.1.2
107
107
  signing_key:
108
108
  specification_version: 4
109
109
  summary: OmniAuth OAuth2 strategy for the Auth0 platform.