omniauth-auth0 2.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.circleci/config.yml +63 -0
- data/.devcontainer/devcontainer.json +18 -0
- data/.github/CODEOWNERS +1 -0
- data/.github/ISSUE_TEMPLATE/config.yml +8 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +39 -0
- data/.github/ISSUE_TEMPLATE/report_a_bug.md +55 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +32 -0
- data/.github/stale.yml +20 -0
- data/.github/workflows/semgrep.yml +24 -0
- data/.gitignore +5 -2
- data/.semgrepignore +4 -0
- data/.shiprc +7 -0
- data/.snyk +9 -0
- data/CHANGELOG.md +212 -4
- data/CONTRIBUTING.md +71 -0
- data/EXAMPLES.md +167 -0
- data/Gemfile +17 -17
- data/Gemfile.lock +180 -0
- data/README.md +117 -92
- data/Rakefile +2 -2
- data/codecov.yml +22 -0
- data/lib/omniauth/auth0/errors.rb +11 -0
- data/lib/omniauth/auth0/jwt_validator.rb +278 -0
- data/lib/omniauth/auth0/telemetry.rb +36 -0
- data/lib/omniauth/strategies/auth0.rb +89 -21
- data/lib/omniauth-auth0/version.rb +1 -1
- data/lib/omniauth-auth0.rb +1 -1
- data/omniauth-auth0.gemspec +6 -7
- data/opslevel.yml +6 -0
- data/spec/omniauth/auth0/jwt_validator_spec.rb +729 -0
- data/spec/omniauth/auth0/telemetry_spec.rb +28 -0
- data/spec/omniauth/strategies/auth0_spec.rb +160 -18
- data/spec/resources/jwks.json +28 -0
- data/spec/spec_helper.rb +12 -7
- metadata +54 -16
- data/.travis.yml +0 -6
data/codecov.yml
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
coverage:
|
2
|
+
precision: 2
|
3
|
+
round: down
|
4
|
+
range: "60...100"
|
5
|
+
status:
|
6
|
+
project:
|
7
|
+
default:
|
8
|
+
enabled: true
|
9
|
+
target: auto
|
10
|
+
threshold: 5%
|
11
|
+
if_no_uploads: error
|
12
|
+
patch:
|
13
|
+
default:
|
14
|
+
enabled: true
|
15
|
+
target: 80%
|
16
|
+
threshold: 30%
|
17
|
+
if_no_uploads: error
|
18
|
+
changes:
|
19
|
+
default:
|
20
|
+
enabled: true
|
21
|
+
if_no_uploads: error
|
22
|
+
comment: false
|
@@ -0,0 +1,278 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'uri'
|
3
|
+
require 'json'
|
4
|
+
require 'omniauth'
|
5
|
+
require 'omniauth/auth0/errors'
|
6
|
+
|
7
|
+
module OmniAuth
|
8
|
+
module Auth0
|
9
|
+
# JWT Validator class
|
10
|
+
class JWTValidator
|
11
|
+
attr_accessor :issuer, :domain
|
12
|
+
|
13
|
+
# Initializer
|
14
|
+
# @param options object
|
15
|
+
# options.domain - Application domain.
|
16
|
+
# options.issuer - Application issuer (optional).
|
17
|
+
# options.client_id - Application Client ID.
|
18
|
+
# options.client_secret - Application Client Secret.
|
19
|
+
|
20
|
+
def initialize(options, authorize_params = {})
|
21
|
+
@domain = uri_string(options.domain)
|
22
|
+
|
23
|
+
# Use custom issuer if provided, otherwise use domain
|
24
|
+
@issuer = @domain
|
25
|
+
@issuer = uri_string(options.issuer) if options.respond_to?(:issuer)
|
26
|
+
|
27
|
+
@client_id = options.client_id
|
28
|
+
@client_secret = options.client_secret
|
29
|
+
end
|
30
|
+
|
31
|
+
# Verify a token's signature. Only tokens signed with the RS256 or HS256 signatures are supported.
|
32
|
+
# Deprecated: Please use `decode` instead
|
33
|
+
# @return array - The token's key and signing algorithm
|
34
|
+
def verify_signature(jwt)
|
35
|
+
head = token_head(jwt)
|
36
|
+
key, alg = extract_key(head)
|
37
|
+
|
38
|
+
# Call decode to verify the signature
|
39
|
+
JWT.decode(jwt, key, true, decode_opts(alg))
|
40
|
+
return key, alg
|
41
|
+
end
|
42
|
+
|
43
|
+
# Decodes a JWT and verifies it's signature. Only tokens signed with the RS256 or HS256 signatures are supported.
|
44
|
+
# @param jwt string - JWT to verify.
|
45
|
+
# @return hash - The decoded token, if there were no exceptions.
|
46
|
+
# @see https://github.com/jwt/ruby-jwt
|
47
|
+
def decode(jwt)
|
48
|
+
head = token_head(jwt)
|
49
|
+
key, alg = extract_key(head)
|
50
|
+
|
51
|
+
# Call decode to verify the signature
|
52
|
+
JWT.decode(jwt, key, true, decode_opts(alg))
|
53
|
+
end
|
54
|
+
|
55
|
+
# Verify a JWT.
|
56
|
+
# @param jwt string - JWT to verify.
|
57
|
+
# @param authorize_params hash - Authorization params to verify on the JWT
|
58
|
+
# @return hash - The verified token payload, if there were no exceptions.
|
59
|
+
def verify(jwt, authorize_params = {})
|
60
|
+
if !jwt
|
61
|
+
raise OmniAuth::Auth0::TokenValidationError.new('ID token is required but missing')
|
62
|
+
end
|
63
|
+
|
64
|
+
parts = jwt.split('.')
|
65
|
+
if parts.length != 3
|
66
|
+
raise OmniAuth::Auth0::TokenValidationError.new('ID token could not be decoded')
|
67
|
+
end
|
68
|
+
|
69
|
+
id_token, header = decode(jwt)
|
70
|
+
verify_claims(id_token, authorize_params)
|
71
|
+
|
72
|
+
return id_token
|
73
|
+
end
|
74
|
+
|
75
|
+
# Get the decoded head segment from a JWT.
|
76
|
+
# @return hash - The parsed head of the JWT passed, empty hash if not.
|
77
|
+
def token_head(jwt)
|
78
|
+
jwt_parts = jwt.split('.')
|
79
|
+
return {} if blank?(jwt_parts) || blank?(jwt_parts[0])
|
80
|
+
|
81
|
+
json_parse(Base64.decode64(jwt_parts[0]))
|
82
|
+
end
|
83
|
+
|
84
|
+
# Get the JWKS from the issuer and return a public key.
|
85
|
+
# @param x5c string - X.509 certificate chain from a JWKS.
|
86
|
+
# @return key - The X.509 certificate public key.
|
87
|
+
def jwks_public_cert(x5c)
|
88
|
+
x5c = Base64.decode64(x5c)
|
89
|
+
|
90
|
+
# https://docs.ruby-lang.org/en/2.4.0/OpenSSL/X509/Certificate.html
|
91
|
+
OpenSSL::X509::Certificate.new(x5c).public_key
|
92
|
+
end
|
93
|
+
|
94
|
+
# Return a specific key from a JWKS object.
|
95
|
+
# @param key string - Key to find in the JWKS.
|
96
|
+
# @param kid string - Key ID to identify the right JWK.
|
97
|
+
# @return nil|string
|
98
|
+
def jwks_key(key, kid)
|
99
|
+
return nil if blank?(jwks[:keys])
|
100
|
+
|
101
|
+
matching_jwk = jwks[:keys].find { |jwk| jwk[:kid] == kid }
|
102
|
+
matching_jwk[key] if matching_jwk
|
103
|
+
end
|
104
|
+
|
105
|
+
private
|
106
|
+
# Get the JWT decode options. We disable the claim checks since we perform our claim validation logic
|
107
|
+
# Docs: https://github.com/jwt/ruby-jwt
|
108
|
+
# @return hash
|
109
|
+
def decode_opts(alg)
|
110
|
+
{
|
111
|
+
algorithm: alg,
|
112
|
+
verify_expiration: false,
|
113
|
+
verify_iat: false,
|
114
|
+
verify_iss: false,
|
115
|
+
verify_aud: false,
|
116
|
+
verify_jti: false,
|
117
|
+
verify_subj: false,
|
118
|
+
verify_not_before: false
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
def extract_key(head)
|
123
|
+
if head[:alg] == 'RS256'
|
124
|
+
key, alg = [rs256_decode_key(head[:kid]), head[:alg]]
|
125
|
+
elsif head[:alg] == 'HS256'
|
126
|
+
key, alg = [@client_secret, head[:alg]]
|
127
|
+
else
|
128
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Signature algorithm of #{head[:alg]} is not supported. Expected the ID token to be signed with RS256 or HS256")
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def rs256_decode_key(kid)
|
133
|
+
jwks_x5c = jwks_key(:x5c, kid)
|
134
|
+
|
135
|
+
if jwks_x5c.nil?
|
136
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Could not find a public key for Key ID (kid) '#{kid}'")
|
137
|
+
end
|
138
|
+
|
139
|
+
jwks_public_cert(jwks_x5c.first)
|
140
|
+
end
|
141
|
+
|
142
|
+
# Get a JWKS from the domain
|
143
|
+
# @return void
|
144
|
+
def jwks
|
145
|
+
jwks_uri = URI(@domain + '.well-known/jwks.json')
|
146
|
+
@jwks ||= json_parse(Net::HTTP.get(jwks_uri))
|
147
|
+
end
|
148
|
+
|
149
|
+
# Rails Active Support blank method.
|
150
|
+
# @param obj object - Object to check for blankness.
|
151
|
+
# @return boolean
|
152
|
+
def blank?(obj)
|
153
|
+
obj.respond_to?(:empty?) ? obj.empty? : !obj
|
154
|
+
end
|
155
|
+
|
156
|
+
# Parse JSON with symbolized names.
|
157
|
+
# @param json string - JSON to parse.
|
158
|
+
# @return hash
|
159
|
+
def json_parse(json)
|
160
|
+
JSON.parse(json, symbolize_names: true)
|
161
|
+
end
|
162
|
+
|
163
|
+
# Parse a URI into the desired string format
|
164
|
+
# @param uri - the URI to parse
|
165
|
+
# @return string
|
166
|
+
def uri_string(uri)
|
167
|
+
temp_domain = URI(uri)
|
168
|
+
temp_domain = URI("https://#{uri}") unless temp_domain.scheme
|
169
|
+
temp_domain = temp_domain.to_s
|
170
|
+
temp_domain.end_with?('/') ? temp_domain : "#{temp_domain}/"
|
171
|
+
end
|
172
|
+
|
173
|
+
def verify_claims(id_token, authorize_params)
|
174
|
+
leeway = authorize_params[:leeway] || 60
|
175
|
+
max_age = authorize_params[:max_age]
|
176
|
+
nonce = authorize_params[:nonce]
|
177
|
+
organization = authorize_params[:organization]
|
178
|
+
|
179
|
+
verify_iss(id_token)
|
180
|
+
verify_sub(id_token)
|
181
|
+
verify_aud(id_token)
|
182
|
+
verify_expiration(id_token, leeway)
|
183
|
+
verify_iat(id_token)
|
184
|
+
verify_nonce(id_token, nonce)
|
185
|
+
verify_azp(id_token)
|
186
|
+
verify_auth_time(id_token, leeway, max_age)
|
187
|
+
verify_org(id_token, organization)
|
188
|
+
end
|
189
|
+
|
190
|
+
def verify_iss(id_token)
|
191
|
+
issuer = id_token['iss']
|
192
|
+
if !issuer
|
193
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Issuer (iss) claim must be a string present in the ID token")
|
194
|
+
elsif @issuer != issuer
|
195
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Issuer (iss) claim mismatch in the ID token, expected (#{@issuer}), found (#{id_token['iss']})")
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
def verify_sub(id_token)
|
200
|
+
subject = id_token['sub']
|
201
|
+
if !subject || !subject.is_a?(String) || subject.empty?
|
202
|
+
raise OmniAuth::Auth0::TokenValidationError.new('Subject (sub) claim must be a string present in the ID token')
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
def verify_aud(id_token)
|
207
|
+
audience = id_token['aud']
|
208
|
+
if !audience || !(audience.is_a?(String) || audience.is_a?(Array))
|
209
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Audience (aud) claim must be a string or array of strings present in the ID token")
|
210
|
+
elsif audience.is_a?(Array) && !audience.include?(@client_id)
|
211
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Audience (aud) claim mismatch in the ID token; expected #{@client_id} but was not one of #{audience.join(', ')}")
|
212
|
+
elsif audience.is_a?(String) && audience != @client_id
|
213
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Audience (aud) claim mismatch in the ID token; expected #{@client_id} but found #{audience}")
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def verify_expiration(id_token, leeway)
|
218
|
+
expiration = id_token['exp']
|
219
|
+
if !expiration || !expiration.is_a?(Integer)
|
220
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Expiration time (exp) claim must be a number present in the ID token")
|
221
|
+
elsif expiration <= Time.now.to_i - leeway
|
222
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Expiration time (exp) claim error in the ID token; current time (#{Time.now}) is after expiration time (#{Time.at(expiration + leeway)})")
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def verify_iat(id_token)
|
227
|
+
if !id_token['iat']
|
228
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Issued At (iat) claim must be a number present in the ID token")
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def verify_nonce(id_token, nonce)
|
233
|
+
if nonce
|
234
|
+
received_nonce = id_token['nonce']
|
235
|
+
if !received_nonce
|
236
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Nonce (nonce) claim must be a string present in the ID token")
|
237
|
+
elsif nonce != received_nonce
|
238
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Nonce (nonce) claim value mismatch in the ID token; expected (#{nonce}), found (#{received_nonce})")
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
def verify_azp(id_token)
|
244
|
+
audience = id_token['aud']
|
245
|
+
if audience.is_a?(Array) && audience.length > 1
|
246
|
+
azp = id_token['azp']
|
247
|
+
if !azp || !azp.is_a?(String)
|
248
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Authorized Party (azp) claim must be a string present in the ID token when Audience (aud) claim has multiple values")
|
249
|
+
elsif azp != @client_id
|
250
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Authorized Party (azp) claim mismatch in the ID token; expected (#{@client_id}), found (#{azp})")
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def verify_auth_time(id_token, leeway, max_age)
|
256
|
+
if max_age
|
257
|
+
auth_time = id_token['auth_time']
|
258
|
+
if !auth_time || !auth_time.is_a?(Integer)
|
259
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Authentication Time (auth_time) claim must be a number present in the ID token when Max Age (max_age) is specified")
|
260
|
+
elsif Time.now.to_i > auth_time + max_age + leeway;
|
261
|
+
raise OmniAuth::Auth0::TokenValidationError.new("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 + leeway)})")
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def verify_org(id_token, organization)
|
267
|
+
if organization
|
268
|
+
org_id = id_token['org_id']
|
269
|
+
if !org_id || !org_id.is_a?(String)
|
270
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Organization Id (org_id) claim must be a string present in the ID token")
|
271
|
+
elsif org_id != organization
|
272
|
+
raise OmniAuth::Auth0::TokenValidationError.new("Organization Id (org_id) claim value mismatch in the ID token; expected '#{organization}', found '#{org_id}'")
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
278
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module OmniAuth
|
4
|
+
module Auth0
|
5
|
+
# Module to provide necessary telemetry for API requests.
|
6
|
+
module Telemetry
|
7
|
+
|
8
|
+
# Return a telemetry hash to be encoded and sent to Auth0.
|
9
|
+
# @return hash
|
10
|
+
def telemetry
|
11
|
+
telemetry = {
|
12
|
+
name: 'omniauth-auth0',
|
13
|
+
version: OmniAuth::Auth0::VERSION,
|
14
|
+
env: {
|
15
|
+
ruby: RUBY_VERSION
|
16
|
+
}
|
17
|
+
}
|
18
|
+
add_rails_version telemetry
|
19
|
+
end
|
20
|
+
|
21
|
+
# JSON-ify and base64 encode the current telemetry.
|
22
|
+
# @return string
|
23
|
+
def telemetry_encoded
|
24
|
+
Base64.urlsafe_encode64(JSON.dump(telemetry))
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def add_rails_version(telemetry)
|
30
|
+
return telemetry unless Gem.loaded_specs['rails'].respond_to? :version
|
31
|
+
telemetry[:env][:rails] = Gem.loaded_specs['rails'].version.to_s
|
32
|
+
telemetry
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -1,19 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'base64'
|
2
4
|
require 'uri'
|
5
|
+
require 'securerandom'
|
3
6
|
require 'omniauth-oauth2'
|
7
|
+
require 'omniauth/auth0/jwt_validator'
|
8
|
+
require 'omniauth/auth0/telemetry'
|
9
|
+
require 'omniauth/auth0/errors'
|
4
10
|
|
5
11
|
module OmniAuth
|
6
12
|
module Strategies
|
7
13
|
# Auth0 OmniAuth strategy
|
8
14
|
class Auth0 < OmniAuth::Strategies::OAuth2
|
15
|
+
include OmniAuth::Auth0::Telemetry
|
16
|
+
|
9
17
|
option :name, 'auth0'
|
10
18
|
|
11
|
-
args [
|
12
|
-
|
13
|
-
|
14
|
-
|
19
|
+
args %i[
|
20
|
+
client_id
|
21
|
+
client_secret
|
22
|
+
domain
|
15
23
|
]
|
16
24
|
|
25
|
+
# Setup client URLs used during authentication
|
17
26
|
def client
|
18
27
|
options.client_options.site = domain_url
|
19
28
|
options.client_options.authorize_url = '/authorize'
|
@@ -22,25 +31,47 @@ module OmniAuth
|
|
22
31
|
super
|
23
32
|
end
|
24
33
|
|
34
|
+
# Use the "sub" key of the userinfo returned
|
35
|
+
# as the uid (globally unique string identifier).
|
25
36
|
uid { raw_info['sub'] }
|
26
37
|
|
38
|
+
# Build the API credentials hash with returned auth data.
|
27
39
|
credentials do
|
28
|
-
|
29
|
-
|
40
|
+
credentials = {
|
41
|
+
'token' => access_token.token,
|
42
|
+
'expires' => true
|
43
|
+
}
|
44
|
+
|
30
45
|
if access_token.params
|
31
|
-
|
32
|
-
|
33
|
-
|
46
|
+
credentials.merge!(
|
47
|
+
'id_token' => access_token.params['id_token'],
|
48
|
+
'token_type' => access_token.params['token_type'],
|
49
|
+
'refresh_token' => access_token.refresh_token
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Retrieve and remove authorization params from the session
|
54
|
+
session_authorize_params = session['authorize_params'] || {}
|
55
|
+
session.delete('authorize_params')
|
56
|
+
|
57
|
+
auth_scope = session_authorize_params[:scope]
|
58
|
+
if auth_scope.respond_to?(:include?) && auth_scope.include?('openid')
|
59
|
+
# Make sure the ID token can be verified and decoded.
|
60
|
+
jwt_validator.verify(credentials['id_token'], session_authorize_params)
|
34
61
|
end
|
35
|
-
|
62
|
+
|
63
|
+
credentials
|
36
64
|
end
|
37
65
|
|
66
|
+
# Store all raw information for use in the session.
|
38
67
|
extra do
|
39
68
|
{
|
40
69
|
raw_info: raw_info
|
41
70
|
}
|
42
71
|
end
|
43
72
|
|
73
|
+
# Build a hash of information about the user
|
74
|
+
# with keys taken from the Auth Hash Schema.
|
44
75
|
info do
|
45
76
|
{
|
46
77
|
name: raw_info['name'] || raw_info['sub'],
|
@@ -50,56 +81,93 @@ module OmniAuth
|
|
50
81
|
}
|
51
82
|
end
|
52
83
|
|
84
|
+
# Define the parameters used for the /authorize endpoint
|
53
85
|
def authorize_params
|
54
86
|
params = super
|
55
|
-
|
87
|
+
%w[connection connection_scope prompt screen_hint login_hint organization invitation ui_locales].each do |key|
|
88
|
+
params[key] = request.params[key] if request.params.key?(key)
|
89
|
+
end
|
90
|
+
|
91
|
+
# Generate nonce
|
92
|
+
params[:nonce] = SecureRandom.hex
|
93
|
+
# Generate leeway if none exists
|
94
|
+
params[:leeway] = 60 unless params[:leeway]
|
95
|
+
|
96
|
+
# Store authorize params in the session for token verification
|
97
|
+
session['authorize_params'] = params.to_hash
|
98
|
+
|
56
99
|
params
|
57
100
|
end
|
58
101
|
|
102
|
+
def build_access_token
|
103
|
+
options.token_params[:headers] = { 'Auth0-Client' => telemetry_encoded }
|
104
|
+
super
|
105
|
+
end
|
106
|
+
|
107
|
+
# Declarative override for the request phase of authentication
|
59
108
|
def request_phase
|
60
109
|
if no_client_id?
|
110
|
+
# Do we have a client_id for this Application?
|
61
111
|
fail!(:missing_client_id)
|
62
112
|
elsif no_client_secret?
|
113
|
+
# Do we have a client_secret for this Application?
|
63
114
|
fail!(:missing_client_secret)
|
64
115
|
elsif no_domain?
|
116
|
+
# Do we have a domain for this Application?
|
65
117
|
fail!(:missing_domain)
|
66
118
|
else
|
119
|
+
# All checks pass, run the Oauth2 request_phase method.
|
67
120
|
super
|
68
121
|
end
|
69
122
|
end
|
70
123
|
|
124
|
+
def callback_phase
|
125
|
+
super
|
126
|
+
rescue OmniAuth::Auth0::TokenValidationError => e
|
127
|
+
fail!(:token_validation_error, e)
|
128
|
+
end
|
129
|
+
|
71
130
|
private
|
131
|
+
def jwt_validator
|
132
|
+
@jwt_validator ||= OmniAuth::Auth0::JWTValidator.new(options)
|
133
|
+
end
|
72
134
|
|
135
|
+
# Parse the raw user info.
|
73
136
|
def raw_info
|
74
|
-
|
75
|
-
|
137
|
+
return @raw_info if @raw_info
|
138
|
+
|
139
|
+
if access_token["id_token"]
|
140
|
+
claims, header = jwt_validator.decode(access_token["id_token"])
|
141
|
+
@raw_info = claims
|
142
|
+
else
|
143
|
+
userinfo_url = options.client_options.userinfo_url
|
144
|
+
@raw_info = access_token.get(userinfo_url).parsed
|
145
|
+
end
|
146
|
+
|
147
|
+
return @raw_info
|
76
148
|
end
|
77
149
|
|
150
|
+
# Check if the options include a client_id
|
78
151
|
def no_client_id?
|
79
152
|
['', nil].include?(options.client_id)
|
80
153
|
end
|
81
154
|
|
155
|
+
# Check if the options include a client_secret
|
82
156
|
def no_client_secret?
|
83
157
|
['', nil].include?(options.client_secret)
|
84
158
|
end
|
85
159
|
|
160
|
+
# Check if the options include a domain
|
86
161
|
def no_domain?
|
87
162
|
['', nil].include?(options.domain)
|
88
163
|
end
|
89
164
|
|
165
|
+
# Normalize a domain to a URL.
|
90
166
|
def domain_url
|
91
167
|
domain_url = URI(options.domain)
|
92
168
|
domain_url = URI("https://#{domain_url}") if domain_url.scheme.nil?
|
93
169
|
domain_url.to_s
|
94
170
|
end
|
95
|
-
|
96
|
-
def client_info
|
97
|
-
client_info = JSON.dump(
|
98
|
-
name: 'omniauth-auth0',
|
99
|
-
version: OmniAuth::Auth0::VERSION
|
100
|
-
)
|
101
|
-
Base64.urlsafe_encode64(client_info)
|
102
|
-
end
|
103
171
|
end
|
104
172
|
end
|
105
173
|
end
|
data/lib/omniauth-auth0.rb
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
require 'omniauth-auth0/version'
|
1
|
+
require 'omniauth-auth0/version'
|
2
2
|
require 'omniauth/strategies/auth0'
|
data/omniauth-auth0.gemspec
CHANGED
@@ -8,24 +8,23 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.authors = ['Auth0']
|
9
9
|
s.email = ['info@auth0.com']
|
10
10
|
s.homepage = 'https://github.com/auth0/omniauth-auth0'
|
11
|
-
s.summary = '
|
11
|
+
s.summary = 'OmniAuth OAuth2 strategy for the Auth0 platform.'
|
12
12
|
s.description = %q{Auth0 is an authentication broker that supports social identity providers as well as enterprise identity providers such as Active Directory, LDAP, Google Apps, Salesforce.
|
13
13
|
|
14
14
|
OmniAuth is a library that standardizes multi-provider authentication for web applications. It was created to be powerful, flexible, and do as little as possible.
|
15
15
|
|
16
|
-
omniauth-auth0 is the
|
16
|
+
omniauth-auth0 is the OmniAuth strategy for Auth0.
|
17
17
|
}
|
18
18
|
|
19
|
-
s.rubyforge_project = 'omniauth-auth0'
|
20
|
-
|
21
19
|
s.files = `git ls-files`.split("\n")
|
22
20
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
23
21
|
s.executables = `git ls-files -- bin/*`.split('\n').map{ |f| File.basename(f) }
|
24
22
|
s.require_paths = ['lib']
|
25
23
|
|
26
|
-
s.add_runtime_dependency 'omniauth
|
24
|
+
s.add_runtime_dependency 'omniauth', '~> 2'
|
25
|
+
s.add_runtime_dependency 'omniauth-oauth2', '~> 1'
|
26
|
+
|
27
|
+
s.add_development_dependency 'bundler'
|
27
28
|
|
28
|
-
s.add_development_dependency 'bundler', '~> 1.9'
|
29
|
-
|
30
29
|
s.license = 'MIT'
|
31
30
|
end
|