omniauth-activedirectory 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 9e5054c1ce0e8771f7955b5cab69b08b4ecb1287c6add06c6c3557b557df161b
4
+ data.tar.gz: b46b578255169b89254233a5351092d767c7a18e2d923d831f3f9d0c146c45ca
5
+ SHA512:
6
+ metadata.gz: c3c9954a04ee129aa7f5f4a7cb6a32cc487b75e44bd50abde7e3864a56fe9cba9479b3aca3708505f7a73711e23c7392cd7b87ef02bffbd588f92afbe0b53ca0
7
+ data.tar.gz: 3b40be7f0410ff9f79a303aa2614e12314973d5efe2fb90ce116905b1d03a3003b6eddb0cb8a24670cf579e3d9f6823919c577de8a4cb6c4991d0397d3ec098e
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ *.gem
2
+ *.log
3
+ .bundle
4
+ coverage
5
+ .powenv
6
+ .rspec
7
+ Gemfile.lock
8
+ pkg/*
9
+ tmp
data/.rubocop.yml ADDED
@@ -0,0 +1,8 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ AllCops:
4
+ Exclude:
5
+ - 'spec/fixtures/**/*'
6
+
7
+ Style/Encoding:
8
+ Enabled: false
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,20 @@
1
+ # This configuration was generated by `rubocop --auto-gen-config`
2
+ # on 2015-08-06 14:09:24 -0700 using RuboCop version 0.32.1.
3
+ # The point is for the user to remove these configuration records
4
+ # one by one as the offenses are removed from the code base.
5
+ # Note that changes in the inspected code, or installation of new
6
+ # versions of RuboCop, may require this file to be generated again.
7
+
8
+ # Offense count: 2
9
+ Metrics/AbcSize:
10
+ Max: 19
11
+
12
+ # Offense count: 1
13
+ # Configuration parameters: CountComments.
14
+ Metrics/ClassLength:
15
+ Max: 118
16
+
17
+ # Offense count: 1
18
+ # Configuration parameters: Exclude.
19
+ Style/FileName:
20
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2021 Dave Van Fleet
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,94 @@
1
+ # OmniAuth Azure Active Directory
2
+
3
+ This is a fork of Microsoft's official ruby gem for Azure Active Directory as an omniauth provider. Most of this README is taken from Microsoft's original gem, [found here](https://github.com/AzureAD/omniauth-azure-activedirectory), with additions to make it compatible with other providers.
4
+
5
+ OmniAuth strategy to authenticate to Azure Active Directory via OpenId Connect.
6
+
7
+ Before starting, set up a tenant and register a Web Application at [https://manage.windowsazure.com](https://manage.windowsazure.com). Note your client id and tenant for later.
8
+
9
+ # Why this Gem?
10
+
11
+ While Microsoft's original gem still works, when Azure AD is being used as the only provider for omniauth, it hasn't been updated in a significant amount of time. When trying to implement this gem in my own projects, I faced the issue of having many runtime dependency conflicts, meaning I either needed to use older versions of other provider gems (not always possible), or update this gem for myself. This repo is the result of deciding on the latter.
12
+
13
+ ## Samples and Documentation
14
+
15
+ [Find Microsoft's examples here](https://github.com/AzureADSamples) to help you get started with learning the Azure Identity system. This includes tutorials for native clients such as Windows, Windows Phone, iOS, OSX, Android, and Linux. There you can also find full walkthroughs for authentication flows such as OAuth2, OpenID Connect, Graph API, and other features provided by Microsoft.
16
+
17
+ ## How to use this SDK
18
+
19
+ #### Installation
20
+
21
+ Add to your Gemfile:
22
+
23
+ ```ruby
24
+ gem 'omniauth-activedirectory'
25
+ ```
26
+
27
+ ### Usage
28
+
29
+ If you are already using OmniAuth, adding AzureAD is as simple as adding a new provider to your `OmniAuth::Builder`. The provider requires your AzureAD client id and your AzureAD tenant.
30
+
31
+ For example, in Rails you would add this in `config/initializers/omniauth.rb`:
32
+
33
+ ```ruby
34
+ Rails.application.config.middleware.use OmniAuth::Builder do
35
+ provider :activedirectory, ENV['AAD_CLIENT_ID'], ENV['AAD_TENANT']
36
+ # other providers here
37
+ end
38
+ ```
39
+
40
+ When you want to authenticate the user, simply redirect them to `/auth/activedirectory`. From there, OmniAuth will takeover. Once the user authenticates (or fails to authenticate), they will be redirected to `/auth/activedirectory/callback`. The authentication result is available in `request.env['omniauth.auth']`.
41
+
42
+ #### CSRF Concerns
43
+
44
+ Rails' built-in CSRF protection can cause some hassles with omniauth, since a `POST` request is being made to your application by the provider, without an anti forgery token from you application. We need to tells Rails not to perform this check on the specific action being used for authentication with omniauth. Typically, your callback will be routed to the `#create` action in the `Sessions` controller. If this is the case for your app, app the following line in the beggining of the sessions controller:
45
+ ```ruby
46
+ skip_before_action :verify_authenticity_token, only: :create
47
+ ```
48
+ Make sure that nothing sensitive is happening in this action that could expose your app to CSRF attacks. It should pretty much just get the data in the `POST` request and use it to create a new session.
49
+
50
+
51
+ ### Auth Hash
52
+
53
+ OmniAuth AzureAD tries to be consistent with the auth hash schema recommended by OmniAuth. [https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema](https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema).
54
+
55
+ Here's an example of an authentication hash available in the callback. You can access this hash as `request.env['omniauth.auth']`.
56
+
57
+ ```
58
+ :provider => "azureactivedirectory",
59
+ :uid => "123456abcdef",
60
+ :info => {
61
+ :name => "John Smith",
62
+ :email => "jsmith@contoso.net",
63
+ :first_name => "John",
64
+ :last_name => "Smith"
65
+ },
66
+ :credentials => {
67
+ :code => "ffdsjap9fdjw893-rt2wj8r9r32jnkdsflaofdsa9"
68
+ },
69
+ :extra => {
70
+ :session_state => '532fgdsgtfera32',
71
+ :raw_info => {
72
+ :id_token => "fjeri9wqrfe98r23.fdsaf121435rt.f42qfdsaf",
73
+ :id_token_claims => {
74
+ "aud" => "fdsafdsa-fdsafd-fdsa-sfdasfds",
75
+ "iss" => "https://sts.windows.net/fdsafdsa-fdsafdsa/",
76
+ "iat" => 53315113,
77
+ "nbf" => 53143215,
78
+ "exp" => 53425123,
79
+ "ver" => "1.0",
80
+ "tid" => "5ffdsa2f-dsafds-sda-sds",
81
+ "oid" => "fdsafdsaafdsa",
82
+ "upn" => "jsmith@contoso.com",
83
+ "sub" => "123456abcdef",
84
+ "nonce" => "fdsaf342rfdsafdsafsads"
85
+ },
86
+ :id_token_header => {
87
+ "typ" => "JWT",
88
+ "alg" => "RS256",
89
+ "x5t" => "fdsafdsafdsafdsa4t4er32",
90
+ "kid" => "tjiofpjd8ap9fgdsa44"
91
+ }
92
+ }
93
+ }
94
+ ```
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env rake
2
+
3
+ require 'rake'
4
+ require 'rspec/core/rake_task'
5
+ require 'rubocop/rake_task'
6
+
7
+ # This can be run with `bundle exec rake spec`.
8
+ RSpec::Core::RakeTask.new(:spec) do |t|
9
+ t.pattern = `git ls-files`.split("\n").select { |f| f.end_with? 'spec.rb' }
10
+ t.rspec_opts = '--format documentation'
11
+ end
12
+
13
+ # This can be run with `bundle exec rake rubocop`.
14
+ RuboCop::RakeTask.new(:rubocop) do |t|
15
+ t.patterns = `git ls-files`.split("\n").select do |f|
16
+ f.end_with?('.rb') && !f.start_with?('examples')
17
+
18
+ end
19
+ t.fail_on_error = false
20
+ end
21
+
22
+ task default: :spec
@@ -0,0 +1,6 @@
1
+ module OmniAuth
2
+ # The release version.
3
+ module ActiveDirectory
4
+ VERSION = '1.0.1'
5
+ end
6
+ end
@@ -0,0 +1,2 @@
1
+ require 'omniauth/activedirectory/version'
2
+ require 'omniauth/strategies/activedirectory'
@@ -0,0 +1,307 @@
1
+ require 'jwt'
2
+ require 'omniauth'
3
+ require 'openssl'
4
+ require 'securerandom'
5
+
6
+ module OmniAuth
7
+ module Strategies
8
+ # A strategy for authentication against Azure Active Directory.
9
+ class ActiveDirectory
10
+ include OmniAuth::ActiveDirectory
11
+ include OmniAuth::Strategy
12
+
13
+ class OAuthError < StandardError; end
14
+
15
+ ##
16
+ # The client id (key) and tenant must be configured when the OmniAuth
17
+ # middleware is installed. Example:
18
+ #
19
+ # require 'omniauth'
20
+ # require 'omniauth-activedirectory'
21
+ #
22
+ # use OmniAuth::Builder do
23
+ # provider :activedirectory, ENV['AAD_KEY'], ENV['AAD_TENANT']
24
+ # end
25
+ #
26
+ args [:client_id, :tenant]
27
+ option :client_id, nil
28
+ option :tenant, nil
29
+
30
+ # Field renaming is an attempt to fit the OmniAuth recommended schema as
31
+ # best as possible.
32
+ #
33
+ # @see https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema
34
+ uid { @claims['sub'] }
35
+ info do
36
+ { name: @claims['name'],
37
+ email: @claims['email'] || @claims['upn'],
38
+ first_name: @claims['given_name'],
39
+ last_name: @claims['family_name'] }
40
+ end
41
+ credentials { { code: @code } }
42
+ extra do
43
+ { session_state: @session_state,
44
+ raw_info:
45
+ { id_token: @id_token,
46
+ id_token_claims: @claims,
47
+ id_token_header: @header } }
48
+ end
49
+
50
+ DEFAULT_RESPONSE_TYPE = 'code id_token'
51
+ DEFAULT_RESPONSE_MODE = 'form_post'
52
+
53
+ ##
54
+ # Overridden method from OmniAuth::Strategy. This is the first step in the
55
+ # authentication process.
56
+ def request_phase
57
+ redirect authorize_endpoint_url
58
+ end
59
+
60
+ ##
61
+ # Overridden method from OmniAuth::Strategy. This is the second step in
62
+ # the authentication process. It is called after the user enters
63
+ # credentials at the authorization endpoint.
64
+ def callback_phase
65
+ error = request.params['error_reason'] || request.params['error']
66
+ fail(OAuthError, error) if error
67
+ @session_state = request.params['session_state']
68
+ @id_token = request.params['id_token']
69
+ @code = request.params['code']
70
+ @claims, @header = validate_and_parse_id_token(@id_token)
71
+ # validate_chash(@code, @claims, @header)
72
+ super
73
+ end
74
+
75
+ private
76
+
77
+ ##
78
+ # Constructs a one-time-use authorize_endpoint. This method will use
79
+ # a new nonce on each invocation.
80
+ #
81
+ # @return String
82
+ def authorize_endpoint_url
83
+ uri = URI(openid_config['authorization_endpoint'])
84
+ uri.query = URI.encode_www_form(client_id: client_id,
85
+ redirect_uri: callback_url,
86
+ response_mode: response_mode,
87
+ response_type: response_type,
88
+ nonce: new_nonce)
89
+ uri.to_s
90
+ end
91
+
92
+ ##
93
+ # The client id of the calling application. This must be configured where
94
+ # AD is installed as an OmniAuth strategy.
95
+ #
96
+ # @return String
97
+ def client_id
98
+ return options.client_id if options.client_id
99
+ fail StandardError, 'No client_id specified in AzureAD configuration.'
100
+ end
101
+
102
+ ##
103
+ # The expected id token issuer taken from the discovery endpoint.
104
+ #
105
+ # @return String
106
+ def issuer
107
+ openid_config['issuer']
108
+ end
109
+
110
+ ##
111
+ # Fetches the current signing keys for Azure AD. Note that there should
112
+ # always two available, and that they have a 6 week rollover.
113
+ #
114
+ # Each key is a hash with the following fields:
115
+ # kty, use, kid, x5t, n, e, x5c
116
+ #
117
+ # @return Array[Hash]
118
+ def fetch_signing_keys
119
+ response = JSON.parse(Net::HTTP.get(URI(signing_keys_url)))
120
+ response['keys']
121
+ rescue JSON::ParserError
122
+ raise StandardError, 'Unable to fetch AzureAD signing keys.'
123
+ end
124
+
125
+ ##
126
+ # Fetches the OpenId Connect configuration for the AzureAD tenant. This
127
+ # contains several import values, including:
128
+ #
129
+ # authorization_endpoint
130
+ # token_endpoint
131
+ # token_endpoint_auth_methods_supported
132
+ # jwks_uri
133
+ # response_types_supported
134
+ # response_modes_supported
135
+ # subject_types_supported
136
+ # id_token_signing_alg_values_supported
137
+ # scopes_supported
138
+ # issuer
139
+ # claims_supported
140
+ # microsoft_multi_refresh_token
141
+ # check_session_iframe
142
+ # end_session_endpoint
143
+ # userinfo_endpoint
144
+ #
145
+ # @return Hash
146
+ def fetch_openid_config
147
+ JSON.parse(Net::HTTP.get(URI(openid_config_url)))
148
+ rescue JSON::ParserError
149
+ raise StandardError, 'Unable to fetch OpenId configuration for ' \
150
+ 'AzureAD tenant.'
151
+ end
152
+
153
+ ##
154
+ # Generates a new nonce for one time use. Stores it in the session so
155
+ # multiple users don't share nonces. All nonces should be generated by
156
+ # this method.
157
+ #
158
+ # @return String
159
+ def new_nonce
160
+ session['omniauth-azure-activedirectory.nonce'] = SecureRandom.uuid
161
+ end
162
+
163
+ ##
164
+ # A memoized version of #fetch_openid_config.
165
+ #
166
+ # @return Hash
167
+ def openid_config
168
+ @openid_config ||= fetch_openid_config
169
+ end
170
+
171
+ ##
172
+ # The location of the OpenID configuration for the tenant.
173
+ #
174
+ # @return String
175
+ def openid_config_url
176
+ "https://login.windows.net/#{tenant}/.well-known/openid-configuration"
177
+ end
178
+
179
+ ##
180
+ # Returns the most recent nonce for the session and deletes it from the
181
+ # session.
182
+ #
183
+ # @return String
184
+ def read_nonce
185
+ session.delete('omniauth-azure-activedirectory.nonce')
186
+ end
187
+
188
+ ##
189
+ # The response_type that will be set in the authorization request query
190
+ # parameters. Can be overridden by the client, but it shouldn't need to
191
+ # be.
192
+ #
193
+ # @return String
194
+ def response_type
195
+ options[:response_type] || DEFAULT_RESPONSE_TYPE
196
+ end
197
+
198
+ ##
199
+ # The response_mode that will be set in the authorization request query
200
+ # parameters. Can be overridden by the client, but it shouldn't need to
201
+ # be.
202
+ #
203
+ # @return String
204
+ def response_mode
205
+ options[:response_mode] || DEFAULT_RESPONSE_MODE
206
+ end
207
+
208
+ ##
209
+ # The keys used to sign the id token JWTs. This is just a memoized version
210
+ # of #fetch_signing_keys.
211
+ #
212
+ # @return Array[Hash]
213
+ def signing_keys
214
+ @signing_keys ||= fetch_signing_keys
215
+ end
216
+
217
+ ##
218
+ # The location of the public keys of the token signer. This is parsed from
219
+ # the OpenId config response.
220
+ #
221
+ # @return String
222
+ def signing_keys_url
223
+ return openid_config['jwks_uri'] if openid_config.include? 'jwks_uri'
224
+ fail StandardError, 'No jwks_uri in OpenId config response.'
225
+ end
226
+
227
+ ##
228
+ # The tenant of the calling application. Note that this must be
229
+ # explicitly configured when installing the AzureAD OmniAuth strategy.
230
+ #
231
+ # @return String
232
+ def tenant
233
+ return options.tenant if options.tenant
234
+ fail StandardError, 'No tenant specified in AzureAD configuration.'
235
+ end
236
+
237
+ ##
238
+ # Verifies the signature of the id token as well as the exp, nbf, iat,
239
+ # iss, and aud fields.
240
+ #
241
+ # See OpenId Connect Core 3.1.3.7 and 3.2.2.11.
242
+ #
243
+ # @return Claims, Header
244
+ def validate_and_parse_id_token(id_token)
245
+ # The second parameter is the public key to verify the signature.
246
+ # However, that key is overridden by the value of the executed block
247
+ # if one is present.
248
+ #
249
+ # If you're thinking that this looks ugly with the raw nil and boolean,
250
+ # see https://github.com/jwt/ruby-jwt/issues/59.
251
+ jwt_claims, jwt_header =
252
+ JWT.decode(id_token, nil, false, verify_options) do |header|
253
+ # There should always be one key from the discovery endpoint that
254
+ # matches the id in the JWT header.
255
+ x5c = (signing_keys.find do |key|
256
+ key['kid'] == header['kid']
257
+ end || {})['x5c']
258
+ if x5c.nil? || x5c.empty?
259
+ fail JWT::VerificationError,
260
+ 'No keys from key endpoint match the id token'
261
+ end
262
+ # The key also contains other fields, such as n and e, that are
263
+ # redundant. x5c is sufficient to verify the id token.
264
+ OpenSSL::X509::Certificate.new(JWT.base64url_decode(x5c.first)).public_key
265
+ end
266
+ return jwt_claims, jwt_header if jwt_claims['nonce'] == read_nonce
267
+ fail JWT::DecodeError, 'Returned nonce did not match.'
268
+ end
269
+
270
+ ##
271
+ # Verifies that the c_hash the id token claims matches the authorization
272
+ # code. See OpenId Connect Core 3.3.2.11.
273
+ #
274
+ # @param String code
275
+ # @param Hash claims
276
+ # @param Hash header
277
+ # def validate_chash(code, claims, header)
278
+ # # This maps RS256 -> sha256, ES384 -> sha384, etc.
279
+ # algorithm = (header['alg'] || 'RS256').sub(/RS|ES|HS/, 'sha')
280
+ # full_hash = OpenSSL::Digest.new(algorithm).digest code
281
+ # c_hash = JWT.base64url_encode full_hash[0..full_hash.length / 2 - 1]
282
+ # return if c_hash == claims['c_hash']
283
+ # fail JWT::VerificationError,
284
+ # 'c_hash in id token does not match auth code.'
285
+ # end
286
+
287
+ ##
288
+ # The options passed to the Ruby JWT library to verify the id token.
289
+ # Note that these are not all the checks we perform. Some (like nonce)
290
+ # are not handled by the JWT API and are checked manually in
291
+ # #validate_and_parse_id_token.
292
+ #
293
+ # @return Hash
294
+ def verify_options
295
+ { verify_expiration: true,
296
+ verify_not_before: true,
297
+ verify_iat: true,
298
+ verify_iss: true,
299
+ 'iss' => issuer,
300
+ verify_aud: true,
301
+ 'aud' => client_id }
302
+ end
303
+ end
304
+ end
305
+ end
306
+
307
+ OmniAuth.config.add_camelization 'activedirectory', 'ActiveDirectory'
@@ -0,0 +1 @@
1
+ require 'omniauth/activedirectory'
@@ -0,0 +1,29 @@
1
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
2
+ require 'omniauth/activedirectory/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'omniauth-activedirectory'
6
+ s.version = OmniAuth::ActiveDirectory::VERSION
7
+ s.authors = ['Microsoft Corporation', 'Dave Van Fleet']
8
+ s.email = 'vanfleet@arsome.com'
9
+ s.summary = 'Azure Active Directory strategy for OmniAuth'
10
+ s.description = 'Allows developers to authenticate to Azure AD'
11
+ s.homepage = 'https://github.com/davevanfleet/omniauth-activedirectory'
12
+ s.license = 'MIT'
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.require_paths = ['lib']
16
+
17
+ s.required_ruby_version = '>= 2.2'
18
+
19
+ s.add_runtime_dependency 'jwt', '>= 2.0'
20
+ s.add_runtime_dependency 'oauth2', '~> 1.1'
21
+ s.add_runtime_dependency 'omniauth', '~> 2.0'
22
+ s.add_runtime_dependency 'omniauth-oauth2', '~> 1.7.1'
23
+
24
+ s.add_development_dependency 'rake', '~> 12.0'
25
+ s.add_development_dependency 'rspec', '~> 3.6'
26
+ s.add_development_dependency 'rubocop', '~> 0.49'
27
+ s.add_development_dependency 'simplecov', '~> 0.10'
28
+ s.add_development_dependency 'webmock', '~> 1.21'
29
+ end
@@ -0,0 +1 @@
1
+ eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImFiYzEyMyJ9.eyJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9idW5jaC1vZi1yYW5kb20tY2hhcnMiLCJuYW1lIjoiSm9obiBTbWl0aCIsImF1ZCI6InRoZSBjbGllbnQgaWQiLCJub25jZSI6Im15IG5vbmNlIiwiZ2l2ZW5fbmFtZSI6IkpvaG4iLCJmYW1pbHlfbmFtZSI6InNtaXRoIiwiZW1haWwiOiJqc21pdGhAY29udG9zby5jb20iLCJjX2hhc2giOiJWcFRRaWk1VF84cmd3eEEtV3RiMkJ3In0.Xz9SL1dm9xeJ3YtBIwSpL7SHEMr5lsL32mkJIugoAt7rNhj2ZauN77_N3skU9FIRTVb_XBFHrLo1AXion7RWoOGAMk8xnuQRlhamGoWsjttWE9oO6J6kuQPSDBvLTA88UqLoGNezDwFNfgUFQq-66m33ZWdkiNOFoFZ_In6DtAwxHZZUys-KoYD3iCbviUoBzU57aV-SBsWyComq39pDGpw03qZoa_xgRfujdVHG1DKlO5VG79kUE3ySYWJyBYVKUdAzjH1iotjpPA1svtqytn4CUldAMi4nnf7iq5SCJMb4ucu0mN6AhJH9ktY--fGY6_OidyiDe4F57ZzLw-3jOQ
@@ -0,0 +1 @@
1
+ eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImFiYzEyMyJ9.eyJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9idW5jaC1vZi1yYW5kb20tY2hhcnMiLCJuYW1lIjoiSm9obiBTbWl0aCIsImF1ZCI6Im5vdCB0aGUgY2xpZW50IGlkIiwibm9uY2UiOiJteSBub25jZSIsImdpdmVuX25hbWUiOiJKb2huIiwiZmFtaWx5X25hbWUiOiJzbWl0aCIsImVtYWlsIjoianNtaXRoQGNvbnRvc28uY29tIn0.gGCFTcGDBb2P5tPRj2ojUUiwOJoSslQlxEVTElZY6FCzCZzcypsnrYOB9Adkztp2AWF4wW9fT58lqXwaahKquXtK4wyK4KoNBxXBhS4sDMeNpVkK4914tT_6gecvyUsI_tlJaS0epd5c0mN9-1QjgvNEirY1L-XYaT290LmLYVYIFTEJXoSlnwvv081k0txdJZKr14JXd_bSLUbhGSd-NcGZkJuVmg2F_C65zd1wUsQOkV2iVdJ-ycaDJklv8-DFfDFIHQio8S9yqyieHwArRmTW9HzcoHhWBh2MIItszoTSbmQEF062NtNBPW8gyk1OSot5X9klJUhgPAAFqJ0TJQ
@@ -0,0 +1 @@
1
+ eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImFiYzEyMyJ9.eyJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9idW5jaC1vZi1yYW5kb20tY2hhcnMiLCJuYW1lIjoiSm9obiBTbWl0aCIsImF1ZCI6InRoZSBjbGllbnQgaWQiLCJub25jZSI6Im15IG5vbmNlIiwiZ2l2ZW5fbmFtZSI6IkpvaG4iLCJmYW1pbHlfbmFtZSI6InNtaXRoIiwiZW1haWwiOiJqc21pdGhAY29udG9zby5jb20iLCJjX2hhc2giOiI1WEhDdk9qcUgtbnJBXzNXNUJYaWJnIn0.EHPFrxMbr2EH1IZ15F3oP1yvrukadY4ggZSOxm625qPoMxfhv-QzFm0YMhkAG0cLM_LSHi_RgedDwTGuzOtIWqmheYzydnhtbIBeKmx0RSgdob6WeiTZwJ93VRiV4q82Qda41JaaIl_wdWd4lVyVstd9o9jPYMtKEVLgaNDrtHt6pPxEGCVraiaM6tVyKc5XIHu3wNaqle5UZZREU6oirwTCUhXDZkz1g5qY2-aWUdfFVsElSarJuMcxGDPD20hvx7T3D7SCHAF8WhKw3AwQyrodKWCo3cqDOz6vHymb_-ELkJc14GMbtJiyrf6XYySZZoseoI_WBDmLfKcK637xCw
@@ -0,0 +1 @@
1
+ eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImFiYzEyMyJ9.eyJpc3MiOiJodHRwczovL3N0cy5pbXBvc3Rlci5uZXQvYnVuY2gtb2YtcmFuZG9tLWNoYXJzIiwibmFtZSI6IkpvaG4gU21pdGgiLCJhdWQiOiJ0aGUgY2xpZW50IGlkIiwibm9uY2UiOiJteSBub25jZSIsImdpdmVuX25hbWUiOiJKb2huIiwiZmFtaWx5X25hbWUiOiJzbWl0aCIsImVtYWlsIjoianNtaXRoQGNvbnRvc28uY29tIn0.fwnJuRsif_Td3MfXoyADHidYJyPFdWSBBoLbVAu4Lz3-pmSln9Vgxl5KowqEKq2LX5n0aqyWVGLcoT-_G_PNXuizuNmssv5vreKLvDMpsFXt2irdwGYDCRki7KQPBk3bn12YjBzE2EqiRy7dTEG_0vWoh1RqoNP72BBL8xYQUlIOFleZhT5KGNYbh7rvcmDq7aA-xdaXT3QJfHCHpitW_zVzZ5Gok_awcdx_v3r3eFbG2IT0PfmT40Ljia0aP2i60KgsOLLHarYO51KFNDEfr1pUDf4IweaEzstbVLwk-_5ulJ5QgByhNJrmWDfrGeCQRk0SO2XX-EUsVn5ySVJ5CQ
@@ -0,0 +1 @@
1
+ eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImFiYzEyMzQifQ.eyJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9idW5jaC1vZi1yYW5kb20tY2hhcnMiLCJuYW1lIjoiSm9obiBTbWl0aCIsImF1ZCI6InRoZSBjbGllbnQgaWQiLCJub25jZSI6Im15IG5vbmNlIiwiZ2l2ZW5fbmFtZSI6IkpvaG4iLCJmYW1pbHlfbmFtZSI6InNtaXRoIiwiZW1haWwiOiJqc21pdGhAY29udG9zby5jb20iLCJjX2hhc2giOiI1WEhDdk9qcUgtbnJBXzNXNUJYaWJnIn0.gWGBc9rH30SN17Ikm1CjqIYAyzFHX0yeRQu85sVYLE3r5k26bjS3R6rTJcCQlYqHPRdoPcnkUgT1QVbdThw34ICrODoavs7I5QYEn_jKP9zM4UJEKQaCLBAtitzrk1KDEf0GLcNKif-MYu7MiQfoOzwCGWfIs-vgqk4lv0JUs9OlSLp5LHru7G3jKy6Qswbrpxpjzm9I8BnKEdhUfhz4P6wIf9KLMmhgeGQdQ6wBuxPmOf9r6EKIij2AENhFp1qP90m8kXq9tIt5FZFjwIs_G6spLl0gQXyx0qC8rP5JTkqwrBUieWU-BRqVdax8YxA0iDKzZyfsMV92yVcZT6S_NQ
@@ -0,0 +1 @@
1
+ eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImFiYzEyMyJ9.eyJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9idW5jaC1vZi1yYW5kb20tY2hhcnMiLCJuYW1lIjoiSm9obiBTbWl0aCIsImF1ZCI6InRoZSBjbGllbnQgaWQiLCJub25jZSI6Im5vdCBteSBub25jZSIsImdpdmVuX25hbWUiOiJKb2huIiwiZmFtaWx5X25hbWUiOiJzbWl0aCIsImVtYWlsIjoianNtaXRoQGNvbnRvc28uY29tIn0.KBSOCiy0sUF33akept9nPNFgmMWxiPWDBVA0dZqQaF6gQkhQu82irAQzB2Ygkh9KDeIEf0MSZWLDq0X3W3Fke4wzjrbzL-2QM4l-KgPFbJixqtJYHSPOidHSCQ8vA0v8kES3H_zqU6QisygwwXLh2ozqKXMnsrBPIAtiZz_a0vPbHtrYbb-WIrtTruMemcTt5OkbfDIttzi5EarakQg93vraIb0jK0szuAqLkXFOzcIIGPgyAvVpHZveqm99GR04tbKyTRIyJP1vZwtIpu89PKFM3soWcWd_kjAWcS81ZTzEn5_P-1QL7YTInK53acNXZHh08Fba3Um4J_KlV2KRjw
@@ -0,0 +1 @@
1
+ eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6ImFiYzEyMyJ9.eyJpc3MiOiJodHRwczovL3N0cy53aW5kb3dzLm5ldC9idW5jaC1vZi1yYW5kb20tY2hhcnMiLCJuYW1lIjoiSm9obiBTbWl0aCIsImF1ZCI6InRoZSBjbGllbnQgaWQiLCJub25jZSI6Im15IG5vbmNlIiwiZ2l2ZW5fbmFtZSI6IkpvaG4iLCJmYW1pbHlfbmFtZSI6InNtaXRoIiwiZW1haWwiOiJqc21pdGhAY29udG9zby5jb20iLCJjX2hhc2giOiJWcFRRaWk1VF84cmd3eEEtV3RiMkJ3In0.Xz9SL1dm9xeJ3YtBIwSpL7SHEMr5lsL32mkJIugoAt7rNhj2ZauN77_N3skU9FIRTVb_XBFHrLo1AXion7RWoOGAMk8xnuQRlhamGoWsjttWE9oO6J6kuQPSDBvLTA88UqLoGNezDwFNfgUFQq-66m33ZWdkiNOFoFZ_In6DtAwxHZZUys-KoYD3iCbviUoBzU57aV-SBsWyComq39pDGpw03qZoa_xgRfujdVHG1DKlO5VG79kUE3ySYWJyBYVKUdAzjH1iotjpPA1svtqytn4CUldAMi4nnf7iq5SCJMb4ucu0mN6AhJH9ktY--fGY6_OidyiDe4F57ZzLw-3jOQ
@@ -0,0 +1 @@
1
+ MIIBwzCCAbegAwIBAgIBATADBgEAMDAxEzARBgoJkiaJk_IsZAEZFgNvcmcxGTAXBgoJkiaJk_IsZAEZFglydWJ5LWxhbmcwHhcNMTUwODA2MjMyOTE4WhcNMjUwODAzMjMyOTE4WjAwMRMwEQYKCZImiZPyLGQBGRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVieS1sYW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxyunSConbK4z1T47vukPa0OaNcY_R6l8Z0TILR1w5O_YkMbJGRXpZORFPVs83xLoxs7RcPWnibQhQ4G6m6fwEA4rutvOm-3xWyey-OOZdVqpNmxqd2VcCCI6AoUtl8m4w0UFuu-oiELj7BF8cGS5wvHYATEBEY72n_84uu-LF423Ffe8HeMEY00nO3ZVcV9MjFBVps8RAwL62ooXPZyly6fQt4728wlZPs3EMijS-Bj4auokx6ssBooaF9XiZJKKCAe16epbBB9S4XVlNXo6EhZ-PBpMFRJknDwWFFYPVOX3NlBp8chi8VaXmDXqsFJiwkkeIqg4I6WFAM4BsnDInwIDAQABMAMGAQADAQA
@@ -0,0 +1 @@
1
+ MIIBjTCCAYGgAwIBAgIBATADBgEAMBUxEzARBgoJkiaJk_IsZAEZFgNvcmcwHhcNMTUwODA3MjAyMDU1WhcNMjUwODA0MjAyMDU1WjAVMRMwEQYKCZImiZPyLGQBGRYDb3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy8VyE4KHx0GDV6RMYqscBR56lal9uQNYXm_Du8O6-F8Da9Xc0h7O8JWomqFLUEE-0ogMcjzOAiQzTc8X6VhkIBbMCKYA6OQ-hiC3aaYFLNAnxaVThnUJWXxA7spbnKFG1xZK01G8bAx7s7DbbWMHlchebjWprCMkYEjnECXVuDyfkZW-8aHDCtq62JAd-WQL1LN-UkOBCgodTNW2x7e-_KBvPzPSSzYygAh7kCl727QeHwplgA83mQrdecNvYoiEBYOjSKz8bdiKRYjmogGoDv3_W4cY76a9XBZpSoNjBWdWo_w7ce4KbOsi3V0g8EZm9ccKjBPKe9pZYF4aCNQJ6QIDAQABMAMGAQADAQA
@@ -0,0 +1,200 @@
1
+ require 'spec_helper'
2
+ require 'omniauth-activedirectory'
3
+
4
+ # This was fairly awkward to test. I've stubbed every endpoint and am simulating
5
+ # the state of the request. Especially large strings are stored in fixtures.
6
+ describe OmniAuth::Strategies::ActiveDirectory do
7
+ let(:app) { -> _ { [200, {}, ['Hello world.']] } }
8
+ let(:x5c) { File.read(File.expand_path('../../../fixtures/x5c.txt', __FILE__)) }
9
+
10
+ # These values were used to create the "successful" id_token JWT.
11
+ let(:client_id) { 'the client id' }
12
+ let(:code) { 'code' }
13
+ let(:email) { 'jsmith@contoso.com' }
14
+ let(:family_name) { 'smith' }
15
+ let(:given_name) { 'John' }
16
+ let(:issuer) { 'https://sts.windows.net/bunch-of-random-chars' }
17
+ let(:kid) { 'abc123' }
18
+ let(:name) { 'John Smith' }
19
+ let(:nonce) { 'my nonce' }
20
+ let(:session_state) { 'session state' }
21
+ let(:auth_endpoint_host) { 'authorize.com' }
22
+
23
+ let(:hybrid_flow_params) do
24
+ { 'id_token' => id_token,
25
+ 'session_state' => session_state,
26
+ 'code' => code }
27
+ end
28
+
29
+ let(:tenant) { 'tenant' }
30
+ let(:openid_config_response) { "{\"issuer\":\"#{issuer}\",\"authorization_endpoint\":\"http://#{auth_endpoint_host}\",\"jwks_uri\":\"https://login.windows.net/common/discovery/keys\"}" }
31
+ let(:keys_response) { "{\"keys\":[{\"kid\":\"#{kid}\",\"x5c\":[\"#{x5c}\"]}]}" }
32
+
33
+ let(:env) { { 'rack.session' => { 'omniauth-azure-activedirectory.nonce' => nonce } } }
34
+
35
+ before(:each) do
36
+ stub_request(:get, "https://login.windows.net/#{tenant}/.well-known/openid-configuration")
37
+ .to_return(status: 200, body: openid_config_response)
38
+ stub_request(:get, 'https://login.windows.net/common/discovery/keys')
39
+ .to_return(status: 200, body: keys_response)
40
+ end
41
+
42
+ describe '#callback_phase' do
43
+ let(:request) { double('Request', params: hybrid_flow_params, path_info: 'path') }
44
+ let(:strategy) do
45
+ described_class.new(app, client_id, tenant).tap do |s|
46
+ allow(s).to receive(:request) { request }
47
+ end
48
+ end
49
+
50
+ subject { -> { strategy.callback_phase } }
51
+ before(:each) { strategy.call!(env) }
52
+
53
+ context 'with a successful response' do
54
+ # payload:
55
+ # { 'iss' => 'https://sts.windows.net/bunch-of-random-chars',
56
+ # 'name' => 'John Smith',
57
+ # 'aud' => 'the client id',
58
+ # 'nonce' => 'my nonce',
59
+ # 'email' => 'jsmith@contoso.com',
60
+ # 'given_name' => 'John',
61
+ # 'family_name' => 'Smith' }
62
+ # headers:
63
+ # { 'typ' => 'JWT',
64
+ # 'alg' => 'RS256',
65
+ # 'kid' => 'abc123' }
66
+ #
67
+ let(:id_token) { File.read(File.expand_path('../../../fixtures/id_token.txt', __FILE__)) }
68
+
69
+ # If it passes this test, then the id was successfully validated.
70
+ it { is_expected.to_not raise_error }
71
+
72
+ describe 'the auth hash' do
73
+ before(:each) { strategy.callback_phase }
74
+
75
+ subject { env['omniauth.auth'] }
76
+
77
+ it 'should contain the name' do
78
+ expect(subject.info['name']).to eq name
79
+ end
80
+
81
+ it 'should contain the first name' do
82
+ expect(subject.info['first_name']).to eq given_name
83
+ end
84
+
85
+ it 'should contain the last name' do
86
+ expect(subject.info['last_name']).to eq family_name
87
+ end
88
+
89
+ it 'should contain the email' do
90
+ expect(subject.info['email']).to eq email
91
+ end
92
+
93
+ it 'should contain the auth code' do
94
+ expect(subject.credentials['code']).to eq code
95
+ end
96
+
97
+ it 'should contain the session state' do
98
+ expect(subject.extra['session_state']).to eq session_state
99
+ end
100
+ end
101
+ end
102
+
103
+ context 'with an invalid issuer' do
104
+ # payload:
105
+ # { 'iss' => 'https://sts.imposter.net/bunch-of-random-chars', ... }
106
+ #
107
+ let(:id_token) { File.read(File.expand_path('../../../fixtures/id_token_bad_issuer.txt', __FILE__)) }
108
+ it { is_expected.to raise_error JWT::InvalidIssuerError }
109
+ end
110
+
111
+ context 'with an invalid audience' do
112
+ # payload:
113
+ # { 'aud' => 'not the client id', ... }
114
+ #
115
+ let(:id_token) { File.read(File.expand_path('../../../fixtures/id_token_bad_audience.txt', __FILE__)) }
116
+ it { is_expected.to raise_error JWT::InvalidAudError }
117
+ end
118
+
119
+ context 'with a non-matching nonce' do
120
+ # payload:
121
+ # { 'nonce' => 'not my nonce', ... }
122
+ #
123
+ let(:id_token) { File.read(File.expand_path('../../../fixtures/id_token_bad_nonce.txt', __FILE__)) }
124
+ it { is_expected.to raise_error JWT::DecodeError }
125
+ end
126
+
127
+ context 'with the wrong x5c' do
128
+ let(:x5c) { File.read(File.expand_path('../../../fixtures/x5c_different.txt', __FILE__)) }
129
+ let(:id_token) { File.read(File.expand_path('../../../fixtures/id_token.txt', __FILE__)) }
130
+ it { is_expected.to raise_error JWT::VerificationError }
131
+ end
132
+
133
+ context 'with a non-matching c_hash' do
134
+ let(:id_token) { File.read(File.expand_path('../../../fixtures/id_token_bad_chash.txt', __FILE__)) }
135
+ it { is_expected.to raise_error JWT::VerificationError }
136
+ end
137
+
138
+ context 'with a non-matching kid' do
139
+ let(:id_token) { File.read(File.expand_path('../../../fixtures/id_token_bad_kid.txt', __FILE__)) }
140
+ it { is_expected.to raise_error JWT::VerificationError }
141
+ end
142
+
143
+ context 'with no alg header' do
144
+ let(:id_token) { File.read(File.expand_path('../../../fixtures/id_token_no_alg.txt', __FILE__)) }
145
+
146
+ it 'should correctly parse using default RS256' do
147
+ expect(subject).to_not raise_error
148
+ end
149
+
150
+ describe 'the auth hash' do
151
+ subject { env['omniauth.auth'] }
152
+ before(:each) { strategy.callback_phase }
153
+
154
+ it 'should default to RS256' do
155
+ expect(subject.info['name']).to eq name
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ describe '#request_phase' do
162
+ let(:strategy) { described_class.new(app, client_id, tenant) }
163
+ subject { strategy.request_phase }
164
+ before(:each) { strategy.call!(env) }
165
+
166
+ it 'should make a redirect' do
167
+ expect(subject.first).to eq 302
168
+ end
169
+
170
+ it 'should redirect to the correct endpoint' do
171
+ expect(URI(subject[1]['Location']).host).to eq auth_endpoint_host
172
+ end
173
+ end
174
+
175
+ describe '#read_nonce' do
176
+ let(:strategy) { described_class.new(app, client_id, tenant) }
177
+ let(:env) { { 'rack.session' => {} } }
178
+ before(:each) { strategy.call!(env) }
179
+ subject { strategy.send(:read_nonce) }
180
+
181
+ context 'before a nonce is set' do
182
+ it { is_expected.to be nil }
183
+ end
184
+
185
+ context 'after a nonce is set' do
186
+ before(:each) { @nonce = strategy.send(:new_nonce) }
187
+ it 'should match' do
188
+ expect(subject).to eq @nonce
189
+ end
190
+ end
191
+
192
+ context 'twice in a row' do
193
+ before(:each) do
194
+ strategy.send(:new_nonce)
195
+ strategy.send(:read_nonce)
196
+ end
197
+ it { is_expected.to be nil }
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,44 @@
1
+ #-------------------------------------------------------------------------------
2
+ # Copyright (c) 2015 Micorosft Corporation
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ # of this software and associated documentation files (the "Software"), to deal
6
+ # in the Software without restriction, including without limitation the rights
7
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ # copies of the Software, and to permit persons to whom the Software is
9
+ # furnished to do so, subject to the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be included in
12
+ # all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ # THE SOFTWARE.
21
+ #-------------------------------------------------------------------------------
22
+
23
+ require 'webmock/rspec'
24
+ require 'simplecov'
25
+
26
+ SimpleCov.start do
27
+ # Don't measure coverage on test files.
28
+ add_filter 'spec'
29
+ end
30
+
31
+ WebMock.disable_net_connect!(allow_localhost: true)
32
+
33
+ RSpec.configure do |config|
34
+ config.expect_with :rspec do |expectations|
35
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
36
+ end
37
+
38
+ config.mock_with :rspec do |mocks|
39
+ mocks.verify_partial_doubles = true
40
+ end
41
+
42
+ config.warnings = true
43
+ config.order = :random
44
+ end
metadata ADDED
@@ -0,0 +1,192 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omniauth-activedirectory
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Microsoft Corporation
8
+ - Dave Van Fleet
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2021-03-18 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: jwt
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '2.0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '2.0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: oauth2
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: '1.1'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '1.1'
42
+ - !ruby/object:Gem::Dependency
43
+ name: omniauth
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '2.0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '2.0'
56
+ - !ruby/object:Gem::Dependency
57
+ name: omniauth-oauth2
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: 1.7.1
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: 1.7.1
70
+ - !ruby/object:Gem::Dependency
71
+ name: rake
72
+ requirement: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '12.0'
77
+ type: :development
78
+ prerelease: false
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '12.0'
84
+ - !ruby/object:Gem::Dependency
85
+ name: rspec
86
+ requirement: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '3.6'
91
+ type: :development
92
+ prerelease: false
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: '3.6'
98
+ - !ruby/object:Gem::Dependency
99
+ name: rubocop
100
+ requirement: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: '0.49'
105
+ type: :development
106
+ prerelease: false
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: '0.49'
112
+ - !ruby/object:Gem::Dependency
113
+ name: simplecov
114
+ requirement: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - "~>"
117
+ - !ruby/object:Gem::Version
118
+ version: '0.10'
119
+ type: :development
120
+ prerelease: false
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: '0.10'
126
+ - !ruby/object:Gem::Dependency
127
+ name: webmock
128
+ requirement: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - "~>"
131
+ - !ruby/object:Gem::Version
132
+ version: '1.21'
133
+ type: :development
134
+ prerelease: false
135
+ version_requirements: !ruby/object:Gem::Requirement
136
+ requirements:
137
+ - - "~>"
138
+ - !ruby/object:Gem::Version
139
+ version: '1.21'
140
+ description: Allows developers to authenticate to Azure AD
141
+ email: vanfleet@arsome.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".gitignore"
147
+ - ".rubocop.yml"
148
+ - ".rubocop_todo.yml"
149
+ - Gemfile
150
+ - LICENSE.txt
151
+ - README.md
152
+ - Rakefile
153
+ - lib/omniauth-activedirectory.rb
154
+ - lib/omniauth/activedirectory.rb
155
+ - lib/omniauth/activedirectory/version.rb
156
+ - lib/omniauth/strategies/activedirectory.rb
157
+ - omniauth-activedirectory.gemspec
158
+ - spec/fixtures/id_token.txt
159
+ - spec/fixtures/id_token_bad_audience.txt
160
+ - spec/fixtures/id_token_bad_chash.txt
161
+ - spec/fixtures/id_token_bad_issuer.txt
162
+ - spec/fixtures/id_token_bad_kid.txt
163
+ - spec/fixtures/id_token_bad_nonce.txt
164
+ - spec/fixtures/id_token_no_alg.txt
165
+ - spec/fixtures/x5c.txt
166
+ - spec/fixtures/x5c_different.txt
167
+ - spec/omniauth/strategies/activedirectory_spec.rb
168
+ - spec/spec_helper.rb
169
+ homepage: https://github.com/davevanfleet/omniauth-activedirectory
170
+ licenses:
171
+ - MIT
172
+ metadata: {}
173
+ post_install_message:
174
+ rdoc_options: []
175
+ require_paths:
176
+ - lib
177
+ required_ruby_version: !ruby/object:Gem::Requirement
178
+ requirements:
179
+ - - ">="
180
+ - !ruby/object:Gem::Version
181
+ version: '2.2'
182
+ required_rubygems_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ requirements: []
188
+ rubygems_version: 3.2.3
189
+ signing_key:
190
+ specification_version: 4
191
+ summary: Azure Active Directory strategy for OmniAuth
192
+ test_files: []