omniauth_openid_connect 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
+ SHA1:
3
+ metadata.gz: acc382de3a9187fc1fc72053e311d7d82f579351
4
+ data.tar.gz: 38f48f09a1c3886b5a5e64da87614f76ce7d157b
5
+ SHA512:
6
+ metadata.gz: 300022e2fbe8589c5e3d791e468263015260256e51a34f8da390c30b5ee46c5da22d5556cb4acc7d89f40bbad6b2aae6dbcc916b997ee6aeb8eebd1ad8dd77f2
7
+ data.tar.gz: dbc66b01bec8c313449b56f4248925989621eab47790ff541fb338719287014926f208a1b0cf2e22ce53e938c98b8ee622a25eafb7c955d4ce7332ddd4683429
data/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ InstalledFiles
7
+ _yardoc
8
+ coverage
9
+ doc/
10
+ lib/bundler/man
11
+ pkg
12
+ rdoc
13
+ spec/reports
14
+ test/tmp
15
+ test/version_tmp
16
+ tmp
17
+ .ruby-version
18
+ .ruby-gemset
19
+ Gemfile.lock
data/.travis.yml ADDED
@@ -0,0 +1,9 @@
1
+ before_install:
2
+ - gem update bundler
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1.0
7
+ - 2.2.0
8
+ - 2.3.0
9
+ - rbx
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,14 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard 'minitest' do
5
+ # with Minitest::Unit
6
+ watch(%r|^test/(.*)\/(.*)_test\.rb|)
7
+ watch(%r|^lib/(.*)\.rb|) { |m| "test/lib/#{m[1]}_test.rb" }
8
+ watch(%r|^test/test_helper\.rb|) { "test" }
9
+ end
10
+
11
+ guard :bundler do
12
+ watch('Gemfile')
13
+ watch(/^.+\.gemspec/)
14
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 John Bohn
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,71 @@
1
+ # OmniAuth::OpenIDConnect
2
+
3
+ OpenID Connect strategy for OmniAuth
4
+ [![Gem Version](https://badge.fury.io/rb/omniauth-openid-connect.png)](http://badge.fury.io/rb/omniauth-openid-connect)
5
+ [![Build Status](https://travis-ci.org/jjbohn/omniauth-openid-connect.png?branch=master)](https://travis-ci.org/jjbohn/omniauth-openid-connect)
6
+ [![Coverage Status](https://coveralls.io/repos/jjbohn/omniauth-openid-connect/badge.png?branch=master)](https://coveralls.io/r/jjbohn/omniauth-openid-connect?branch=master)
7
+ [![Code Climate](https://codeclimate.com/github/jjbohn/omniauth-openid-connect.png)](https://codeclimate.com/github/jjbohn/omniauth-openid-connect)
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'omniauth-openid-connect'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install omniauth-openid-connect
22
+
23
+ ## Usage
24
+
25
+ Example configuration
26
+ ```ruby
27
+ config.omniauth :openid_connect, {
28
+ name: :my_provider,
29
+ scope: [:openid, :email, :profile, :address],
30
+ response_type: :code,
31
+ client_options: {
32
+ port: 443,
33
+ scheme: "https",
34
+ host: "myprovider.com",
35
+ identifier: ENV["OP_CLIENT_ID"],
36
+ secret: ENV["OP_SECRET_KEY"],
37
+ redirect_uri: "http://myapp.com/users/auth/openid_connect/callback",
38
+ },
39
+ }
40
+ ```
41
+
42
+ Configuration details:
43
+ * `name` is arbitrary, I recommend using the name of your provider. The name
44
+ configuration exists because you could be using multiple OpenID Connect
45
+ providers in a single app.
46
+ * Although `response_type` is an available option, currently, only `:code`
47
+ is valid. There are plans to bring in implicit flow and hybrid flow at some
48
+ point, but it hasn't come up yet for me. Those flows aren't best practive for
49
+ server side web apps anyway and are designed more for native/mobile apps.
50
+ * If you want to pass `state` paramete by yourself. You can set Proc Object.
51
+ e.g. `state: Proc.new{ SecureRandom.hex(32) }`
52
+ * `nonce` is optional. If don't want to pass "nonce" parameter to provider, You should specify
53
+ `false` to `send_nonce` option. (default true)
54
+ * Support for other client authentication methods. If don't specified
55
+ `:client_auth_method` option, automatically set `:basic`.
56
+ * Use "OpenID Connect Discovery", You should specify `true` to `discovery` option. (default false)
57
+ * In "OpenID Connect Discovery", generally provider should have Webfinger endpoint.
58
+ If provider does not have Webfinger endpoint, You can specify "Issuer" to option.
59
+ e.g. `issuer: "https://myprovider.com"`
60
+ It means to get configuration from "https://myprovider.com/.well-known/openid-configuration".
61
+
62
+ For the full low down on OpenID Connect, please check out
63
+ [the spec](http://openid.net/specs/openid-connect-core-1_0.html).
64
+
65
+ ## Contributing
66
+
67
+ 1. Fork it ( http://github.com/jjbohn/omniauth-openid-connect/fork )
68
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
69
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
70
+ 4. Push to the branch (`git push origin my-new-feature`)
71
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'test'
6
+ t.test_files = FileList['test/lib/omniauth/**/*_test.rb']
7
+ t.verbose = true
8
+ end
9
+
10
+ task default: :test
@@ -0,0 +1,3 @@
1
+ require 'omniauth/openid_connect/errors'
2
+ require 'omniauth/openid_connect/version'
3
+ require 'omniauth/strategies/openid_connect'
@@ -0,0 +1,6 @@
1
+ module OmniAuth
2
+ module OpenIDConnect
3
+ class Error < RuntimeError; end
4
+ class MissingCodeError < Error; end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module OmniAuth
2
+ module OpenIDConnect
3
+ VERSION = '0.1'
4
+ end
5
+ end
@@ -0,0 +1,253 @@
1
+ require 'addressable/uri'
2
+ require 'timeout'
3
+ require 'net/http'
4
+ require 'open-uri'
5
+ require 'omniauth'
6
+ require 'openid_connect'
7
+
8
+ module OmniAuth
9
+ module Strategies
10
+ class OpenIDConnect
11
+ include OmniAuth::Strategy
12
+
13
+ option :client_options, {
14
+ identifier: nil,
15
+ secret: nil,
16
+ redirect_uri: nil,
17
+ scheme: 'https',
18
+ host: nil,
19
+ port: 443,
20
+ authorization_endpoint: '/authorize',
21
+ token_endpoint: '/token',
22
+ userinfo_endpoint: '/userinfo',
23
+ jwks_uri: '/jwk'
24
+ }
25
+ option :issuer
26
+ option :discovery, false
27
+ option :client_signing_alg
28
+ option :client_jwk_signing_key
29
+ option :client_x509_signing_key
30
+ option :scope, [:openid]
31
+ option :response_type, "code"
32
+ option :state
33
+ option :response_mode
34
+ option :display, nil #, [:page, :popup, :touch, :wap]
35
+ option :prompt, nil #, [:none, :login, :consent, :select_account]
36
+ option :hd, nil
37
+ option :max_age
38
+ option :ui_locales
39
+ option :id_token_hint
40
+ option :login_hint
41
+ option :acr_values
42
+ option :send_nonce, true
43
+ option :send_scope_to_token_endpoint, true
44
+ option :client_auth_method
45
+
46
+ uid { user_info.sub }
47
+
48
+ info do
49
+ {
50
+ name: user_info.name,
51
+ email: user_info.email,
52
+ nickname: user_info.preferred_username,
53
+ first_name: user_info.given_name,
54
+ last_name: user_info.family_name,
55
+ gender: user_info.gender,
56
+ image: user_info.picture,
57
+ phone: user_info.phone_number,
58
+ urls: { website: user_info.website }
59
+ }
60
+ end
61
+
62
+ extra do
63
+ { raw_info: user_info.raw_attributes }
64
+ end
65
+
66
+ credentials do
67
+ {
68
+ id_token: access_token.id_token,
69
+ token: access_token.access_token,
70
+ refresh_token: access_token.refresh_token,
71
+ expires_in: access_token.expires_in,
72
+ scope: access_token.scope
73
+ }
74
+ end
75
+
76
+ def client
77
+ @client ||= ::OpenIDConnect::Client.new(client_options)
78
+ end
79
+
80
+ def config
81
+ @config ||= ::OpenIDConnect::Discovery::Provider::Config.discover!(options.issuer)
82
+ end
83
+
84
+ def request_phase
85
+ options.issuer = issuer if options.issuer.blank?
86
+ discover! if options.discovery
87
+ redirect authorize_uri
88
+ end
89
+
90
+ def callback_phase
91
+ error = request.params['error_reason'] || request.params['error']
92
+ if error
93
+ raise CallbackError.new(request.params['error'], request.params['error_description'] || request.params['error_reason'], request.params['error_uri'])
94
+ elsif request.params['state'].to_s.empty? || request.params['state'] != stored_state
95
+ return Rack::Response.new(['401 Unauthorized'], 401).finish
96
+ elsif !request.params['code']
97
+ return fail!(:missing_code, OmniAuth::OpenIDConnect::MissingCodeError.new(request.params['error']))
98
+ else
99
+ options.issuer = issuer if options.issuer.blank?
100
+ discover! if options.discovery
101
+ client.redirect_uri = redirect_uri
102
+ client.authorization_code = authorization_code
103
+ access_token
104
+ super
105
+ end
106
+ rescue CallbackError => e
107
+ fail!(:invalid_credentials, e)
108
+ rescue ::Timeout::Error, ::Errno::ETIMEDOUT => e
109
+ fail!(:timeout, e)
110
+ rescue ::SocketError => e
111
+ fail!(:failed_to_connect, e)
112
+ end
113
+
114
+ def authorization_code
115
+ request.params['code']
116
+ end
117
+
118
+ def authorize_uri
119
+ client.redirect_uri = redirect_uri
120
+ opts = {
121
+ response_type: options.response_type,
122
+ scope: options.scope,
123
+ state: new_state,
124
+ nonce: (new_nonce if options.send_nonce),
125
+ hd: options.hd,
126
+ }
127
+ client.authorization_uri(opts.reject { |k, v| v.nil? })
128
+ end
129
+
130
+ def public_key
131
+ return config.jwks if options.discovery
132
+ key_or_secret
133
+ end
134
+
135
+ private
136
+
137
+ def issuer
138
+ resource = "#{ client_options.scheme }://#{ client_options.host }"
139
+ resource = "#{ resource }:#{ client_options.port }" if client_options.port
140
+ ::OpenIDConnect::Discovery::Provider.discover!(resource).issuer
141
+ end
142
+
143
+ def discover!
144
+ client_options.authorization_endpoint = config.authorization_endpoint
145
+ client_options.token_endpoint = config.token_endpoint
146
+ client_options.userinfo_endpoint = config.userinfo_endpoint
147
+ client_options.jwks_uri = config.jwks_uri
148
+ end
149
+
150
+ def user_info
151
+ @user_info ||= access_token.userinfo!
152
+ end
153
+
154
+ def access_token
155
+ @access_token ||= begin
156
+ _access_token = client.access_token!(
157
+ scope: (options.scope if options.send_scope_to_token_endpoint),
158
+ client_auth_method: options.client_auth_method
159
+ )
160
+ _id_token = decode_id_token _access_token.id_token
161
+ _id_token.verify!(
162
+ issuer: options.issuer,
163
+ client_id: client_options.identifier,
164
+ nonce: stored_nonce
165
+ )
166
+ _access_token
167
+ end
168
+ end
169
+
170
+ def decode_id_token(id_token)
171
+ ::OpenIDConnect::ResponseObject::IdToken.decode(id_token, public_key)
172
+ end
173
+
174
+ def client_options
175
+ options.client_options
176
+ end
177
+
178
+ def new_state
179
+ state = options.state.call if options.state.respond_to? :call
180
+ session['omniauth.state'] = state || SecureRandom.hex(16)
181
+ end
182
+
183
+ def stored_state
184
+ session.delete('omniauth.state')
185
+ end
186
+
187
+ def new_nonce
188
+ session['omniauth.nonce'] = SecureRandom.hex(16)
189
+ end
190
+
191
+ def stored_nonce
192
+ session.delete('omniauth.nonce')
193
+ end
194
+
195
+ def session
196
+ return {} if @env.nil?
197
+ super
198
+ end
199
+
200
+ def key_or_secret
201
+ case options.client_signing_alg
202
+ when :HS256, :HS384, :HS512
203
+ return client_options.secret
204
+ when :RS256, :RS384, :RS512
205
+ if options.client_jwk_signing_key
206
+ return parse_jwk_key(options.client_jwk_signing_key)
207
+ elsif options.client_x509_signing_key
208
+ return parse_x509_key(options.client_x509_signing_key)
209
+ end
210
+ else
211
+ end
212
+ end
213
+
214
+ def parse_x509_key(key)
215
+ OpenSSL::X509::Certificate.new(key).public_key
216
+ end
217
+
218
+ def parse_jwk_key(key)
219
+ json = JSON.parse(key)
220
+ if json.has_key?('keys')
221
+ JSON::JWK::Set.new json['keys']
222
+ else
223
+ JSON::JWK.new json
224
+ end
225
+ end
226
+
227
+ def decode(str)
228
+ UrlSafeBase64.decode64(str).unpack('B*').first.to_i(2).to_s
229
+ end
230
+
231
+ def redirect_uri
232
+ return client_options.redirect_uri unless request.params['redirect_uri']
233
+ "#{ client_options.redirect_uri }?redirect_uri=#{ CGI.escape(request.params['redirect_uri']) }"
234
+ end
235
+
236
+ class CallbackError < StandardError
237
+ attr_accessor :error, :error_reason, :error_uri
238
+
239
+ def initialize(error, error_reason=nil, error_uri=nil)
240
+ self.error = error
241
+ self.error_reason = error_reason
242
+ self.error_uri = error_uri
243
+ end
244
+
245
+ def message
246
+ [error, error_reason, error_uri].compact.join(' | ')
247
+ end
248
+ end
249
+ end
250
+ end
251
+ end
252
+
253
+ OmniAuth.config.add_camelization 'openid_connect', 'OpenIDConnect'
@@ -0,0 +1 @@
1
+ require 'omniauth/openid_connect'
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'omniauth/openid_connect/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'omniauth_openid_connect'
8
+ spec.version = OmniAuth::OpenIDConnect::VERSION
9
+ spec.authors = 'John Bohn'
10
+ spec.email = 'jjbohn@gmail.com'
11
+ spec.summary = 'OpenID Connect Strategy for OmniAuth'
12
+ spec.description = 'OpenID Connect Strategy for OmniAuth'
13
+ spec.homepage = 'https://github.com/jjbohn/omniauth-openid-connect'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r(^bin/)) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r(^(test|spec|features)/))
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'omniauth', '~> 1.3'
22
+ spec.add_dependency 'openid_connect', '~> 0.12.0'
23
+ spec.add_dependency 'addressable', '~> 2.5'
24
+ spec.add_development_dependency 'bundler', '~> 1.5'
25
+ spec.add_development_dependency 'minitest', '~> 5.1'
26
+ spec.add_development_dependency 'mocha', '~> 1.2'
27
+ spec.add_development_dependency 'guard', '~> 2.14'
28
+ spec.add_development_dependency 'guard-minitest', '~> 2.4'
29
+ spec.add_development_dependency 'guard-bundler', '~> 2.1'
30
+ spec.add_development_dependency 'rake', '~> 11.3'
31
+ spec.add_development_dependency 'simplecov', '~> 0.12'
32
+ spec.add_development_dependency 'pry', '~> 0.9'
33
+ spec.add_development_dependency 'coveralls', '~> 0.8'
34
+ spec.add_development_dependency 'faker', '~> 1.6'
35
+ end
@@ -0,0 +1 @@
1
+ eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzcyI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZfV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5NzAKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6qJp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJNqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7TpdQyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoSK5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg
@@ -0,0 +1,8 @@
1
+ {"keys": [{
2
+ "kty": "RSA",
3
+ "n": "0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMstn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbISD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw",
4
+ "e": "AQAB",
5
+ "alg": "RS256",
6
+ "kid": "1e9gdk7"
7
+ }]
8
+ }
@@ -0,0 +1,19 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIDJDCCAgwCCQC57Ob2JfXb+DANBgkqhkiG9w0BAQUFADBUMQswCQYDVQQGEwJK
3
+ UDEOMAwGA1UECBMFVG9reW8xITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5
4
+ IEx0ZDESMBAGA1UEAxMJbG9jYWxob3N0MB4XDTE0MDgwMTA4NTAxM1oXDTE1MDgw
5
+ MTA4NTAxM1owVDELMAkGA1UEBhMCSlAxDjAMBgNVBAgTBVRva3lvMSEwHwYDVQQK
6
+ ExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMTCWxvY2FsaG9zdDCC
7
+ ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAN+7czSGHN2087T+oX2kBCY/
8
+ XN6UOS/mdU2Gn//omZlyxsQXIqvgBLNWeCVt4QdlFUbgPLggfXUelECV/RUOCIIi
9
+ F2Th4t3x1LviN2XkUiva0DZBnOycqEaJdkyreEuGL1CLVZgZjKmSzNqLl0Yci3D0
10
+ zgVsXFZSadQebietm4CCmfJYREt9NJxXcrLxVDgat/Xm/KJBsohs3f+cbBT8EXer
11
+ 7+2oZjZoVUgw1hu0alaOvAfE4mxsVwjn3g2mjDqRJLbbuWqgDobjMHah+d4zwJvN
12
+ ePK8E0hfaz/XBLsJ4e6bQA3M3bANEgSvsicup/qb/0th4gUdc/kj4aJGj0RP7oEC
13
+ AwEAATANBgkqhkiG9w0BAQUFAAOCAQEADuVec/8u2qJiq6K2W/gSLGYCBZq64OrA
14
+ s7L2+S82m9/3gAb62wGcDNZjIGFDQubXmO6RhHv7JUT5YZqv9/kRGTJcHDUrwwoN
15
+ IE99CIPizp7VfnrZ6GsYeszSsw3m+mKTETm+6ELmaSDbYAsrCg4IpGwUF0L88ATv
16
+ CJ8QzW4X7b9dYVc7UAYyCie2N65GXfesBbRlSwFLuVqIzZfMdNpNijTIUwUqGSME
17
+ b8IjLYzvekP53CO4wEBRrAVIPNXgftorxIE30OLWua2Qw3y6Pn+Qp5fLe47025S7
18
+ Lcec18/FbHG0Vbq0qO9cKQw80XyK31N6z556wr2GN2WyixkzVRddXA==
19
+ -----END CERTIFICATE-----
@@ -0,0 +1,352 @@
1
+ require 'test_helper'
2
+
3
+ module OmniAuth
4
+ module Strategies
5
+ class OpenIDConnectTest < StrategyTestCase
6
+ def test_client_options_defaults
7
+ assert_equal 'https', strategy.options.client_options.scheme
8
+ assert_equal 443, strategy.options.client_options.port
9
+ assert_equal '/authorize', strategy.options.client_options.authorization_endpoint
10
+ assert_equal '/token', strategy.options.client_options.token_endpoint
11
+ end
12
+
13
+ def test_request_phase
14
+ expected_redirect = /^https:\/\/example\.com\/authorize\?client_id=1234&nonce=\w{32}&response_type=code&scope=openid&state=\w{32}$/
15
+ strategy.options.issuer = 'example.com'
16
+ strategy.options.client_options.host = 'example.com'
17
+ strategy.expects(:redirect).with(regexp_matches(expected_redirect))
18
+ strategy.request_phase
19
+ end
20
+
21
+ def test_request_phase_with_discovery
22
+ expected_redirect = /^https:\/\/example\.com\/authorization\?client_id=1234&nonce=\w{32}&response_type=code&scope=openid&state=\w{32}$/
23
+ strategy.options.client_options.host = 'example.com'
24
+ strategy.options.discovery = true
25
+
26
+ issuer = stub('OpenIDConnect::Discovery::Issuer')
27
+ issuer.stubs(:issuer).returns('https://example.com/')
28
+ ::OpenIDConnect::Discovery::Provider.stubs(:discover!).returns(issuer)
29
+
30
+ config = stub('OpenIDConnect::Discovery::Provder::Config')
31
+ config.stubs(:authorization_endpoint).returns('https://example.com/authorization')
32
+ config.stubs(:token_endpoint).returns('https://example.com/token')
33
+ config.stubs(:userinfo_endpoint).returns('https://example.com/userinfo')
34
+ config.stubs(:jwks_uri).returns('https://example.com/jwks')
35
+ ::OpenIDConnect::Discovery::Provider::Config.stubs(:discover!).with('https://example.com/').returns(config)
36
+
37
+ strategy.expects(:redirect).with(regexp_matches(expected_redirect))
38
+ strategy.request_phase
39
+
40
+ assert_equal strategy.options.issuer, 'https://example.com/'
41
+ assert_equal strategy.options.client_options.authorization_endpoint, 'https://example.com/authorization'
42
+ assert_equal strategy.options.client_options.token_endpoint, 'https://example.com/token'
43
+ assert_equal strategy.options.client_options.userinfo_endpoint, 'https://example.com/userinfo'
44
+ assert_equal strategy.options.client_options.jwks_uri, 'https://example.com/jwks'
45
+ end
46
+
47
+ def test_uid
48
+ assert_equal user_info.sub, strategy.uid
49
+ end
50
+
51
+ def test_callback_phase(session = {}, params = {})
52
+ code = SecureRandom.hex(16)
53
+ state = SecureRandom.hex(16)
54
+ nonce = SecureRandom.hex(16)
55
+ request.stubs(:params).returns('code' => code, 'state' => state)
56
+ request.stubs(:path_info).returns('')
57
+
58
+ strategy.options.issuer = 'example.com'
59
+ strategy.options.client_signing_alg = :RS256
60
+ strategy.options.client_jwk_signing_key = File.read('test/fixtures/jwks.json')
61
+
62
+ id_token = stub('OpenIDConnect::ResponseObject::IdToken')
63
+ id_token.stubs(:verify!).with(issuer: strategy.options.issuer, client_id: @identifier, nonce: nonce).returns(true)
64
+ ::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
65
+
66
+ strategy.unstub(:user_info)
67
+ access_token = stub('OpenIDConnect::AccessToken')
68
+ access_token.stubs(:access_token)
69
+ access_token.stubs(:refresh_token)
70
+ access_token.stubs(:expires_in)
71
+ access_token.stubs(:scope)
72
+ access_token.stubs(:id_token).returns(File.read('test/fixtures/id_token.txt'))
73
+ client.expects(:access_token!).at_least_once.returns(access_token)
74
+ access_token.expects(:userinfo!).returns(user_info)
75
+
76
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
77
+ strategy.callback_phase
78
+ end
79
+
80
+ def test_callback_phase_with_discovery
81
+ code = SecureRandom.hex(16)
82
+ state = SecureRandom.hex(16)
83
+ nonce = SecureRandom.hex(16)
84
+ jwks = JSON::JWK::Set.new(JSON.parse(File.read('test/fixtures/jwks.json'))['keys'])
85
+
86
+ request.stubs(:params).returns('code' => code, 'state' => state)
87
+ request.stubs(:path_info).returns('')
88
+
89
+ strategy.options.client_options.host = 'example.com'
90
+ strategy.options.discovery = true
91
+
92
+ issuer = stub('OpenIDConnect::Discovery::Issuer')
93
+ issuer.stubs(:issuer).returns('https://example.com/')
94
+ ::OpenIDConnect::Discovery::Provider.stubs(:discover!).returns(issuer)
95
+
96
+ config = stub('OpenIDConnect::Discovery::Provder::Config')
97
+ config.stubs(:authorization_endpoint).returns('https://example.com/authorization')
98
+ config.stubs(:token_endpoint).returns('https://example.com/token')
99
+ config.stubs(:userinfo_endpoint).returns('https://example.com/userinfo')
100
+ config.stubs(:jwks_uri).returns('https://example.com/jwks')
101
+ config.stubs(:jwks).returns(jwks)
102
+
103
+ ::OpenIDConnect::Discovery::Provider::Config.stubs(:discover!).with('https://example.com/').returns(config)
104
+
105
+ id_token = stub('OpenIDConnect::ResponseObject::IdToken')
106
+ id_token.stubs(:verify!).with(issuer: 'https://example.com/', client_id: @identifier, nonce: nonce).returns(true)
107
+ ::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
108
+
109
+ strategy.unstub(:user_info)
110
+ access_token = stub('OpenIDConnect::AccessToken')
111
+ access_token.stubs(:access_token)
112
+ access_token.stubs(:refresh_token)
113
+ access_token.stubs(:expires_in)
114
+ access_token.stubs(:scope)
115
+ access_token.stubs(:id_token).returns(File.read('test/fixtures/id_token.txt'))
116
+ client.expects(:access_token!).at_least_once.returns(access_token)
117
+ access_token.expects(:userinfo!).returns(user_info)
118
+
119
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
120
+ strategy.callback_phase
121
+ end
122
+
123
+ def test_callback_phase_with_error
124
+ state = SecureRandom.hex(16)
125
+ nonce = SecureRandom.hex(16)
126
+ request.stubs(:params).returns('error' => 'invalid_request')
127
+ request.stubs(:path_info).returns('')
128
+
129
+ strategy.call!({'rack.session' => {'omniauth.state' => state, 'omniauth.nonce' => nonce}})
130
+ strategy.expects(:fail!)
131
+ strategy.callback_phase
132
+ end
133
+
134
+ def test_callback_phase_with_invalid_state
135
+ code = SecureRandom.hex(16)
136
+ state = SecureRandom.hex(16)
137
+ nonce = SecureRandom.hex(16)
138
+ request.stubs(:params).returns('code' => code, 'state' => 'foobar')
139
+ request.stubs(:path_info).returns('')
140
+
141
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
142
+ result = strategy.callback_phase
143
+
144
+ assert result.kind_of?(Array)
145
+ assert result.first == 401, "Expecting unauthorized"
146
+ end
147
+
148
+ def test_callback_phase_with_timeout
149
+ code = SecureRandom.hex(16)
150
+ state = SecureRandom.hex(16)
151
+ nonce = SecureRandom.hex(16)
152
+ request.stubs(:params).returns('code' => code, 'state' => state)
153
+ request.stubs(:path_info).returns('')
154
+
155
+ strategy.options.issuer = 'example.com'
156
+
157
+ strategy.stubs(:access_token).raises(::Timeout::Error.new('error'))
158
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
159
+ strategy.expects(:fail!)
160
+ strategy.callback_phase
161
+ end
162
+
163
+ def test_callback_phase_with_etimeout
164
+ code = SecureRandom.hex(16)
165
+ state = SecureRandom.hex(16)
166
+ nonce = SecureRandom.hex(16)
167
+ request.stubs(:params).returns('code' => code, 'state' => state)
168
+ request.stubs(:path_info).returns('')
169
+
170
+ strategy.options.issuer = 'example.com'
171
+
172
+ strategy.stubs(:access_token).raises(::Errno::ETIMEDOUT.new('error'))
173
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
174
+ strategy.expects(:fail!)
175
+ strategy.callback_phase
176
+ end
177
+
178
+ def test_callback_phase_with_socket_error
179
+ code = SecureRandom.hex(16)
180
+ state = SecureRandom.hex(16)
181
+ nonce = SecureRandom.hex(16)
182
+ request.stubs(:params).returns('code' => code, 'state' => state)
183
+ request.stubs(:path_info).returns('')
184
+
185
+ strategy.options.issuer = 'example.com'
186
+
187
+ strategy.stubs(:access_token).raises(::SocketError.new('error'))
188
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
189
+ strategy.expects(:fail!)
190
+ strategy.callback_phase
191
+ end
192
+
193
+ def test_info
194
+ info = strategy.info
195
+ assert_equal user_info.name, info[:name]
196
+ assert_equal user_info.email, info[:email]
197
+ assert_equal user_info.preferred_username, info[:nickname]
198
+ assert_equal user_info.given_name, info[:first_name]
199
+ assert_equal user_info.family_name, info[:last_name]
200
+ assert_equal user_info.gender, info[:gender]
201
+ assert_equal user_info.picture, info[:image]
202
+ assert_equal user_info.phone_number, info[:phone]
203
+ assert_equal({ website: user_info.website }, info[:urls])
204
+ end
205
+
206
+ def test_extra
207
+ assert_equal({ raw_info: user_info.as_json }, strategy.extra)
208
+ end
209
+
210
+ def test_credentials
211
+ strategy.options.issuer = 'example.com'
212
+ strategy.options.client_signing_alg = :RS256
213
+ strategy.options.client_jwk_signing_key = File.read('test/fixtures/jwks.json')
214
+
215
+ id_token = stub('OpenIDConnect::ResponseObject::IdToken')
216
+ id_token.stubs(:verify!).returns(true)
217
+ ::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
218
+
219
+ access_token = stub('OpenIDConnect::AccessToken')
220
+ access_token.stubs(:access_token).returns(SecureRandom.hex(16))
221
+ access_token.stubs(:refresh_token).returns(SecureRandom.hex(16))
222
+ access_token.stubs(:expires_in).returns(Time.now)
223
+ access_token.stubs(:scope).returns('openidconnect')
224
+ access_token.stubs(:id_token).returns(File.read('test/fixtures/id_token.txt'))
225
+
226
+ client.expects(:access_token!).returns(access_token)
227
+ access_token.expects(:refresh_token).returns(access_token.refresh_token)
228
+ access_token.expects(:expires_in).returns(access_token.expires_in)
229
+
230
+ assert_equal(
231
+ {
232
+ id_token: access_token.id_token,
233
+ token: access_token.access_token,
234
+ refresh_token: access_token.refresh_token,
235
+ expires_in: access_token.expires_in,
236
+ scope: access_token.scope
237
+ },
238
+ strategy.credentials
239
+ )
240
+ end
241
+
242
+ def test_option_send_nonce
243
+ strategy.options.client_options[:host] = 'foobar.com'
244
+
245
+ assert(strategy.authorize_uri =~ /nonce=/, 'URI must contain nonce')
246
+
247
+ strategy.options.send_nonce = false
248
+ assert(!(strategy.authorize_uri =~ /nonce=/), 'URI must not contain nonce')
249
+ end
250
+
251
+ def test_failure_endpoint_redirect
252
+ OmniAuth.config.stubs(:failure_raise_out_environments).returns([])
253
+ strategy.stubs(:env).returns({})
254
+ request.stubs(:params).returns('error' => 'access denied')
255
+
256
+ result = strategy.callback_phase
257
+
258
+ assert(result.is_a? Array)
259
+ assert(result[0] == 302, 'Redirect')
260
+ assert(result[1]["Location"] =~ /\/auth\/failure/)
261
+ end
262
+
263
+ def test_state
264
+ strategy.options.state = lambda { 42 }
265
+ session = { "state" => 42 }
266
+
267
+ expected_redirect = /&state=/
268
+ strategy.options.issuer = 'example.com'
269
+ strategy.options.client_options.host = 'example.com'
270
+ strategy.expects(:redirect).with(regexp_matches(expected_redirect))
271
+ strategy.request_phase
272
+
273
+ # this should succeed as the correct state is passed with the request
274
+ test_callback_phase(session, { 'state' => 42 })
275
+
276
+ # the following should fail because the wrong state is passed to the callback
277
+ code = SecureRandom.hex(16)
278
+ request.stubs(:params).returns('code' => code, 'state' => 43)
279
+ request.stubs(:path_info).returns('')
280
+ strategy.call!('rack.session' => session)
281
+
282
+ result = strategy.callback_phase
283
+
284
+ assert result.kind_of?(Array)
285
+ assert result.first == 401, 'Expecting unauthorized'
286
+ end
287
+
288
+ def test_option_client_auth_method
289
+ state = SecureRandom.hex(16)
290
+ nonce = SecureRandom.hex(16)
291
+
292
+ opts = strategy.options.client_options
293
+ opts[:host] = 'foobar.com'
294
+ strategy.options.issuer = 'foobar.com'
295
+ strategy.options.client_auth_method = :not_basic
296
+ strategy.options.client_signing_alg = :RS256
297
+ strategy.options.client_jwk_signing_key = File.read('test/fixtures/jwks.json')
298
+
299
+ json_response = {
300
+ access_token: 'test_access_token',
301
+ id_token: File.read('test/fixtures/id_token.txt'),
302
+ token_type: 'Bearer',
303
+ }.to_json
304
+ success = Struct.new(:status, :body).new(200, json_response)
305
+
306
+ request.stubs(:path_info).returns('')
307
+ strategy.call!('rack.session' => { 'omniauth.state' => state, 'omniauth.nonce' => nonce })
308
+
309
+ id_token = stub('OpenIDConnect::ResponseObject::IdToken')
310
+ id_token.stubs(:verify!).with(issuer: strategy.options.issuer, client_id: @identifier, nonce: nonce).returns(true)
311
+ ::OpenIDConnect::ResponseObject::IdToken.stubs(:decode).returns(id_token)
312
+
313
+ HTTPClient.any_instance.stubs(:post).with(
314
+ "#{ opts.scheme }://#{ opts.host }:#{ opts.port }#{ opts.token_endpoint }",
315
+ { scope: 'openid', grant_type: :client_credentials, client_id: @identifier, client_secret: @secret },
316
+ {}
317
+ ).returns(success)
318
+
319
+ assert(strategy.send :access_token)
320
+ end
321
+
322
+ def test_public_key_with_jwks
323
+ strategy.options.client_signing_alg = :RS256
324
+ strategy.options.client_jwk_signing_key = File.read('./test/fixtures/jwks.json')
325
+
326
+ assert_equal JSON::JWK::Set, strategy.public_key.class
327
+ end
328
+
329
+ def test_public_key_with_jwk
330
+ strategy.options.client_signing_alg = :RS256
331
+ jwks_str = File.read('./test/fixtures/jwks.json')
332
+ jwks = JSON.parse(jwks_str)
333
+ jwk = jwks['keys'].first
334
+ strategy.options.client_jwk_signing_key = jwk.to_json
335
+
336
+ assert_equal JSON::JWK, strategy.public_key.class
337
+ end
338
+
339
+ def test_public_key_with_x509
340
+ strategy.options.client_signing_alg = :RS256
341
+ strategy.options.client_x509_signing_key = File.read('./test/fixtures/test.crt')
342
+ assert_equal OpenSSL::PKey::RSA, strategy.public_key.class
343
+ end
344
+
345
+ def test_public_key_with_hmac
346
+ strategy.options.client_options.secret = 'secret'
347
+ strategy.options.client_signing_alg = :HS256
348
+ assert_equal strategy.options.client_options.secret, strategy.public_key
349
+ end
350
+ end
351
+ end
352
+ end
@@ -0,0 +1,51 @@
1
+ class StrategyTestCase < MiniTest::Test
2
+ class DummyApp
3
+ def call(env); end
4
+ end
5
+
6
+ attr_accessor :identifier, :secret
7
+
8
+ def setup
9
+ @identifier = '1234'
10
+ @secret = '1234asdgat3'
11
+ end
12
+
13
+ def client
14
+ strategy.client
15
+ end
16
+
17
+ def user_info
18
+ @user_info ||= OpenIDConnect::ResponseObject::UserInfo.new(
19
+ sub: SecureRandom.hex(16),
20
+ name: Faker::Name.name,
21
+ email: Faker::Internet.email,
22
+ nickname: Faker::Name.first_name,
23
+ preferred_username: Faker::Internet.user_name,
24
+ given_name: Faker::Name.first_name,
25
+ family_name: Faker::Name.last_name,
26
+ gender: 'female',
27
+ picture: Faker::Internet.url + '.png',
28
+ phone_number: Faker::PhoneNumber.phone_number,
29
+ website: Faker::Internet.url,
30
+ )
31
+ end
32
+
33
+ def request
34
+ @request ||= stub('Request').tap do |request|
35
+ request.stubs(:params).returns({})
36
+ request.stubs(:cookies).returns({})
37
+ request.stubs(:env).returns({})
38
+ request.stubs(:scheme).returns({})
39
+ request.stubs(:ssl?).returns(false)
40
+ end
41
+ end
42
+
43
+ def strategy
44
+ @strategy ||= OmniAuth::Strategies::OpenIDConnect.new(DummyApp.new).tap do |strategy|
45
+ strategy.options.client_options.identifier = @identifier
46
+ strategy.options.client_options.secret = @secret
47
+ strategy.stubs(:request).returns(request)
48
+ strategy.stubs(:user_info).returns(user_info)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,13 @@
1
+ require 'simplecov'
2
+ require 'coveralls'
3
+ require 'minitest/autorun'
4
+ require 'mocha/mini_test'
5
+ require 'faker'
6
+ require 'active_support'
7
+ require 'omniauth_openid_connect'
8
+ require_relative 'strategy_test_case'
9
+
10
+ SimpleCov.command_name 'test'
11
+ SimpleCov.start
12
+ Coveralls.wear!
13
+ OmniAuth.config.test_mode = true
metadata ADDED
@@ -0,0 +1,264 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omniauth_openid_connect
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - John Bohn
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-12-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: omniauth
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.3'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.3'
27
+ - !ruby/object:Gem::Dependency
28
+ name: openid_connect
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.12.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.12.0
41
+ - !ruby/object:Gem::Dependency
42
+ name: addressable
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.5'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.5'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.5'
69
+ - !ruby/object:Gem::Dependency
70
+ name: minitest
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '5.1'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '5.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: mocha
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '1.2'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '1.2'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '2.14'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '2.14'
111
+ - !ruby/object:Gem::Dependency
112
+ name: guard-minitest
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '2.4'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '2.4'
125
+ - !ruby/object:Gem::Dependency
126
+ name: guard-bundler
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '2.1'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '2.1'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rake
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '11.3'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '11.3'
153
+ - !ruby/object:Gem::Dependency
154
+ name: simplecov
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '0.12'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '0.12'
167
+ - !ruby/object:Gem::Dependency
168
+ name: pry
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '0.9'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '0.9'
181
+ - !ruby/object:Gem::Dependency
182
+ name: coveralls
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '0.8'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '0.8'
195
+ - !ruby/object:Gem::Dependency
196
+ name: faker
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - "~>"
200
+ - !ruby/object:Gem::Version
201
+ version: '1.6'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - "~>"
207
+ - !ruby/object:Gem::Version
208
+ version: '1.6'
209
+ description: OpenID Connect Strategy for OmniAuth
210
+ email: jjbohn@gmail.com
211
+ executables: []
212
+ extensions: []
213
+ extra_rdoc_files: []
214
+ files:
215
+ - ".gitignore"
216
+ - ".travis.yml"
217
+ - Gemfile
218
+ - Guardfile
219
+ - LICENSE.txt
220
+ - README.md
221
+ - Rakefile
222
+ - lib/omniauth/openid_connect.rb
223
+ - lib/omniauth/openid_connect/errors.rb
224
+ - lib/omniauth/openid_connect/version.rb
225
+ - lib/omniauth/strategies/openid_connect.rb
226
+ - lib/omniauth_openid_connect.rb
227
+ - omniauth_openid_connect.gemspec
228
+ - test/fixtures/id_token.txt
229
+ - test/fixtures/jwks.json
230
+ - test/fixtures/test.crt
231
+ - test/lib/omniauth/strategies/openid_connect_test.rb
232
+ - test/strategy_test_case.rb
233
+ - test/test_helper.rb
234
+ homepage: https://github.com/jjbohn/omniauth-openid-connect
235
+ licenses:
236
+ - MIT
237
+ metadata: {}
238
+ post_install_message:
239
+ rdoc_options: []
240
+ require_paths:
241
+ - lib
242
+ required_ruby_version: !ruby/object:Gem::Requirement
243
+ requirements:
244
+ - - ">="
245
+ - !ruby/object:Gem::Version
246
+ version: '0'
247
+ required_rubygems_version: !ruby/object:Gem::Requirement
248
+ requirements:
249
+ - - ">="
250
+ - !ruby/object:Gem::Version
251
+ version: '0'
252
+ requirements: []
253
+ rubyforge_project:
254
+ rubygems_version: 2.5.1
255
+ signing_key:
256
+ specification_version: 4
257
+ summary: OpenID Connect Strategy for OmniAuth
258
+ test_files:
259
+ - test/fixtures/id_token.txt
260
+ - test/fixtures/jwks.json
261
+ - test/fixtures/test.crt
262
+ - test/lib/omniauth/strategies/openid_connect_test.rb
263
+ - test/strategy_test_case.rb
264
+ - test/test_helper.rb