omniauth-test 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,45 +1,206 @@
1
- require 'omniauth/oauth'
2
- require 'multi_json'
3
-
1
+ require 'omniauth/strategies/oauth2'
2
+ require 'base64'
3
+ require 'openssl'
4
+ require 'rack/utils'
5
+ require 'uri'
6
+
4
7
  module OmniAuth
5
- module Strategies
6
- class Test < OAuth2
7
-
8
- def initialize(app, api_key = nil, secret_key = nil, options = {}, &block)
9
- client_options = {
10
- :site => 'http://auth.cibplus.com',
11
- :authorize_url => "http://localhost:3000/auth/test/callback",
12
- :access_token_url => "http://auth.cibplus.com/oauth/token"
13
- }
14
- super(app, :test, api_key, secret_key, client_options, &block)
15
- end
16
-
17
- protected
18
-
19
- def user_data
20
- #@data ||= MultiJson.decode(@access_token.get("/auth/my_strategy/user.json"))
21
- end
22
-
23
- def request_phase
24
- options[:scope] ||= "read"
25
- super
26
- end
27
-
28
- def user_hash
29
- user_data
30
- end
31
-
32
- def auth_hash
33
- OmniAuth::Utils.deep_merge(super, {
34
- 'uid' => user_data["uid"],
35
- 'user_info' => user_data['user_info'],
36
- 'extra' => {
37
- 'admin' => user_data['extra']['admin'],
38
- 'first_name' => user_data['extra']['first_name'],
39
- 'last_name' => user_data['extra']['last_name'],
40
- }
41
- })
42
- end
8
+ module Strategies
9
+ class Test < OmniAuth::Strategies::OAuth2
10
+ class NoAuthorizationCodeError < StandardError; end
11
+ class UnknownSignatureAlgorithmError < NotImplementedError; end
12
+
13
+ DEFAULT_SCOPE = 'email'
14
+
15
+ option :client_options, {
16
+ :site => 'https://auth.cibplus.com',
17
+ :authorize_url => "https://www.facebook.com/dialog/oauth",
18
+ :token_url => '/oauth/token'
19
+ }
20
+
21
+ option :token_params, {
22
+ :parse => :query
23
+ }
24
+
25
+ option :access_token_options, {
26
+ :header_format => 'OAuth %s',
27
+ :param_name => 'access_token'
28
+ }
29
+
30
+ option :authorize_options, [:scope, :display, :auth_type]
31
+
32
+ uid { raw_info['id'] }
33
+
34
+ info do
35
+ prune!({
36
+ 'nickname' => raw_info['username'],
37
+ 'email' => raw_info['email'],
38
+ 'name' => raw_info['name'],
39
+ 'first_name' => raw_info['first_name'],
40
+ 'last_name' => raw_info['last_name'],
41
+ 'image' => image_url(uid, options),
42
+ 'description' => raw_info['bio'],
43
+ 'urls' => {
44
+ 'Facebook' => raw_info['link'],
45
+ 'Website' => raw_info['website']
46
+ },
47
+ 'location' => (raw_info['location'] || {})['name'],
48
+ 'verified' => raw_info['verified']
49
+ })
50
+ end
51
+
52
+ extra do
53
+ hash = {}
54
+ hash['raw_info'] = raw_info unless skip_info?
55
+ prune! hash
56
+ end
57
+
58
+ def raw_info
59
+ @raw_info ||= access_token.get('/me', info_options).parsed || {}
60
+ end
61
+
62
+ def info_options
63
+ params = {:appsecret_proof => appsecret_proof}
64
+ params.merge!({:fields => options[:info_fields]}) if options[:info_fields]
65
+ params.merge!({:locale => options[:locale]}) if options[:locale]
66
+
67
+ { :params => params }
68
+ end
69
+
70
+ def callback_phase
71
+ with_authorization_code! do
72
+ super
73
+ end
74
+ rescue NoAuthorizationCodeError => e
75
+ fail!(:no_authorization_code, e)
76
+ rescue UnknownSignatureAlgorithmError => e
77
+ fail!(:unknown_signature_algoruthm, e)
78
+ end
79
+
80
+ # NOTE If we're using code from the signed request then FB sets the redirect_uri to '' during the authorize
81
+ # phase and it must match during the access_token phase:
82
+ # https://github.com/facebook/facebook-php-sdk/blob/master/src/base_facebook.php#L477
83
+ def callback_url
84
+ if @authorization_code_from_signed_request_in_cookie
85
+ ''
86
+ else
87
+ options[:callback_url] || super
88
+ end
89
+ end
90
+
91
+ def access_token_options
92
+ options.access_token_options.inject({}) { |h,(k,v)| h[k.to_sym] = v; h }
93
+ end
94
+
95
+ # You can pass +display+, +scope+, or +auth_type+ params to the auth request, if you need to set them dynamically.
96
+ # You can also set these options in the OmniAuth config :authorize_params option.
97
+ #
98
+ # For example: /auth/facebook?display=popup
99
+ def authorize_params
100
+ super.tap do |params|
101
+ %w[display scope auth_type].each do |v|
102
+ if request.params[v]
103
+ params[v.to_sym] = request.params[v]
104
+ end
105
+ end
106
+
107
+ params[:scope] ||= DEFAULT_SCOPE
108
+ end
109
+ end
110
+
111
+ protected
112
+
113
+ def build_access_token
114
+ super.tap do |token|
115
+ token.options.merge!(access_token_options)
116
+ end
117
+ end
118
+
119
+ private
120
+
121
+ def signed_request_from_cookie
122
+ @signed_request_from_cookie ||= raw_signed_request_from_cookie && parse_signed_request(raw_signed_request_from_cookie)
123
+ end
124
+
125
+ def raw_signed_request_from_cookie
126
+ request.cookies["fbsr_#{client.id}"]
127
+ end
128
+
129
+ # Picks the authorization code in order, from:
130
+ #
131
+ # 1. The request 'code' param (manual callback from standard server-side flow)
132
+ # 2. A signed request from cookie (passed from the client during the client-side flow)
133
+ def with_authorization_code!
134
+ if request.params.key?('code')
135
+ yield
136
+ elsif code_from_signed_request = signed_request_from_cookie && signed_request_from_cookie['code']
137
+ request.params['code'] = code_from_signed_request
138
+ @authorization_code_from_signed_request_in_cookie = true
139
+ # NOTE The code from the signed fbsr_XXX cookie is set by the FB JS SDK will confirm that the identity of the
140
+ # user contained in the signed request matches the user loading the app.
141
+ original_provider_ignores_state = options.provider_ignores_state
142
+ options.provider_ignores_state = true
143
+ begin
144
+ yield
145
+ ensure
146
+ request.params.delete('code')
147
+ @authorization_code_from_signed_request_in_cookie = false
148
+ options.provider_ignores_state = original_provider_ignores_state
149
+ end
150
+ else
151
+ raise NoAuthorizationCodeError, 'must pass either a `code` (via URL or by an `fbsr_XXX` signed request cookie)'
152
+ end
153
+ end
154
+
155
+ def prune!(hash)
156
+ hash.delete_if do |_, value|
157
+ prune!(value) if value.is_a?(Hash)
158
+ value.nil? || (value.respond_to?(:empty?) && value.empty?)
159
+ end
160
+ end
161
+
162
+ def parse_signed_request(value)
163
+ signature, encoded_payload = value.split('.')
164
+ return if signature.nil?
165
+
166
+ decoded_hex_signature = base64_decode_url(signature)
167
+ decoded_payload = MultiJson.decode(base64_decode_url(encoded_payload))
168
+
169
+ unless decoded_payload['algorithm'] == 'HMAC-SHA256'
170
+ raise UnknownSignatureAlgorithmError, "unknown algorithm: #{decoded_payload['algorithm']}"
171
+ end
172
+
173
+ if valid_signature?(client.secret, decoded_hex_signature, encoded_payload)
174
+ decoded_payload
175
+ end
176
+ end
177
+
178
+ def valid_signature?(secret, signature, payload, algorithm = OpenSSL::Digest::SHA256.new)
179
+ OpenSSL::HMAC.digest(algorithm, secret, payload) == signature
180
+ end
181
+
182
+ def base64_decode_url(value)
183
+ value += '=' * (4 - value.size.modulo(4))
184
+ Base64.decode64(value.tr('-_', '+/'))
185
+ end
186
+
187
+ def image_url(uid, options)
188
+ uri_class = options[:secure_image_url] ? URI::HTTPS : URI::HTTP
189
+ url = uri_class.build({:host => 'graph.facebook.com', :path => "/#{uid}/picture"})
190
+
191
+ query = if options[:image_size].is_a?(String)
192
+ { :type => options[:image_size] }
193
+ elsif options[:image_size].is_a?(Hash)
194
+ options[:image_size]
195
+ end
196
+ url.query = Rack::Utils.build_query(query) if query
197
+
198
+ url.to_s
199
+ end
200
+
201
+ def appsecret_proof
202
+ @appsecret_proof ||= OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, client.secret, access_token.token)
203
+ end
204
+ end
43
205
  end
44
- end
45
- end
206
+ end
@@ -1,3 +1,3 @@
1
1
  module OmniauthTest
2
- VERSION = "0.0.8"
2
+ VERSION = "0.0.9"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-test
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors: