omniauth_openid_connect 0.1

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 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