omniauth-pixelpin 1.1.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: f4ac8e3dfdcf06437d1cc683672babbc3b591bbf
4
+ data.tar.gz: a430367cf8071233ff603b81ba35f0f48fd29a98
5
+ SHA512:
6
+ metadata.gz: 74cbbf4ad91e2d8db6bfd8f60230db03df5b975ce3ebf532b523a8635b599d161f614c14ef4df23ba58e62e4baedb4daec1a8a7764c0abc59c82664d70eb0082
7
+ data.tar.gz: 856a1c350414f00011688e0be0b4e08890a90b2a7f53a7a290400de6052dda4e1b672be36f469b31b3d1c2a8b5759d0f716d84d4766204c20a9226d2e35ef199
@@ -0,0 +1 @@
1
+ require "omniauth/pixelpin"
@@ -0,0 +1,3 @@
1
+ require "omniauth/pixelpin/errors"
2
+ require "omniauth/pixelpin/version"
3
+ require "omniauth/strategies/pixelpin"
@@ -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 = "1.1.1"
4
+ end
5
+ end
@@ -0,0 +1,284 @@
1
+ require 'addressable/uri'
2
+ require 'timeout'
3
+ require 'net/http'
4
+ require 'open-uri'
5
+ require 'omniauth'
6
+ require 'openid_connect'
7
+ require 'json'
8
+
9
+ module OmniAuth
10
+ module Strategies
11
+ class OpenIDConnect
12
+ include OmniAuth::Strategy
13
+
14
+ option :client_options, {
15
+ identifier: nil,
16
+ secret: nil,
17
+ redirect_uri: nil,
18
+ scheme: "https",
19
+ host: "login.pixelpin.io",
20
+ port: 443,
21
+ authorization_endpoint: "https://login.pixelpin.io/connect/authorize",
22
+ token_endpoint: "https://login.pixelpin.io/connect/token",
23
+ userinfo_endpoint: "https://login.pixelpin.io/connect/userinfo",
24
+ jwks_uri: 'https://login.pixelpin.io/.well-known/jwks'
25
+ }
26
+ option :issuer, "https://login.pixelpin.io/"
27
+ option :discovery, true
28
+ option :client_signing_alg
29
+ option :client_jwk_signing_key
30
+ option :client_x509_signing_key
31
+ option :scope, [:openid]
32
+ option :response_type, "code"
33
+ option :state
34
+ option :response_mode
35
+ option :display, nil #, [:page, :popup, :touch, :wap]
36
+ option :prompt, nil #, [:none, :login, :consent, :select_account]
37
+ option :hd, nil
38
+ option :max_age
39
+ option :ui_locales
40
+ option :id_token_hint
41
+ option :login_hint
42
+ option :acr_values
43
+ option :send_nonce, true
44
+ option :send_scope_to_token_endpoint, true
45
+ option :client_auth_method
46
+
47
+ uid { user_info.sub }
48
+
49
+ def formatted_address
50
+ formatted_address = HashWithIndifferentAccess.new(user_info.raw_attributes)
51
+ end
52
+
53
+ def address
54
+ if formatted_address["address"].nil?
55
+ address = JSON.parse('{
56
+ "street_address": "",
57
+ "country": "",
58
+ "region": "",
59
+ "locality": "",
60
+ "postal_code": ""
61
+ }')
62
+ else
63
+ address = ActiveSupport::JSON.decode(formatted_address["address"])
64
+ end
65
+ end
66
+
67
+ info do
68
+ {
69
+ name: user_info.name,
70
+ email: user_info.email,
71
+ nickname: user_info.preferred_username,
72
+ first_name: user_info.given_name,
73
+ last_name: user_info.family_name,
74
+ gender: user_info.gender,
75
+ phone: user_info.phone_number,
76
+ birthdate: user_info.birthdate,
77
+ street_address: address["street_address"],
78
+ country: address["country"],
79
+ region: address["region"],
80
+ city: address["locality"],
81
+ zip: address["postal_code"],
82
+ urls: { website: user_info.website }
83
+ }
84
+ end
85
+
86
+ def user_info
87
+ address = JSON.parse(user_info.address)
88
+
89
+ end
90
+
91
+ extra do
92
+ {raw_info: user_info.raw_attributes}
93
+ end
94
+
95
+ credentials do
96
+ {
97
+ id_token: access_token.id_token,
98
+ token: access_token.access_token,
99
+ refresh_token: access_token.refresh_token,
100
+ expires_in: access_token.expires_in,
101
+ scope: access_token.scope
102
+ }
103
+ end
104
+
105
+ def client
106
+ @client ||= ::OpenIDConnect::Client.new(client_options)
107
+ end
108
+
109
+ def config
110
+ cache_options = {
111
+ host:client_options.host,
112
+ port:client_options.port
113
+ }
114
+ @config ||= ::OpenIDConnect::Discovery::Provider::Config.discover!(options.issuer, cache_options = [client_options.host, client_options.port])
115
+ end
116
+
117
+ def request_phase
118
+ options.issuer = issuer if options.issuer.blank?
119
+ discover! if options.discovery
120
+ redirect authorize_uri
121
+ end
122
+
123
+ def callback_phase
124
+ error = request.params['error_reason'] || request.params['error']
125
+ if error
126
+ raise CallbackError.new(request.params['error'], request.params['error_description'] || request.params['error_reason'], request.params['error_uri'])
127
+ elsif request.params['state'].to_s.empty? || request.params['state'] != stored_state
128
+ return Rack::Response.new(['401 Unauthorized'], 401).finish
129
+ elsif !request.params["code"]
130
+ return fail!(:missing_code, OmniAuth::OpenIDConnect::MissingCodeError.new(request.params["error"]))
131
+ else
132
+ options.issuer = issuer if options.issuer.blank?
133
+ discover! if options.discovery
134
+ client.redirect_uri = client_options.redirect_uri
135
+ client.authorization_code = authorization_code
136
+ access_token
137
+ super
138
+ end
139
+ rescue CallbackError => e
140
+ fail!(:invalid_credentials, e)
141
+ rescue ::Timeout::Error, ::Errno::ETIMEDOUT => e
142
+ fail!(:timeout, e)
143
+ rescue ::SocketError => e
144
+ fail!(:failed_to_connect, e)
145
+ end
146
+
147
+
148
+ def authorization_code
149
+ request.params["code"]
150
+ end
151
+
152
+ def authorize_uri
153
+ client.redirect_uri = client_options.redirect_uri
154
+ opts = {
155
+ response_type: options.response_type,
156
+ scope: options.scope,
157
+ state: new_state,
158
+ nonce: (new_nonce if options.send_nonce),
159
+ hd: options.hd,
160
+ }
161
+ client.authorization_uri(opts.reject{|k,v| v.nil?})
162
+ end
163
+
164
+ def public_key
165
+ if options.discovery
166
+ config.jwks
167
+ else
168
+ key_or_secret
169
+ end
170
+ end
171
+
172
+ private
173
+
174
+ def issuer
175
+ resource = "#{client_options.scheme}://#{client_options.host}" + ((client_options.port) ? ":#{client_options.port.to_s}" : '')
176
+ ::OpenIDConnect::Discovery::Provider.discover!(resource).issuer
177
+ end
178
+
179
+ def discover!
180
+ client_options.authorization_endpoint = config.authorization_endpoint
181
+ client_options.token_endpoint = config.token_endpoint
182
+ client_options.userinfo_endpoint = config.userinfo_endpoint
183
+ client_options.jwks_uri = config.jwks_uri
184
+ end
185
+
186
+ def user_info
187
+ @user_info ||= access_token.userinfo!
188
+ end
189
+
190
+ def access_token
191
+ @access_token ||= lambda {
192
+ _access_token = client.access_token!(
193
+ scope: (options.scope if options.send_scope_to_token_endpoint),
194
+ client_auth_method: options.client_auth_method
195
+ )
196
+ _id_token = decode_id_token _access_token.id_token
197
+ _id_token.verify!(
198
+ issuer: options.issuer,
199
+ client_id: client_options.identifier,
200
+ nonce: stored_nonce
201
+ )
202
+ _access_token
203
+ }.call()
204
+ end
205
+
206
+ def decode_id_token(id_token)
207
+ ::OpenIDConnect::ResponseObject::IdToken.decode(id_token, public_key)
208
+ end
209
+
210
+
211
+ def client_options
212
+ options.client_options
213
+ end
214
+
215
+ def new_state
216
+ state = options.state.call if options.state.respond_to? :call
217
+ session['omniauth.state'] = state || SecureRandom.hex(16)
218
+ end
219
+
220
+ def stored_state
221
+ session.delete('omniauth.state')
222
+ end
223
+
224
+ def new_nonce
225
+ session['omniauth.nonce'] = SecureRandom.hex(16)
226
+ end
227
+
228
+ def stored_nonce
229
+ session.delete('omniauth.nonce')
230
+ end
231
+
232
+ def session
233
+ @env.nil? ? {} : super
234
+ end
235
+
236
+ def key_or_secret
237
+ case options.client_signing_alg
238
+ when :HS256, :HS384, :HS512
239
+ return client_options.secret
240
+ when :RS256, :RS384, :RS512
241
+ if options.client_jwk_signing_key
242
+ return parse_jwk_key(options.client_jwk_signing_key)
243
+ elsif options.client_x509_signing_key
244
+ return parse_x509_key(options.client_x509_signing_key)
245
+ end
246
+ else
247
+ end
248
+ end
249
+
250
+ def parse_x509_key(key)
251
+ OpenSSL::X509::Certificate.new(key).public_key
252
+ end
253
+
254
+ def parse_jwk_key(key)
255
+ json = JSON.parse(key)
256
+ if json.has_key?('keys')
257
+ JSON::JWK::Set.new json['keys']
258
+ else
259
+ JSON::JWK.new json
260
+ end
261
+ end
262
+
263
+ def decode(str)
264
+ UrlSafeBase64.decode64(str).unpack('B*').first.to_i(2).to_s
265
+ end
266
+
267
+ class CallbackError < StandardError
268
+ attr_accessor :error, :error_reason, :error_uri
269
+
270
+ def initialize(error, error_reason=nil, error_uri=nil)
271
+ self.error = error
272
+ self.error_reason = error_reason
273
+ self.error_uri = error_uri
274
+ end
275
+
276
+ def message
277
+ [error, error_reason, error_uri].compact.join(' | ')
278
+ end
279
+ end
280
+ end
281
+ end
282
+ end
283
+
284
+ OmniAuth.config.add_camelization 'pixelpin', 'OpenIDConnect'
metadata ADDED
@@ -0,0 +1,251 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: omniauth-pixelpin
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.1
5
+ platform: ruby
6
+ authors:
7
+ - Callum Brankin
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-06-02 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.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.1'
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: '1.0'
34
+ - - ">="
35
+ - !ruby/object:Gem::Version
36
+ version: 1.0.3
37
+ type: :runtime
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '1.0'
44
+ - - ">="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.0.3
47
+ - !ruby/object:Gem::Dependency
48
+ name: addressable
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '2.3'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '2.3'
61
+ - !ruby/object:Gem::Dependency
62
+ name: bundler
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '1.5'
68
+ type: :development
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: '1.5'
75
+ - !ruby/object:Gem::Dependency
76
+ name: minitest
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: '0'
82
+ type: :development
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: mocha
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ type: :development
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ - !ruby/object:Gem::Dependency
104
+ name: guard
105
+ requirement: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ type: :development
111
+ prerelease: false
112
+ version_requirements: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ - !ruby/object:Gem::Dependency
118
+ name: guard-minitest
119
+ requirement: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ type: :development
125
+ prerelease: false
126
+ version_requirements: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '0'
131
+ - !ruby/object:Gem::Dependency
132
+ name: guard-bundler
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ - !ruby/object:Gem::Dependency
146
+ name: rake
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ - !ruby/object:Gem::Dependency
160
+ name: simplecov
161
+ requirement: !ruby/object:Gem::Requirement
162
+ requirements:
163
+ - - ">="
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ type: :development
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ requirements:
170
+ - - ">="
171
+ - !ruby/object:Gem::Version
172
+ version: '0'
173
+ - !ruby/object:Gem::Dependency
174
+ name: pry
175
+ requirement: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ type: :development
181
+ prerelease: false
182
+ version_requirements: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: '0'
187
+ - !ruby/object:Gem::Dependency
188
+ name: coveralls
189
+ requirement: !ruby/object:Gem::Requirement
190
+ requirements:
191
+ - - ">="
192
+ - !ruby/object:Gem::Version
193
+ version: '0'
194
+ type: :development
195
+ prerelease: false
196
+ version_requirements: !ruby/object:Gem::Requirement
197
+ requirements:
198
+ - - ">="
199
+ - !ruby/object:Gem::Version
200
+ version: '0'
201
+ - !ruby/object:Gem::Dependency
202
+ name: faker
203
+ requirement: !ruby/object:Gem::Requirement
204
+ requirements:
205
+ - - ">="
206
+ - !ruby/object:Gem::Version
207
+ version: '0'
208
+ type: :development
209
+ prerelease: false
210
+ version_requirements: !ruby/object:Gem::Requirement
211
+ requirements:
212
+ - - ">="
213
+ - !ruby/object:Gem::Version
214
+ version: '0'
215
+ description: PixelPin OpenID Connect Strategy for OmniAuth
216
+ email:
217
+ - callum@pixelpin.co.uk
218
+ executables: []
219
+ extensions: []
220
+ extra_rdoc_files: []
221
+ files:
222
+ - lib/omniauth-pixelpin.rb
223
+ - lib/omniauth/pixelpin.rb
224
+ - lib/omniauth/pixelpin/errors.rb
225
+ - lib/omniauth/pixelpin/version.rb
226
+ - lib/omniauth/strategies/pixelpin.rb
227
+ homepage: https://github.com/PixelPinPlugins/omniauth-pixelpin
228
+ licenses:
229
+ - MIT
230
+ metadata: {}
231
+ post_install_message:
232
+ rdoc_options: []
233
+ require_paths:
234
+ - lib
235
+ required_ruby_version: !ruby/object:Gem::Requirement
236
+ requirements:
237
+ - - ">="
238
+ - !ruby/object:Gem::Version
239
+ version: '0'
240
+ required_rubygems_version: !ruby/object:Gem::Requirement
241
+ requirements:
242
+ - - ">="
243
+ - !ruby/object:Gem::Version
244
+ version: '0'
245
+ requirements: []
246
+ rubyforge_project:
247
+ rubygems_version: 2.5.2
248
+ signing_key:
249
+ specification_version: 4
250
+ summary: PixelPin OpenID Connect Strategy for OmniAuth
251
+ test_files: []