omniauth-auth0 3.0.0 → 3.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +23 -4
- data/.devcontainer/devcontainer.json +18 -0
- data/.github/ISSUE_TEMPLATE/Bug Report.yml +76 -0
- data/.github/ISSUE_TEMPLATE/Feature Request.yml +53 -0
- data/.github/ISSUE_TEMPLATE/config.yml +2 -2
- data/.github/workflows/semgrep.yml +24 -0
- data/.gitignore +0 -2
- data/.semgrepignore +4 -0
- data/.shiprc +7 -0
- data/CHANGELOG.md +74 -11
- data/EXAMPLES.md +181 -0
- data/Gemfile +15 -15
- data/Gemfile.lock +184 -0
- data/README.md +93 -194
- data/lib/omniauth/auth0/jwt_validator.rb +19 -3
- data/lib/omniauth/strategies/auth0.rb +2 -2
- data/lib/omniauth-auth0/version.rb +1 -1
- data/omniauth-auth0.gemspec +3 -3
- data/opslevel.yml +6 -0
- data/spec/omniauth/auth0/jwt_validator_spec.rb +111 -33
- data/spec/omniauth/strategies/auth0_spec.rb +14 -0
- data/spec/spec_helper.rb +7 -3
- metadata +20 -19
- data/.github/ISSUE_TEMPLATE/feature_request.md +0 -39
- data/.github/ISSUE_TEMPLATE/report_a_bug.md +0 -55
- data/CODE_OF_CONDUCT.md +0 -3
data/README.md
CHANGED
@@ -1,25 +1,14 @@
|
|
1
|
-
|
1
|
+
![Omniauth-auth0](https://cdn.auth0.com/website/sdks/banners/omniauth-auth0-banner.png)
|
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.
|
4
|
-
|
5
|
-
> :warning: **Important security note for v2:** This solution uses a 3rd party library that had a [security issue(s)](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2015-9284) in v2. 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 in v2. **[Upgrading to v3](https://github.com/auth0/omniauth-auth0/pull/128) of this library resolves the issue.**
|
6
3
|
|
7
4
|
[![CircleCI](https://img.shields.io/circleci/project/github/auth0/omniauth-auth0/master.svg)](https://circleci.com/gh/auth0/omniauth-auth0)
|
8
5
|
[![codecov](https://codecov.io/gh/auth0/omniauth-auth0/branch/master/graph/badge.svg)](https://codecov.io/gh/auth0/omniauth-auth0)
|
9
6
|
[![Gem Version](https://badge.fury.io/rb/omniauth-auth0.svg)](https://badge.fury.io/rb/omniauth-auth0)
|
10
7
|
[![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)
|
12
|
-
|
13
|
-
## Table of Contents
|
14
8
|
|
15
|
-
|
16
|
-
-
|
17
|
-
|
18
|
-
- [Contribution](#contribution)
|
19
|
-
- [Support + Feedback](#support--feedback)
|
20
|
-
- [Vulnerability Reporting](#vulnerability-reporting)
|
21
|
-
- [What is Auth0](#what-is-auth0)
|
22
|
-
- [License](#license)
|
9
|
+
<div>
|
10
|
+
📚 <a href="#documentation">Documentation</a> - 🚀 <a href="#getting-started">Getting started</a> - 💻 <a href="https://www.rubydoc.info/gems/omniauth-auth0">API reference</a> - 💬 <a href="#feedback">Feedback</a>
|
11
|
+
</div>
|
23
12
|
|
24
13
|
## Documentation
|
25
14
|
|
@@ -27,7 +16,9 @@ An [OmniAuth](https://github.com/intridea/omniauth) strategy for authenticating
|
|
27
16
|
- [Sample projects](https://github.com/auth0-samples/auth0-rubyonrails-sample)
|
28
17
|
- [API Reference](https://www.rubydoc.info/gems/omniauth-auth0)
|
29
18
|
|
30
|
-
##
|
19
|
+
## Getting started
|
20
|
+
|
21
|
+
### Installation
|
31
22
|
|
32
23
|
Add the following line to your `Gemfile`:
|
33
24
|
|
@@ -49,221 +40,129 @@ $ bundle install
|
|
49
40
|
|
50
41
|
See our [contributing guide](CONTRIBUTING.md) for information on local installation for development.
|
51
42
|
|
52
|
-
##
|
53
|
-
|
54
|
-
To start processing authentication requests, the following steps must be performed:
|
55
|
-
|
56
|
-
1. Initialize the strategy
|
57
|
-
2. Configure the callback controller
|
58
|
-
3. Add the required routes
|
59
|
-
4. Trigger an authentication request
|
60
|
-
|
61
|
-
All of these tasks and more are covered in our [Ruby on Rails Quickstart](https://auth0.com/docs/quickstart/webapp/rails).
|
62
|
-
|
63
|
-
### Additional authentication parameters
|
64
|
-
|
65
|
-
To send additional parameters during login, you can specify them when you register the provider:
|
66
|
-
|
67
|
-
```ruby
|
68
|
-
provider
|
69
|
-
:auth0,
|
70
|
-
ENV['AUTH0_CLIENT_ID'],
|
71
|
-
ENV['AUTH0_CLIENT_SECRET'],
|
72
|
-
ENV['AUTH0_DOMAIN'],
|
73
|
-
{
|
74
|
-
authorize_params: {
|
75
|
-
scope: 'openid read:users write:order',
|
76
|
-
audience: 'https://mydomain/api',
|
77
|
-
max_age: 3600 # time in seconds authentication is valid
|
78
|
-
}
|
79
|
-
}
|
80
|
-
```
|
43
|
+
## Configure the SDK
|
81
44
|
|
82
|
-
|
45
|
+
Adding the SDK to your Rails app requires a few steps:
|
83
46
|
|
84
|
-
|
47
|
+
- [Create the configuration file](#create-the-configuration-file)
|
48
|
+
- [Create the initializer](#create-the-initializer)
|
49
|
+
- [Create the callback controller](#create-the-callback-controller)
|
50
|
+
- [Add routes](#add-routes)
|
85
51
|
|
86
|
-
|
52
|
+
### Create the configuration file
|
87
53
|
|
88
|
-
|
89
|
-
- `:uid` - the user identifier
|
90
|
-
- `:info` - the result of the call to `/userinfo` using OmniAuth standard attributes
|
91
|
-
- `:credentials` - tokens requested and data
|
92
|
-
- `:extra` - Additional info obtained from calling `/userinfo` in the `:raw_info` property
|
54
|
+
Create the file `./config/auth0.yml` within your application directory with the following content:
|
93
55
|
|
94
|
-
```
|
95
|
-
|
96
|
-
:
|
97
|
-
:
|
98
|
-
:
|
99
|
-
:name => 'John Foo',
|
100
|
-
:email => 'johnfoo@example.org',
|
101
|
-
:nickname => 'john',
|
102
|
-
:image => 'https://example.org/john.jpg'
|
103
|
-
},
|
104
|
-
:credentials => {
|
105
|
-
:token => 'ACCESS_TOKEN',
|
106
|
-
:expires_at => 1485373937,
|
107
|
-
:expires => true,
|
108
|
-
:refresh_token => 'REFRESH_TOKEN',
|
109
|
-
:id_token => 'JWT_ID_TOKEN',
|
110
|
-
:token_type => 'bearer',
|
111
|
-
},
|
112
|
-
:extra => {
|
113
|
-
:raw_info => {
|
114
|
-
:email => 'johnfoo@example.org',
|
115
|
-
:email_verified => 'true',
|
116
|
-
:name => 'John Foo',
|
117
|
-
:picture => 'https://example.org/john.jpg',
|
118
|
-
:user_id => 'auth0|USER_ID',
|
119
|
-
:nickname => 'john',
|
120
|
-
:created_at => '2014-07-15T17:19:50.387Z'
|
121
|
-
}
|
122
|
-
}
|
123
|
-
}
|
56
|
+
```yml
|
57
|
+
development:
|
58
|
+
auth0_domain: <YOUR_DOMAIN>
|
59
|
+
auth0_client_id: <YOUR_CLIENT_ID>
|
60
|
+
auth0_client_secret: <YOUR AUTH0 CLIENT SECRET>
|
124
61
|
```
|
125
62
|
|
126
|
-
###
|
127
|
-
|
128
|
-
In some scenarios, you may need to pass specific query parameters to `/authorize`. The following parameters are available to enable this:
|
129
|
-
|
130
|
-
- `connection`
|
131
|
-
- `connection_scope`
|
132
|
-
- `prompt`
|
133
|
-
- `screen_hint` (only relevant to New Universal Login Experience)
|
134
|
-
- `organization`
|
135
|
-
- `invitation`
|
136
|
-
|
137
|
-
Simply pass these query parameters to your OmniAuth redirect endpoint to enable their behavior.
|
138
|
-
|
139
|
-
## Examples
|
140
|
-
|
141
|
-
### Auth0 Organizations
|
142
|
-
|
143
|
-
[Organizations](https://auth0.com/docs/organizations) is a set of features that provide better support for developers who build and maintain SaaS and Business-to-Business (B2B) applications.
|
144
|
-
|
145
|
-
Using Organizations, you can:
|
63
|
+
### Create the initializer
|
146
64
|
|
147
|
-
|
148
|
-
- Manage their membership in a variety of ways, including user invitation.
|
149
|
-
- Configure branded, federated login flows for each organization.
|
150
|
-
- Implement role-based access control, such that users can have different roles when authenticating in the context of different organizations.
|
151
|
-
- Build administration capabilities into your products, using Organizations APIs, so that those businesses can manage their own organizations.
|
152
|
-
|
153
|
-
Note that Organizations is currently only available to customers on our Enterprise and Startup subscription plans.
|
154
|
-
|
155
|
-
#### Logging in with an Organization
|
156
|
-
|
157
|
-
Logging in with an Organization is as easy as passing the parameters to the authorize endpoint. You can do this with
|
65
|
+
Create a new Ruby file in `./config/initializers/auth0.rb` to configure the OmniAuth middleware:
|
158
66
|
|
159
67
|
```ruby
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
Alternatively you can configure the organization when you register the provider:
|
171
|
-
|
172
|
-
```ruby
|
173
|
-
provider
|
174
|
-
:auth0,
|
175
|
-
ENV['AUTH0_CLIENT_ID'],
|
176
|
-
ENV['AUTH0_CLIENT_SECRET'],
|
177
|
-
ENV['AUTH0_DOMAIN']
|
178
|
-
{
|
68
|
+
AUTH0_CONFIG = Rails.application.config_for(:auth0)
|
69
|
+
|
70
|
+
Rails.application.config.middleware.use OmniAuth::Builder do
|
71
|
+
provider(
|
72
|
+
:auth0,
|
73
|
+
AUTH0_CONFIG['auth0_client_id'],
|
74
|
+
AUTH0_CONFIG['auth0_client_secret'],
|
75
|
+
AUTH0_CONFIG['auth0_domain'],
|
76
|
+
callback_path: '/auth/auth0/callback',
|
179
77
|
authorize_params: {
|
180
|
-
scope: 'openid
|
181
|
-
audience: 'https://{AUTH0_DOMAIN}/api',
|
182
|
-
organization: '{AUTH0_ORGANIZATION}'
|
78
|
+
scope: 'openid profile'
|
183
79
|
}
|
184
|
-
|
80
|
+
)
|
81
|
+
end
|
185
82
|
```
|
186
83
|
|
187
|
-
|
188
|
-
|
189
|
-
#### Validating Organizations when using Organization Login Prompt
|
190
|
-
|
191
|
-
When Organization login prompt is enabled on your application, but you haven't specified an Organization for the application's authorization endpoint, the `org_id` claim will be present on the ID token, and should be validated to ensure that the value received is expected or known.
|
192
|
-
|
193
|
-
Normally, validating the issuer would be enough to ensure that the token was issued by Auth0, and this check is performed by the SDK. However, in the case of organizations, additional checks should be made so that the organization within an Auth0 tenant is expected.
|
84
|
+
### Create the callback controller
|
194
85
|
|
195
|
-
|
86
|
+
Create a new controller `./app/controllers/auth0_controller.rb` to handle the callback from Auth0.
|
196
87
|
|
197
|
-
|
88
|
+
> You can also run `rails generate controller auth0 callback failure logout --skip-assets --skip-helper --skip-routes --skip-template-engine` to scaffold this controller for you.
|
198
89
|
|
199
90
|
```ruby
|
91
|
+
# ./app/controllers/auth0_controller.rb
|
92
|
+
class Auth0Controller < ApplicationController
|
200
93
|
def callback
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
94
|
+
# OmniAuth stores the information returned from Auth0 and the IdP in request.env['omniauth.auth'].
|
95
|
+
# In this code, you will pull the raw_info supplied from the id_token and assign it to the session.
|
96
|
+
# Refer to https://github.com/auth0/omniauth-auth0/blob/master/EXAMPLES.md#example-of-the-resulting-authentication-hash for complete information on 'omniauth.auth' contents.
|
97
|
+
auth_info = request.env['omniauth.auth']
|
98
|
+
session[:userinfo] = auth_info['extra']['raw_info']
|
99
|
+
|
100
|
+
# Redirect to the URL you want after successful auth
|
101
|
+
redirect_to '/dashboard'
|
209
102
|
end
|
210
|
-
```
|
211
|
-
|
212
|
-
For more information, please read [Work with Tokens and Organizations](https://auth0.com/docs/organizations/using-tokens) on Auth0 Docs.
|
213
103
|
|
214
|
-
|
104
|
+
def failure
|
105
|
+
# Handles failed authentication -- Show a failure page (you can also handle with a redirect)
|
106
|
+
@error_msg = request.params['message']
|
107
|
+
end
|
215
108
|
|
216
|
-
|
109
|
+
def logout
|
110
|
+
# you will finish this in a later step
|
111
|
+
end
|
112
|
+
end
|
113
|
+
```
|
217
114
|
|
218
|
-
|
115
|
+
### Add routes
|
219
116
|
|
220
|
-
|
117
|
+
Finally, add the following routes to your `./config/routes.rb` file:
|
221
118
|
|
222
119
|
```ruby
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
}
|
230
|
-
%>
|
120
|
+
Rails.application.routes.draw do
|
121
|
+
# ..
|
122
|
+
get '/auth/auth0/callback' => 'auth0#callback'
|
123
|
+
get '/auth/failure' => 'auth0#failure'
|
124
|
+
get '/auth/logout' => 'auth0#logout'
|
125
|
+
end
|
231
126
|
```
|
232
127
|
|
233
|
-
##
|
128
|
+
## Logging in
|
234
129
|
|
235
|
-
|
236
|
-
|
237
|
-
- [Auth0's contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md)
|
238
|
-
- [Auth0's Code of Conduct](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md)
|
239
|
-
- [This repo's contribution guide](CONTRIBUTING.md)
|
240
|
-
|
241
|
-
## Support + Feedback
|
130
|
+
To redirect your users to Auth0 for authentication, redirect your users to the `/auth/auth0` endpoint of your app. One way to do this is to use a link or button on a page:
|
242
131
|
|
243
|
-
|
244
|
-
|
245
|
-
|
132
|
+
```html
|
133
|
+
<%= button_to 'Login', '/auth/auth0', method: :post %>
|
134
|
+
```
|
246
135
|
|
247
|
-
##
|
136
|
+
## Feedback
|
248
137
|
|
249
|
-
|
138
|
+
### Contributing
|
250
139
|
|
251
|
-
|
140
|
+
We appreciate feedback and contribution to this repo! Before you get started, please see the following:
|
252
141
|
|
253
|
-
Auth0
|
142
|
+
- [Auth0's general contribution guidelines](https://github.com/auth0/open-source-template/blob/master/GENERAL-CONTRIBUTING.md)
|
143
|
+
- [Auth0's code of conduct guidelines](https://github.com/auth0/open-source-template/blob/master/CODE-OF-CONDUCT.md)
|
144
|
+
- [This repo's contribution guide](https://github.com/auth0/omniauth-auth0/blob/master/CONTRIBUTING.md)
|
254
145
|
|
255
|
-
|
256
|
-
- log in users with username/password databases, passwordless, or multi-factor authentication
|
257
|
-
- link multiple user accounts together
|
258
|
-
- generate signed JSON Web Tokens to authorize your API calls and flow the user identity securely
|
259
|
-
- access demographics and analytics detailing how, when, and where users are logging in
|
260
|
-
- enrich user profiles from other data sources using customizable JavaScript rules
|
146
|
+
### Raise an issue
|
261
147
|
|
262
|
-
[
|
148
|
+
To provide feedback or report a bug, please [raise an issue on our issue tracker](https://github.com/auth0/omniauth-auth0/issues).
|
263
149
|
|
264
|
-
|
150
|
+
### Vulnerability Reporting
|
265
151
|
|
266
|
-
|
152
|
+
Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues.
|
267
153
|
|
154
|
+
---
|
268
155
|
|
269
|
-
|
156
|
+
<p align="center">
|
157
|
+
<picture>
|
158
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.auth0.com/website/sdks/logos/auth0_dark_mode.png" width="150">
|
159
|
+
<source media="(prefers-color-scheme: light)" srcset="https://cdn.auth0.com/website/sdks/logos/auth0_light_mode.png" width="150">
|
160
|
+
<img alt="Auth0 Logo" src="https://cdn.auth0.com/website/sdks/logos/auth0_light_mode.png" width="150">
|
161
|
+
</picture>
|
162
|
+
</p>
|
163
|
+
<p align="center">
|
164
|
+
Auth0 is an easy to implement, adaptable authentication and authorization platform. To learn more checkout <a href="https://auth0.com/why-auth0">Why Auth0?</a>
|
165
|
+
</p>
|
166
|
+
<p align="center">
|
167
|
+
This project is licensed under the MIT license. See the <a href="https://github.com/auth0/omniauth-auth0/blob/master/LICENSE"> LICENSE</a> file for more info.
|
168
|
+
</p>
|
@@ -7,6 +7,7 @@ require 'omniauth/auth0/errors'
|
|
7
7
|
module OmniAuth
|
8
8
|
module Auth0
|
9
9
|
# JWT Validator class
|
10
|
+
# rubocop:disable Metrics/
|
10
11
|
class JWTValidator
|
11
12
|
attr_accessor :issuer, :domain
|
12
13
|
|
@@ -264,12 +265,27 @@ module OmniAuth
|
|
264
265
|
end
|
265
266
|
|
266
267
|
def verify_org(id_token, organization)
|
267
|
-
|
268
|
+
return unless organization
|
269
|
+
|
270
|
+
validate_as_id = organization.start_with? 'org_'
|
271
|
+
|
272
|
+
if validate_as_id
|
268
273
|
org_id = id_token['org_id']
|
269
274
|
if !org_id || !org_id.is_a?(String)
|
270
|
-
raise OmniAuth::Auth0::TokenValidationError
|
275
|
+
raise OmniAuth::Auth0::TokenValidationError,
|
276
|
+
'Organization Id (org_id) claim must be a string present in the ID token'
|
271
277
|
elsif org_id != organization
|
272
|
-
raise OmniAuth::Auth0::TokenValidationError
|
278
|
+
raise OmniAuth::Auth0::TokenValidationError,
|
279
|
+
"Organization Id (org_id) claim value mismatch in the ID token; expected '#{organization}', found '#{org_id}'"
|
280
|
+
end
|
281
|
+
else
|
282
|
+
org_name = id_token['org_name']
|
283
|
+
if !org_name || !org_name.is_a?(String)
|
284
|
+
raise OmniAuth::Auth0::TokenValidationError,
|
285
|
+
'Organization Name (org_name) claim must be a string present in the ID token'
|
286
|
+
elsif org_name != organization.downcase
|
287
|
+
raise OmniAuth::Auth0::TokenValidationError,
|
288
|
+
"Organization Name (org_name) claim value mismatch in the ID token; expected '#{organization}', found '#{org_name}'"
|
273
289
|
end
|
274
290
|
end
|
275
291
|
end
|
@@ -84,7 +84,7 @@ module OmniAuth
|
|
84
84
|
# Define the parameters used for the /authorize endpoint
|
85
85
|
def authorize_params
|
86
86
|
params = super
|
87
|
-
%w[connection connection_scope prompt screen_hint login_hint organization invitation].each do |key|
|
87
|
+
%w[connection connection_scope prompt screen_hint login_hint organization invitation ui_locales].each do |key|
|
88
88
|
params[key] = request.params[key] if request.params.key?(key)
|
89
89
|
end
|
90
90
|
|
@@ -94,7 +94,7 @@ module OmniAuth
|
|
94
94
|
params[:leeway] = 60 unless params[:leeway]
|
95
95
|
|
96
96
|
# Store authorize params in the session for token verification
|
97
|
-
session['authorize_params'] = params
|
97
|
+
session['authorize_params'] = params.to_hash
|
98
98
|
|
99
99
|
params
|
100
100
|
end
|
data/omniauth-auth0.gemspec
CHANGED
@@ -21,10 +21,10 @@ omniauth-auth0 is the OmniAuth strategy for Auth0.
|
|
21
21
|
s.executables = `git ls-files -- bin/*`.split('\n').map{ |f| File.basename(f) }
|
22
22
|
s.require_paths = ['lib']
|
23
23
|
|
24
|
-
s.add_runtime_dependency 'omniauth', '~> 2
|
25
|
-
s.add_runtime_dependency 'omniauth-oauth2', '~> 1
|
24
|
+
s.add_runtime_dependency 'omniauth', '~> 2'
|
25
|
+
s.add_runtime_dependency 'omniauth-oauth2', '~> 1'
|
26
26
|
|
27
27
|
s.add_development_dependency 'bundler'
|
28
|
-
|
28
|
+
|
29
29
|
s.license = 'MIT'
|
30
30
|
end
|
data/opslevel.yml
ADDED
@@ -357,7 +357,7 @@ describe OmniAuth::Auth0::JWTValidator do
|
|
357
357
|
message: "Nonce (nonce) claim value mismatch in the ID token; expected (noncey), found (mismatch)"
|
358
358
|
}))
|
359
359
|
end
|
360
|
-
|
360
|
+
|
361
361
|
it 'should fail when “aud” is an array of strings and azp claim is not present' do
|
362
362
|
aud = [
|
363
363
|
client_id,
|
@@ -476,41 +476,119 @@ describe OmniAuth::Auth0::JWTValidator do
|
|
476
476
|
expect(id_token['auth_time']).to eq(auth_time)
|
477
477
|
end
|
478
478
|
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
479
|
+
context 'Organization claim validation' do
|
480
|
+
it 'should fail when authorize params has organization but org_id is missing in the token' do
|
481
|
+
payload = {
|
482
|
+
iss: "https://#{domain}/",
|
483
|
+
sub: 'sub',
|
484
|
+
aud: client_id,
|
485
|
+
exp: future_timecode,
|
486
|
+
iat: past_timecode
|
487
|
+
}
|
487
488
|
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
489
|
+
token = make_hs256_token(payload)
|
490
|
+
expect do
|
491
|
+
jwt_validator.verify(token, { organization: 'org_123' })
|
492
|
+
end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and having_attributes({
|
493
|
+
message: "Organization Id (org_id) claim must be a string present in the ID token"
|
494
|
+
}))
|
495
|
+
end
|
495
496
|
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
}
|
497
|
+
it 'should fail when authorize params has organization but org_name is missing in the token' do
|
498
|
+
payload = {
|
499
|
+
iss: "https://#{domain}/",
|
500
|
+
sub: 'sub',
|
501
|
+
aud: client_id,
|
502
|
+
exp: future_timecode,
|
503
|
+
iat: past_timecode
|
504
|
+
}
|
505
505
|
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
506
|
+
token = make_hs256_token(payload)
|
507
|
+
expect do
|
508
|
+
jwt_validator.verify(token, { organization: 'my-organization' })
|
509
|
+
end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and(having_attributes({
|
510
|
+
message: 'Organization Name (org_name) claim must be a string present in the ID token'
|
511
|
+
})))
|
512
|
+
end
|
513
|
+
|
514
|
+
it 'should fail when authorize params has organization but token org_id does not match' do
|
515
|
+
payload = {
|
516
|
+
iss: "https://#{domain}/",
|
517
|
+
sub: 'sub',
|
518
|
+
aud: client_id,
|
519
|
+
exp: future_timecode,
|
520
|
+
iat: past_timecode,
|
521
|
+
org_id: 'org_5678'
|
522
|
+
}
|
523
|
+
|
524
|
+
token = make_hs256_token(payload)
|
525
|
+
expect do
|
526
|
+
jwt_validator.verify(token, { organization: 'org_1234' })
|
527
|
+
end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and(having_attributes({
|
528
|
+
message: "Organization Id (org_id) claim value mismatch in the ID token; expected 'org_1234', found 'org_5678'"
|
529
|
+
})))
|
530
|
+
end
|
531
|
+
|
532
|
+
it 'should fail when authorize params has organization but token org_name does not match' do
|
533
|
+
payload = {
|
534
|
+
iss: "https://#{domain}/",
|
535
|
+
sub: 'sub',
|
536
|
+
aud: client_id,
|
537
|
+
exp: future_timecode,
|
538
|
+
iat: past_timecode,
|
539
|
+
org_name: 'another-organization'
|
540
|
+
}
|
541
|
+
|
542
|
+
token = make_hs256_token(payload)
|
543
|
+
expect do
|
544
|
+
jwt_validator.verify(token, { organization: 'my-organization' })
|
545
|
+
end.to raise_error(an_instance_of(OmniAuth::Auth0::TokenValidationError).and(having_attributes({
|
546
|
+
message: "Organization Name (org_name) claim value mismatch in the ID token; expected 'my-organization', found 'another-organization'"
|
547
|
+
})))
|
548
|
+
end
|
549
|
+
|
550
|
+
it 'should not fail when correctly given an organization ID' do
|
551
|
+
payload = {
|
552
|
+
iss: "https://#{domain}/",
|
553
|
+
sub: 'sub',
|
554
|
+
aud: client_id,
|
555
|
+
exp: future_timecode,
|
556
|
+
iat: past_timecode,
|
557
|
+
org_id: 'org_1234'
|
558
|
+
}
|
513
559
|
|
560
|
+
token = make_hs256_token(payload)
|
561
|
+
jwt_validator.verify(token, { organization: 'org_1234' })
|
562
|
+
end
|
563
|
+
|
564
|
+
it 'should not fail when correctly given an organization name' do
|
565
|
+
payload = {
|
566
|
+
iss: "https://#{domain}/",
|
567
|
+
sub: 'sub',
|
568
|
+
aud: client_id,
|
569
|
+
exp: future_timecode,
|
570
|
+
iat: past_timecode,
|
571
|
+
org_name: 'my-organization'
|
572
|
+
}
|
573
|
+
|
574
|
+
token = make_hs256_token(payload)
|
575
|
+
jwt_validator.verify(token, { organization: 'my-organization' })
|
576
|
+
end
|
577
|
+
|
578
|
+
it 'should not fail when given an organization name in a different casing' do
|
579
|
+
payload = {
|
580
|
+
iss: "https://#{domain}/",
|
581
|
+
sub: 'sub',
|
582
|
+
aud: client_id,
|
583
|
+
exp: future_timecode,
|
584
|
+
iat: past_timecode,
|
585
|
+
org_name: 'my-organization'
|
586
|
+
}
|
587
|
+
|
588
|
+
token = make_hs256_token(payload)
|
589
|
+
jwt_validator.verify(token, { organization: 'MY-ORGANIZATION' })
|
590
|
+
end
|
591
|
+
end
|
514
592
|
it 'should fail for RS256 token when kid is incorrect' do
|
515
593
|
domain = 'example.org'
|
516
594
|
sub = 'abc123'
|
@@ -544,7 +622,7 @@ describe OmniAuth::Auth0::JWTValidator do
|
|
544
622
|
expect do
|
545
623
|
verified_token = make_jwt_validator(opt_domain: domain).verify(token)
|
546
624
|
end.to raise_error(an_instance_of(JWT::VerificationError).and having_attributes({
|
547
|
-
message: "Signature verification
|
625
|
+
message: "Signature verification failed"
|
548
626
|
}))
|
549
627
|
end
|
550
628
|
|
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
require 'jwt'
|
5
|
+
require 'multi_json'
|
5
6
|
|
6
7
|
OmniAuth.config.allowed_request_methods = [:get, :post]
|
7
8
|
|
@@ -198,6 +199,19 @@ describe OmniAuth::Strategies::Auth0 do
|
|
198
199
|
expect(redirect_url).not_to have_query('invitation')
|
199
200
|
end
|
200
201
|
|
202
|
+
def session
|
203
|
+
session_cookie = last_response.cookies['rack.session'].first
|
204
|
+
session_data, _, _ = session_cookie.rpartition('--')
|
205
|
+
decoded_session_data = Base64.decode64(session_data)
|
206
|
+
Marshal.load(decoded_session_data)
|
207
|
+
end
|
208
|
+
|
209
|
+
it "stores session['authorize_params'] as a plain Ruby Hash" do
|
210
|
+
get '/auth/auth0'
|
211
|
+
|
212
|
+
expect(session['authorize_params'].class).to eq(::Hash)
|
213
|
+
end
|
214
|
+
|
201
215
|
describe 'callback' do
|
202
216
|
let(:access_token) { 'access token' }
|
203
217
|
let(:expires_in) { 2000 }
|