Codebase list ruby-omniauth-facebook / upstream/3.0.0
Imported Upstream version 3.0.0 Praveen Arimbrathodiyil 8 years ago
12 changed file(s) with 653 addition(s) and 558 deletion(s). Raw diff Collapse all Expand all
0 ## 3.0.0 (2015-10-26)
1
2 Changes:
3
4 - Remove query string from redirect_uri on callback by default (#221, @gioblu)
5 - Signed request parsing extracted to `OmniAuth::Facebook::SignedRequest` class. (#183, @simi, @Vrael)
6 - Change default value of `info_fields` to `name,email` for the [graph-api-v2.4](https://developers.facebook.com/blog/post/2015/07/08/graph-api-v2.4/). ([#209](https://github.com/mkdynamic/omniauth-facebook/pull/209))
7
08 ## 2.0.1 (2015-02-21)
19
210 Bugfixes:
22
33 ---
44
5 # OmniAuth Facebook  [![Build Status](https://secure.travis-ci.org/mkdynamic/omniauth-facebook.png?branch=master)](https://travis-ci.org/mkdynamic/omniauth-facebook)
5 # OmniAuth Facebook  [![Build Status](https://secure.travis-ci.org/mkdynamic/omniauth-facebook.svg?branch=master)](https://travis-ci.org/mkdynamic/omniauth-facebook) [![Gem Version](https://img.shields.io/gem/v/omniauth-facebook.svg)](https://rubygems.org/gems/omniauth-facebook)
6
67
78 **These notes are based on master, please see tags for README pertaining to specific releases.**
89
4344 `scope` | `email` | A comma-separated list of permissions you want to request from the user. See the Facebook docs for a full list of available permissions: https://developers.facebook.com/docs/reference/login/
4445 `display` | `page` | The display context to show the authentication page. Options are: `page`, `popup` and `touch`. Read the Facebook docs for more details: https://developers.facebook.com/docs/reference/dialogs/oauth/
4546 `image_size` | `square` | Set the size for the returned image url in the auth hash. Valid options include `square` (50x50), `small` (50 pixels wide, variable height), `normal` (100 pixels wide, variable height), or `large` (about 200 pixels wide, variable height). Additionally, you can request a picture of a specific size by setting this option to a hash with `:width` and `:height` as keys. This will return an available profile picture closest to the requested size and requested aspect ratio. If only `:width` or `:height` is specified, we will return a picture whose width or height is closest to the requested size, respectively.
46 `info_fields` | | Specify exactly which fields should be returned when getting the user's info. Value should be a comma-separated string as per https://developers.facebook.com/docs/graph-api/reference/user/ (only `/me` endpoint).
47 `info_fields` | 'name,email' | Specify exactly which fields should be returned when getting the user's info. Value should be a comma-separated string as per https://developers.facebook.com/docs/graph-api/reference/user/ (only `/me` endpoint).
4748 `locale` | | Specify locale which should be used when getting the user's info. Value should be locale string as per https://developers.facebook.com/docs/reference/api/locale/.
48 `auth_type` | | Optionally specifies the requested authentication features as a comma-separated list, as per https://developers.facebook.com/docs/facebook-login/reauthentication/. Valid values are `https` (checks for the presence of the secure cookie and asks for re-authentication if it is not present), and `reauthenticate` (asks the user to re-authenticate unconditionally). Default is `nil`.
49 `auth_type` | | Optionally specifies the requested authentication features as a comma-separated list, as per https://developers.facebook.com/docs/facebook-login/reauthentication/. Valid values are `https` (checks for the presence of the secure cookie and asks for re-authentication if it is not present), and `reauthenticate` (asks the user to re-authenticate unconditionally). Use 'rerequest' when you want to request premissions. Default is `nil`.
4950 `secure_image_url` | `false` | Set to `true` to use https for the avatar image url returned in the auth hash.
5051 `callback_url` / `callback_path` | | Specify a custom callback URL used during the server-side flow. Note this must be allowed by your app configuration on Facebook (see 'Valid OAuth redirect URIs' under the 'Advanced' settings section in the configuration for your Facebook app for more details).
5152
177178
178179
179180 [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/mkdynamic/omniauth-facebook/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
180
22
33 Rake::TestTask.new do |task|
44 task.libs << 'test'
5 task.test_files = FileList['test/*_test.rb']
56 end
67
78 task :default => :test
0 require 'openssl'
1
2 module OmniAuth
3 module Facebook
4 class SignedRequest
5 class UnknownSignatureAlgorithmError < NotImplementedError; end
6 SUPPORTED_ALGORITHM = 'HMAC-SHA256'
7
8 attr_reader :value, :secret
9
10 def self.parse(value, secret)
11 new(value, secret).payload
12 end
13
14 def initialize(value, secret)
15 @value = value
16 @secret = secret
17 end
18
19 def payload
20 @payload ||= parse_signed_request
21 end
22
23 private
24
25 def parse_signed_request
26 signature, encoded_payload = value.split('.')
27 return if signature.nil?
28
29 decoded_hex_signature = base64_decode_url(signature)
30 decoded_payload = MultiJson.decode(base64_decode_url(encoded_payload))
31
32 unless decoded_payload['algorithm'] == SUPPORTED_ALGORITHM
33 raise UnknownSignatureAlgorithmError, "unknown algorithm: #{decoded_payload['algorithm']}"
34 end
35
36 if valid_signature?(decoded_hex_signature, encoded_payload)
37 decoded_payload
38 end
39 end
40
41 def valid_signature?(signature, payload, algorithm = OpenSSL::Digest::SHA256.new)
42 OpenSSL::HMAC.digest(algorithm, secret, payload) == signature
43 end
44
45 def base64_decode_url(value)
46 value += '=' * (4 - value.size.modulo(4))
47 Base64.decode64(value.tr('-_', '+/'))
48 end
49 end
50 end
51 end
00 module OmniAuth
11 module Facebook
2 VERSION = "2.0.1"
2 VERSION = "3.0.0"
33 end
44 end
00 require 'omniauth/strategies/oauth2'
1 require 'base64'
1 require 'omniauth/facebook/signed_request'
22 require 'openssl'
33 require 'rack/utils'
44 require 'uri'
77 module Strategies
88 class Facebook < OmniAuth::Strategies::OAuth2
99 class NoAuthorizationCodeError < StandardError; end
10 class UnknownSignatureAlgorithmError < NotImplementedError; end
1110
1211 DEFAULT_SCOPE = 'email'
13 SUPPORTED_ALGORITHM = 'HMAC-SHA256'
1412
1513 option :client_options, {
1614 :site => 'https://graph.facebook.com',
6159
6260 def info_options
6361 params = {:appsecret_proof => appsecret_proof}
64 params.merge!({:fields => options[:info_fields]}) if options[:info_fields]
62 params.merge!({:fields => (options[:info_fields] || 'name,email')})
6563 params.merge!({:locale => options[:locale]}) if options[:locale]
6664
6765 { :params => params }
7371 end
7472 rescue NoAuthorizationCodeError => e
7573 fail!(:no_authorization_code, e)
76 rescue UnknownSignatureAlgorithmError => e
74 rescue OmniAuth::Facebook::SignedRequest::UnknownSignatureAlgorithmError => e
7775 fail!(:unknown_signature_algorithm, e)
7876 end
7977
8482 if @authorization_code_from_signed_request_in_cookie
8583 ''
8684 else
87 options[:callback_url] || super
85 # Fixes regression in omniauth-oauth2 v1.4.0 by https://github.com/intridea/omniauth-oauth2/commit/85fdbe117c2a4400d001a6368cc359d88f40abc7
86 options[:callback_url] || (full_host + script_name + callback_path)
8887 end
8988 end
9089
119118 private
120119
121120 def signed_request_from_cookie
122 @signed_request_from_cookie ||= raw_signed_request_from_cookie && parse_signed_request(raw_signed_request_from_cookie)
121 @signed_request_from_cookie ||= raw_signed_request_from_cookie && OmniAuth::Facebook::SignedRequest.parse(raw_signed_request_from_cookie, client.secret)
123122 end
124123
125124 def raw_signed_request_from_cookie
159158 end
160159 end
161160
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'] == SUPPORTED_ALGORITHM
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
187161 def image_url(uid, options)
188162 uri_class = options[:secure_image_url] ? URI::HTTPS : URI::HTTP
189163 site_uri = URI.parse(client.site)
00 --- !ruby/object:Gem::Specification
11 name: omniauth-facebook
22 version: !ruby/object:Gem::Version
3 version: 2.0.1
3 version: 3.0.0
44 platform: ruby
55 authors:
66 - Mark Dodwell
88 autorequire:
99 bindir: bin
1010 cert_chain: []
11 date: 2015-02-21 00:00:00.000000000 Z
11 date: 2015-10-27 00:00:00.000000000 Z
1212 dependencies:
1313 - !ruby/object:Gem::Dependency
1414 name: omniauth-oauth2
1515 requirement: !ruby/object:Gem::Requirement
1616 requirements:
17 - - "~>"
17 - - ~>
1818 - !ruby/object:Gem::Version
1919 version: '1.2'
2020 type: :runtime
2121 prerelease: false
2222 version_requirements: !ruby/object:Gem::Requirement
2323 requirements:
24 - - "~>"
24 - - ~>
2525 - !ruby/object:Gem::Version
2626 version: '1.2'
2727 - !ruby/object:Gem::Dependency
2828 name: minitest
2929 requirement: !ruby/object:Gem::Requirement
3030 requirements:
31 - - ">="
31 - - '>='
3232 - !ruby/object:Gem::Version
3333 version: '0'
3434 type: :development
3535 prerelease: false
3636 version_requirements: !ruby/object:Gem::Requirement
3737 requirements:
38 - - ">="
38 - - '>='
3939 - !ruby/object:Gem::Version
4040 version: '0'
4141 - !ruby/object:Gem::Dependency
4242 name: mocha
4343 requirement: !ruby/object:Gem::Requirement
4444 requirements:
45 - - ">="
45 - - '>='
4646 - !ruby/object:Gem::Version
4747 version: '0'
4848 type: :development
4949 prerelease: false
5050 version_requirements: !ruby/object:Gem::Requirement
5151 requirements:
52 - - ">="
52 - - '>='
5353 - !ruby/object:Gem::Version
5454 version: '0'
5555 - !ruby/object:Gem::Dependency
5656 name: rake
5757 requirement: !ruby/object:Gem::Requirement
5858 requirements:
59 - - ">="
59 - - '>='
6060 - !ruby/object:Gem::Version
6161 version: '0'
6262 type: :development
6363 prerelease: false
6464 version_requirements: !ruby/object:Gem::Requirement
6565 requirements:
66 - - ">="
66 - - '>='
6767 - !ruby/object:Gem::Version
6868 version: '0'
6969 description:
7474 extensions: []
7575 extra_rdoc_files: []
7676 files:
77 - ".gitignore"
78 - ".travis.yml"
77 - .gitignore
78 - .travis.yml
7979 - CHANGELOG.md
8080 - Gemfile
8181 - README.md
8686 - example/config.ru
8787 - lib/omniauth-facebook.rb
8888 - lib/omniauth/facebook.rb
89 - lib/omniauth/facebook/signed_request.rb
8990 - lib/omniauth/facebook/version.rb
9091 - lib/omniauth/strategies/facebook.rb
9192 - omniauth-facebook.gemspec
93 - test/fixtures/payload.json
94 - test/fixtures/signed_request.txt
9295 - test/helper.rb
96 - test/signed_request_test.rb
97 - test/strategy_test.rb
9398 - test/support/shared_examples.rb
94 - test/test.rb
9599 homepage: https://github.com/mkdynamic/omniauth-facebook
96100 licenses:
97101 - MIT
102106 - lib
103107 required_ruby_version: !ruby/object:Gem::Requirement
104108 requirements:
105 - - ">="
109 - - '>='
106110 - !ruby/object:Gem::Version
107111 version: '0'
108112 required_rubygems_version: !ruby/object:Gem::Requirement
109113 requirements:
110 - - ">="
114 - - '>='
111115 - !ruby/object:Gem::Version
112116 version: '0'
113117 requirements: []
114118 rubyforge_project:
115 rubygems_version: 2.4.5
119 rubygems_version: 2.0.14
116120 signing_key:
117121 specification_version: 4
118122 summary: Facebook OAuth2 Strategy for OmniAuth
119123 test_files:
124 - test/fixtures/payload.json
125 - test/fixtures/signed_request.txt
120126 - test/helper.rb
127 - test/signed_request_test.rb
128 - test/strategy_test.rb
121129 - test/support/shared_examples.rb
122 - test/test.rb
0 {
1 "algorithm": "HMAC-SHA256",
2 "expires": 1308988800,
3 "issued_at": 1308985018,
4 "oauth_token": "111111111111111|2.AQBAttRlLVnwqNPZ.3600.1111111111.1-111111111111111|T49w3BqoZUegypru51Gra70hED8",
5 "user":
6 {
7 "country": "de",
8 "locale": "en_US",
9 "age":
10 {
11 "min": 21
12 }
13 },
14 "user_id": "111111111111111"
15 }
0 53umfudisP7mKhsi9nZboBg15yMZKhfQAARL9UoZtSE.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImV4cGlyZXMiOjEzMDg5ODg4MDAsImlzc3VlZF9hdCI6MTMwODk4NTAxOCwib2F1dGhfdG9rZW4iOiIxMTExMTExMTExMTExMTF8Mi5BUUJBdHRSbExWbndxTlBaLjM2MDAuMTExMTExMTExMS4xLTExMTExMTExMTExMTExMXxUNDl3M0Jxb1pVZWd5cHJ1NTFHcmE3MGhFRDgiLCJ1c2VyIjp7ImNvdW50cnkiOiJkZSIsImxvY2FsZSI6ImVuX1VTIiwiYWdlIjp7Im1pbiI6MjF9fSwidXNlcl9pZCI6IjExMTExMTExMTExMTExMSJ9
0 require 'helper'
1 require 'omniauth/facebook/signed_request'
2
3 class SignedRequestTest < Minitest::Test
4 def setup
5 @value = fixture('signed_request.txt').strip
6 @secret = "897z956a2z7zzzzz5783z458zz3z7556"
7 @expected_payload = MultiJson.decode(fixture('payload.json'))
8 end
9
10 def test_signed_request_payload
11 signed_request = OmniAuth::Facebook::SignedRequest.new(@value, @secret)
12 assert_equal @expected_payload, signed_request.payload
13 end
14
15 def test_signed_request_parse
16 payload = OmniAuth::Facebook::SignedRequest.parse(@value, @secret)
17 assert_equal @expected_payload, payload
18 end
19
20 private
21
22 def fixture(name)
23 File.read(File.expand_path("fixtures/#{name}", File.dirname(__FILE__)))
24 end
25 end
0 require 'helper'
1 require 'omniauth-facebook'
2 require 'openssl'
3 require 'base64'
4
5 class StrategyTest < StrategyTestCase
6 include OAuth2StrategyTests
7 end
8
9 class ClientTest < StrategyTestCase
10 test 'has correct Facebook site' do
11 assert_equal 'https://graph.facebook.com', strategy.client.site
12 end
13
14 test 'has correct authorize url' do
15 assert_equal 'https://www.facebook.com/dialog/oauth', strategy.client.options[:authorize_url]
16 end
17
18 test 'has correct token url with versioning' do
19 @options = {:client_options => {:site => 'https://graph.facebook.net/v2.2'}}
20 assert_equal 'oauth/access_token', strategy.client.options[:token_url]
21 assert_equal 'https://graph.facebook.net/v2.2/oauth/access_token', strategy.client.token_url
22 end
23 end
24
25 class CallbackUrlTest < StrategyTestCase
26 test "returns the default callback url (omitting querystring)" do
27 url_base = 'http://auth.request.com'
28 @request.stubs(:url).returns("#{url_base}/some/page")
29 strategy.stubs(:script_name).returns('') # as not to depend on Rack env
30 strategy.stubs(:query_string).returns('?foo=bar')
31 assert_equal "#{url_base}/auth/facebook/callback", strategy.callback_url
32 end
33
34 test "returns path from callback_path option (omitting querystring)" do
35 @options = { :callback_path => "/auth/FB/done"}
36 url_base = 'http://auth.request.com'
37 @request.stubs(:url).returns("#{url_base}/page/path")
38 strategy.stubs(:script_name).returns('') # as not to depend on Rack env
39 strategy.stubs(:query_string).returns('?foo=bar')
40 assert_equal "#{url_base}/auth/FB/done", strategy.callback_url
41 end
42
43 test "returns url from callback_url option" do
44 url = 'https://auth.myapp.com/auth/fb/callback'
45 @options = { :callback_url => url }
46 assert_equal url, strategy.callback_url
47 end
48 end
49
50 class AuthorizeParamsTest < StrategyTestCase
51 test 'includes default scope for email' do
52 assert strategy.authorize_params.is_a?(Hash)
53 assert_equal 'email', strategy.authorize_params[:scope]
54 end
55
56 test 'includes display parameter from request when present' do
57 @request.stubs(:params).returns({ 'display' => 'touch' })
58 assert strategy.authorize_params.is_a?(Hash)
59 assert_equal 'touch', strategy.authorize_params[:display]
60 end
61
62 test 'includes auth_type parameter from request when present' do
63 @request.stubs(:params).returns({ 'auth_type' => 'reauthenticate' })
64 assert strategy.authorize_params.is_a?(Hash)
65 assert_equal 'reauthenticate', strategy.authorize_params[:auth_type]
66 end
67
68 test 'overrides default scope with parameter passed from request' do
69 @request.stubs(:params).returns({ 'scope' => 'email' })
70 assert strategy.authorize_params.is_a?(Hash)
71 assert_equal 'email', strategy.authorize_params[:scope]
72 end
73 end
74
75 class TokeParamsTest < StrategyTestCase
76 test 'has correct parse strategy' do
77 assert_equal :query, strategy.token_params[:parse]
78 end
79 end
80
81 class AccessTokenOptionsTest < StrategyTestCase
82 test 'has correct param name by default' do
83 assert_equal 'access_token', strategy.access_token_options[:param_name]
84 end
85
86 test 'has correct header format by default' do
87 assert_equal 'OAuth %s', strategy.access_token_options[:header_format]
88 end
89 end
90
91 class UidTest < StrategyTestCase
92 def setup
93 super
94 strategy.stubs(:raw_info).returns({ 'id' => '123' })
95 end
96
97 test 'returns the id from raw_info' do
98 assert_equal '123', strategy.uid
99 end
100 end
101
102 class InfoTest < StrategyTestCase
103 test 'returns the secure facebook avatar url when `secure_image_url` option is specified' do
104 @options = { :secure_image_url => true }
105 raw_info = { 'name' => 'Fred Smith', 'id' => '321' }
106 strategy.stubs(:raw_info).returns(raw_info)
107 assert_equal 'https://graph.facebook.com/321/picture', strategy.info['image']
108 end
109
110 test 'returns the image_url based of the client site' do
111 @options = { :secure_image_url => true, :client_options => {:site => "https://blah.facebook.com/v2.2"}}
112 raw_info = { 'name' => 'Fred Smith', 'id' => '321' }
113 strategy.stubs(:raw_info).returns(raw_info)
114 assert_equal 'https://blah.facebook.com/v2.2/321/picture', strategy.info['image']
115 end
116
117 test 'returns the image with size specified in the `image_size` option' do
118 @options = { :image_size => 'normal' }
119 raw_info = { 'name' => 'Fred Smith', 'id' => '321' }
120 strategy.stubs(:raw_info).returns(raw_info)
121 assert_equal 'http://graph.facebook.com/321/picture?type=normal', strategy.info['image']
122 end
123
124 test 'returns the image with size specified as a symbol in the `image_size` option' do
125 @options = { :image_size => :normal }
126 raw_info = { 'name' => 'Fred Smith', 'id' => '321' }
127 strategy.stubs(:raw_info).returns(raw_info)
128 assert_equal 'http://graph.facebook.com/321/picture?type=normal', strategy.info['image']
129 end
130
131 test 'returns the image with width and height specified in the `image_size` option' do
132 @options = { :image_size => { :width => 123, :height => 987 } }
133 raw_info = { 'name' => 'Fred Smith', 'id' => '321' }
134 strategy.stubs(:raw_info).returns(raw_info)
135 assert_match 'width=123', strategy.info['image']
136 assert_match 'height=987', strategy.info['image']
137 assert_match 'http://graph.facebook.com/321/picture?', strategy.info['image']
138 end
139 end
140
141 class InfoTestOptionalDataPresent < StrategyTestCase
142 def setup
143 super
144 @raw_info ||= { 'name' => 'Fred Smith' }
145 strategy.stubs(:raw_info).returns(@raw_info)
146 end
147
148 test 'returns the name' do
149 assert_equal 'Fred Smith', strategy.info['name']
150 end
151
152 test 'returns the email' do
153 @raw_info['email'] = 'fred@smith.com'
154 assert_equal 'fred@smith.com', strategy.info['email']
155 end
156
157 test 'returns the username as nickname' do
158 @raw_info['username'] = 'fredsmith'
159 assert_equal 'fredsmith', strategy.info['nickname']
160 end
161
162 test 'returns the first name' do
163 @raw_info['first_name'] = 'Fred'
164 assert_equal 'Fred', strategy.info['first_name']
165 end
166
167 test 'returns the last name' do
168 @raw_info['last_name'] = 'Smith'
169 assert_equal 'Smith', strategy.info['last_name']
170 end
171
172 test 'returns the location name as location' do
173 @raw_info['location'] = { 'id' => '104022926303756', 'name' => 'Palo Alto, California' }
174 assert_equal 'Palo Alto, California', strategy.info['location']
175 end
176
177 test 'returns bio as description' do
178 @raw_info['bio'] = 'I am great'
179 assert_equal 'I am great', strategy.info['description']
180 end
181
182 test 'returns the facebook avatar url' do
183 @raw_info['id'] = '321'
184 assert_equal 'http://graph.facebook.com/321/picture', strategy.info['image']
185 end
186
187 test 'returns the Facebook link as the Facebook url' do
188 @raw_info['link'] = 'http://www.facebook.com/fredsmith'
189 assert_kind_of Hash, strategy.info['urls']
190 assert_equal 'http://www.facebook.com/fredsmith', strategy.info['urls']['Facebook']
191 end
192
193 test 'returns website url' do
194 @raw_info['website'] = 'https://my-wonderful-site.com'
195 assert_kind_of Hash, strategy.info['urls']
196 assert_equal 'https://my-wonderful-site.com', strategy.info['urls']['Website']
197 end
198
199 test 'return both Facebook link and website urls' do
200 @raw_info['link'] = 'http://www.facebook.com/fredsmith'
201 @raw_info['website'] = 'https://my-wonderful-site.com'
202 assert_kind_of Hash, strategy.info['urls']
203 assert_equal 'http://www.facebook.com/fredsmith', strategy.info['urls']['Facebook']
204 assert_equal 'https://my-wonderful-site.com', strategy.info['urls']['Website']
205 end
206
207 test 'returns the positive verified status' do
208 @raw_info['verified'] = true
209 assert strategy.info['verified']
210 end
211
212 test 'returns the negative verified status' do
213 @raw_info['verified'] = false
214 refute strategy.info['verified']
215 end
216 end
217
218 class InfoTestOptionalDataNotPresent < StrategyTestCase
219 def setup
220 super
221 @raw_info ||= { 'name' => 'Fred Smith' }
222 strategy.stubs(:raw_info).returns(@raw_info)
223 end
224
225 test 'has no email key' do
226 refute_has_key 'email', strategy.info
227 end
228
229 test 'has no nickname key' do
230 refute_has_key 'nickname', strategy.info
231 end
232
233 test 'has no first name key' do
234 refute_has_key 'first_name', strategy.info
235 end
236
237 test 'has no last name key' do
238 refute_has_key 'last_name', strategy.info
239 end
240
241 test 'has no location key' do
242 refute_has_key 'location', strategy.info
243 end
244
245 test 'has no description key' do
246 refute_has_key 'description', strategy.info
247 end
248
249 test 'has no urls' do
250 refute_has_key 'urls', strategy.info
251 end
252
253 test 'has no verified key' do
254 refute_has_key 'verified', strategy.info
255 end
256 end
257
258 class RawInfoTest < StrategyTestCase
259 def setup
260 super
261 @access_token = stub('OAuth2::AccessToken')
262 @appsecret_proof = 'appsecret_proof'
263 @options = {:appsecret_proof => @appsecret_proof, :fields => 'name,email'}
264 end
265
266 test 'performs a GET to https://graph.facebook.com/me' do
267 strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
268 strategy.stubs(:access_token).returns(@access_token)
269 params = {:params => @options}
270 @access_token.expects(:get).with('me', params).returns(stub_everything('OAuth2::Response'))
271 strategy.raw_info
272 end
273
274 test 'performs a GET to https://graph.facebook.com/me with locale' do
275 @options.merge!({ :locale => 'cs_CZ' })
276 strategy.stubs(:access_token).returns(@access_token)
277 strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
278 params = {:params => @options}
279 @access_token.expects(:get).with('me', params).returns(stub_everything('OAuth2::Response'))
280 strategy.raw_info
281 end
282
283 test 'performs a GET to https://graph.facebook.com/me with info_fields' do
284 @options.merge!({:info_fields => 'about'})
285 strategy.stubs(:access_token).returns(@access_token)
286 strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
287 params = {:params => {:appsecret_proof => @appsecret_proof, :fields => 'about'}}
288 @access_token.expects(:get).with('me', params).returns(stub_everything('OAuth2::Response'))
289 strategy.raw_info
290 end
291
292 test 'performs a GET to https://graph.facebook.com/me with default info_fields' do
293 strategy.stubs(:access_token).returns(@access_token)
294 strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
295 params = {:params => {:appsecret_proof => @appsecret_proof, :fields => 'name,email'}}
296 @access_token.expects(:get).with('me', params).returns(stub_everything('OAuth2::Response'))
297 strategy.raw_info
298 end
299
300 test 'returns a Hash' do
301 strategy.stubs(:access_token).returns(@access_token)
302 strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
303 raw_response = stub('Faraday::Response')
304 raw_response.stubs(:body).returns('{ "ohai": "thar" }')
305 raw_response.stubs(:status).returns(200)
306 raw_response.stubs(:headers).returns({'Content-Type' => 'application/json' })
307 oauth2_response = OAuth2::Response.new(raw_response)
308 params = {:params => @options}
309 @access_token.stubs(:get).with('me', params).returns(oauth2_response)
310 assert_kind_of Hash, strategy.raw_info
311 assert_equal 'thar', strategy.raw_info['ohai']
312 end
313
314 test 'returns an empty hash when the response is false' do
315 strategy.stubs(:access_token).returns(@access_token)
316 strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
317 oauth2_response = stub('OAuth2::Response', :parsed => false)
318 params = {:params => @options}
319 @access_token.stubs(:get).with('me', params).returns(oauth2_response)
320 assert_kind_of Hash, strategy.raw_info
321 assert_equal({}, strategy.raw_info)
322 end
323
324 test 'should not include raw_info in extras hash when skip_info is specified' do
325 @options = { :skip_info => true }
326 strategy.stubs(:raw_info).returns({:foo => 'bar' })
327 refute_has_key 'raw_info', strategy.extra
328 end
329 end
330
331 class CredentialsTest < StrategyTestCase
332 def setup
333 super
334 @access_token = stub('OAuth2::AccessToken')
335 @access_token.stubs(:token)
336 @access_token.stubs(:expires?)
337 @access_token.stubs(:expires_at)
338 @access_token.stubs(:refresh_token)
339 strategy.stubs(:access_token).returns(@access_token)
340 end
341
342 test 'returns a Hash' do
343 assert_kind_of Hash, strategy.credentials
344 end
345
346 test 'returns the token' do
347 @access_token.stubs(:token).returns('123')
348 assert_equal '123', strategy.credentials['token']
349 end
350
351 test 'returns the expiry status' do
352 @access_token.stubs(:expires?).returns(true)
353 assert strategy.credentials['expires']
354
355 @access_token.stubs(:expires?).returns(false)
356 refute strategy.credentials['expires']
357 end
358
359 test 'returns the refresh token and expiry time when expiring' do
360 ten_mins_from_now = (Time.now + 600).to_i
361 @access_token.stubs(:expires?).returns(true)
362 @access_token.stubs(:refresh_token).returns('321')
363 @access_token.stubs(:expires_at).returns(ten_mins_from_now)
364 assert_equal '321', strategy.credentials['refresh_token']
365 assert_equal ten_mins_from_now, strategy.credentials['expires_at']
366 end
367
368 test 'does not return the refresh token when test is nil and expiring' do
369 @access_token.stubs(:expires?).returns(true)
370 @access_token.stubs(:refresh_token).returns(nil)
371 assert_nil strategy.credentials['refresh_token']
372 refute_has_key 'refresh_token', strategy.credentials
373 end
374
375 test 'does not return the refresh token when not expiring' do
376 @access_token.stubs(:expires?).returns(false)
377 @access_token.stubs(:refresh_token).returns('XXX')
378 assert_nil strategy.credentials['refresh_token']
379 refute_has_key 'refresh_token', strategy.credentials
380 end
381 end
382
383 class ExtraTest < StrategyTestCase
384 def setup
385 super
386 @raw_info = { 'name' => 'Fred Smith' }
387 strategy.stubs(:raw_info).returns(@raw_info)
388 end
389
390 test 'returns a Hash' do
391 assert_kind_of Hash, strategy.extra
392 end
393
394 test 'contains raw info' do
395 assert_equal({ 'raw_info' => @raw_info }, strategy.extra)
396 end
397 end
398
399 module SignedRequestHelpers
400 def signed_request(payload, secret)
401 encoded_payload = base64_encode_url(MultiJson.encode(payload))
402 encoded_signature = base64_encode_url(signature(encoded_payload, secret))
403 [encoded_signature, encoded_payload].join('.')
404 end
405
406 def base64_encode_url(value)
407 Base64.encode64(value).tr('+/', '-_').gsub(/\n/, '')
408 end
409
410 def signature(payload, secret, algorithm = OpenSSL::Digest::SHA256.new)
411 OpenSSL::HMAC.digest(algorithm, secret, payload)
412 end
413 end
414
415 module SignedRequestTests
416 class TestCase < StrategyTestCase
417 include SignedRequestHelpers
418 end
419
420 class CookieAndParamNotPresentTest < TestCase
421 test 'is nil' do
422 assert_nil strategy.send(:signed_request_from_cookie)
423 end
424
425 test 'throws an error on calling build_access_token' do
426 assert_raises(OmniAuth::Strategies::Facebook::NoAuthorizationCodeError) { strategy.send(:with_authorization_code!) {} }
427 end
428 end
429
430 class CookiePresentTest < TestCase
431 def setup(algo = nil)
432 super()
433 @payload = {
434 'algorithm' => algo || 'HMAC-SHA256',
435 'code' => 'm4c0d3z',
436 'issued_at' => Time.now.to_i,
437 'user_id' => '123456'
438 }
439
440 @request.stubs(:cookies).returns({"fbsr_#{@client_id}" => signed_request(@payload, @client_secret)})
441 end
442
443 test 'parses the access code out from the cookie' do
444 assert_equal @payload, strategy.send(:signed_request_from_cookie)
445 end
446
447 test 'throws an error if the algorithm is unknown' do
448 setup('UNKNOWN-ALGO')
449 assert_equal "unknown algorithm: UNKNOWN-ALGO", assert_raises(OmniAuth::Facebook::SignedRequest::UnknownSignatureAlgorithmError) { strategy.send(:signed_request_from_cookie) }.message
450 end
451 end
452
453 class EmptySignedRequestTest < TestCase
454 def setup
455 super
456 @request.stubs(:params).returns({'signed_request' => ''})
457 end
458
459 test 'empty param' do
460 assert_equal nil, strategy.send(:signed_request_from_cookie)
461 end
462 end
463
464 class MissingCodeInParamsRequestTest < TestCase
465 def setup
466 super
467 @request.stubs(:params).returns({})
468 end
469
470 test 'calls fail! when a code is not included in the params' do
471 strategy.expects(:fail!).times(1).with(:no_authorization_code, kind_of(OmniAuth::Strategies::Facebook::NoAuthorizationCodeError))
472 strategy.callback_phase
473 end
474 end
475
476 class MissingCodeInCookieRequestTest < TestCase
477 def setup(algo = nil)
478 super()
479 @payload = {
480 'algorithm' => algo || 'HMAC-SHA256',
481 'code' => nil,
482 'issued_at' => Time.now.to_i,
483 'user_id' => '123456'
484 }
485
486 @request.stubs(:cookies).returns({"fbsr_#{@client_id}" => signed_request(@payload, @client_secret)})
487 end
488
489 test 'calls fail! when a code is not included in the cookie' do
490 strategy.expects(:fail!).times(1).with(:no_authorization_code, kind_of(OmniAuth::Strategies::Facebook::NoAuthorizationCodeError))
491 strategy.callback_phase
492 end
493 end
494
495 class UnknownAlgorithmInCookieRequestTest < TestCase
496 def setup
497 super()
498 @payload = {
499 'algorithm' => 'UNKNOWN-ALGO',
500 'code' => nil,
501 'issued_at' => Time.now.to_i,
502 'user_id' => '123456'
503 }
504
505 @request.stubs(:cookies).returns({"fbsr_#{@client_id}" => signed_request(@payload, @client_secret)})
506 end
507
508 test 'calls fail! when an algorithm is unknown' do
509 strategy.expects(:fail!).times(1).with(:unknown_signature_algorithm, kind_of(OmniAuth::Facebook::SignedRequest::UnknownSignatureAlgorithmError))
510 strategy.callback_phase
511 end
512 end
513 end
+0
-504
test/test.rb less more
0 require 'helper'
1 require 'omniauth-facebook'
2 require 'openssl'
3 require 'base64'
4
5 class StrategyTest < StrategyTestCase
6 include OAuth2StrategyTests
7 end
8
9 class ClientTest < StrategyTestCase
10 test 'has correct Facebook site' do
11 assert_equal 'https://graph.facebook.com', strategy.client.site
12 end
13
14 test 'has correct authorize url' do
15 assert_equal 'https://www.facebook.com/dialog/oauth', strategy.client.options[:authorize_url]
16 end
17
18 test 'has correct token url with versioning' do
19 @options = {:client_options => {:site => 'https://graph.facebook.net/v2.2'}}
20 assert_equal 'oauth/access_token', strategy.client.options[:token_url]
21 assert_equal 'https://graph.facebook.net/v2.2/oauth/access_token', strategy.client.token_url
22 end
23 end
24
25 class CallbackUrlTest < StrategyTestCase
26 test "returns the default callback url" do
27 url_base = 'http://auth.request.com'
28 @request.stubs(:url).returns("#{url_base}/some/page")
29 strategy.stubs(:script_name).returns('') # as not to depend on Rack env
30 assert_equal "#{url_base}/auth/facebook/callback", strategy.callback_url
31 end
32
33 test "returns path from callback_path option" do
34 @options = { :callback_path => "/auth/FB/done"}
35 url_base = 'http://auth.request.com'
36 @request.stubs(:url).returns("#{url_base}/page/path")
37 strategy.stubs(:script_name).returns('') # as not to depend on Rack env
38 assert_equal "#{url_base}/auth/FB/done", strategy.callback_url
39 end
40
41 test "returns url from callback_url option" do
42 url = 'https://auth.myapp.com/auth/fb/callback'
43 @options = { :callback_url => url }
44 assert_equal url, strategy.callback_url
45 end
46 end
47
48 class AuthorizeParamsTest < StrategyTestCase
49 test 'includes default scope for email' do
50 assert strategy.authorize_params.is_a?(Hash)
51 assert_equal 'email', strategy.authorize_params[:scope]
52 end
53
54 test 'includes display parameter from request when present' do
55 @request.stubs(:params).returns({ 'display' => 'touch' })
56 assert strategy.authorize_params.is_a?(Hash)
57 assert_equal 'touch', strategy.authorize_params[:display]
58 end
59
60 test 'includes auth_type parameter from request when present' do
61 @request.stubs(:params).returns({ 'auth_type' => 'reauthenticate' })
62 assert strategy.authorize_params.is_a?(Hash)
63 assert_equal 'reauthenticate', strategy.authorize_params[:auth_type]
64 end
65
66 test 'overrides default scope with parameter passed from request' do
67 @request.stubs(:params).returns({ 'scope' => 'email' })
68 assert strategy.authorize_params.is_a?(Hash)
69 assert_equal 'email', strategy.authorize_params[:scope]
70 end
71 end
72
73 class TokeParamsTest < StrategyTestCase
74 test 'has correct parse strategy' do
75 assert_equal :query, strategy.token_params[:parse]
76 end
77 end
78
79 class AccessTokenOptionsTest < StrategyTestCase
80 test 'has correct param name by default' do
81 assert_equal 'access_token', strategy.access_token_options[:param_name]
82 end
83
84 test 'has correct header format by default' do
85 assert_equal 'OAuth %s', strategy.access_token_options[:header_format]
86 end
87 end
88
89 class UidTest < StrategyTestCase
90 def setup
91 super
92 strategy.stubs(:raw_info).returns({ 'id' => '123' })
93 end
94
95 test 'returns the id from raw_info' do
96 assert_equal '123', strategy.uid
97 end
98 end
99
100 class InfoTest < StrategyTestCase
101 test 'returns the secure facebook avatar url when `secure_image_url` option is specified' do
102 @options = { :secure_image_url => true }
103 raw_info = { 'name' => 'Fred Smith', 'id' => '321' }
104 strategy.stubs(:raw_info).returns(raw_info)
105 assert_equal 'https://graph.facebook.com/321/picture', strategy.info['image']
106 end
107
108 test 'returns the image_url based of the client site' do
109 @options = { :secure_image_url => true, :client_options => {:site => "https://blah.facebook.com/v2.2"}}
110 raw_info = { 'name' => 'Fred Smith', 'id' => '321' }
111 strategy.stubs(:raw_info).returns(raw_info)
112 assert_equal 'https://blah.facebook.com/v2.2/321/picture', strategy.info['image']
113 end
114
115 test 'returns the image with size specified in the `image_size` option' do
116 @options = { :image_size => 'normal' }
117 raw_info = { 'name' => 'Fred Smith', 'id' => '321' }
118 strategy.stubs(:raw_info).returns(raw_info)
119 assert_equal 'http://graph.facebook.com/321/picture?type=normal', strategy.info['image']
120 end
121
122 test 'returns the image with size specified as a symbol in the `image_size` option' do
123 @options = { :image_size => :normal }
124 raw_info = { 'name' => 'Fred Smith', 'id' => '321' }
125 strategy.stubs(:raw_info).returns(raw_info)
126 assert_equal 'http://graph.facebook.com/321/picture?type=normal', strategy.info['image']
127 end
128
129 test 'returns the image with width and height specified in the `image_size` option' do
130 @options = { :image_size => { :width => 123, :height => 987 } }
131 raw_info = { 'name' => 'Fred Smith', 'id' => '321' }
132 strategy.stubs(:raw_info).returns(raw_info)
133 assert_match 'width=123', strategy.info['image']
134 assert_match 'height=987', strategy.info['image']
135 assert_match 'http://graph.facebook.com/321/picture?', strategy.info['image']
136 end
137 end
138
139 class InfoTestOptionalDataPresent < StrategyTestCase
140 def setup
141 super
142 @raw_info ||= { 'name' => 'Fred Smith' }
143 strategy.stubs(:raw_info).returns(@raw_info)
144 end
145
146 test 'returns the name' do
147 assert_equal 'Fred Smith', strategy.info['name']
148 end
149
150 test 'returns the email' do
151 @raw_info['email'] = 'fred@smith.com'
152 assert_equal 'fred@smith.com', strategy.info['email']
153 end
154
155 test 'returns the username as nickname' do
156 @raw_info['username'] = 'fredsmith'
157 assert_equal 'fredsmith', strategy.info['nickname']
158 end
159
160 test 'returns the first name' do
161 @raw_info['first_name'] = 'Fred'
162 assert_equal 'Fred', strategy.info['first_name']
163 end
164
165 test 'returns the last name' do
166 @raw_info['last_name'] = 'Smith'
167 assert_equal 'Smith', strategy.info['last_name']
168 end
169
170 test 'returns the location name as location' do
171 @raw_info['location'] = { 'id' => '104022926303756', 'name' => 'Palo Alto, California' }
172 assert_equal 'Palo Alto, California', strategy.info['location']
173 end
174
175 test 'returns bio as description' do
176 @raw_info['bio'] = 'I am great'
177 assert_equal 'I am great', strategy.info['description']
178 end
179
180 test 'returns the facebook avatar url' do
181 @raw_info['id'] = '321'
182 assert_equal 'http://graph.facebook.com/321/picture', strategy.info['image']
183 end
184
185 test 'returns the Facebook link as the Facebook url' do
186 @raw_info['link'] = 'http://www.facebook.com/fredsmith'
187 assert_kind_of Hash, strategy.info['urls']
188 assert_equal 'http://www.facebook.com/fredsmith', strategy.info['urls']['Facebook']
189 end
190
191 test 'returns website url' do
192 @raw_info['website'] = 'https://my-wonderful-site.com'
193 assert_kind_of Hash, strategy.info['urls']
194 assert_equal 'https://my-wonderful-site.com', strategy.info['urls']['Website']
195 end
196
197 test 'return both Facebook link and website urls' do
198 @raw_info['link'] = 'http://www.facebook.com/fredsmith'
199 @raw_info['website'] = 'https://my-wonderful-site.com'
200 assert_kind_of Hash, strategy.info['urls']
201 assert_equal 'http://www.facebook.com/fredsmith', strategy.info['urls']['Facebook']
202 assert_equal 'https://my-wonderful-site.com', strategy.info['urls']['Website']
203 end
204
205 test 'returns the positive verified status' do
206 @raw_info['verified'] = true
207 assert strategy.info['verified']
208 end
209
210 test 'returns the negative verified status' do
211 @raw_info['verified'] = false
212 refute strategy.info['verified']
213 end
214 end
215
216 class InfoTestOptionalDataNotPresent < StrategyTestCase
217 def setup
218 super
219 @raw_info ||= { 'name' => 'Fred Smith' }
220 strategy.stubs(:raw_info).returns(@raw_info)
221 end
222
223 test 'has no email key' do
224 refute_has_key 'email', strategy.info
225 end
226
227 test 'has no nickname key' do
228 refute_has_key 'nickname', strategy.info
229 end
230
231 test 'has no first name key' do
232 refute_has_key 'first_name', strategy.info
233 end
234
235 test 'has no last name key' do
236 refute_has_key 'last_name', strategy.info
237 end
238
239 test 'has no location key' do
240 refute_has_key 'location', strategy.info
241 end
242
243 test 'has no description key' do
244 refute_has_key 'description', strategy.info
245 end
246
247 test 'has no urls' do
248 refute_has_key 'urls', strategy.info
249 end
250
251 test 'has no verified key' do
252 refute_has_key 'verified', strategy.info
253 end
254 end
255
256 class RawInfoTest < StrategyTestCase
257 def setup
258 super
259 @access_token = stub('OAuth2::AccessToken')
260 @appsecret_proof = 'appsecret_proof'
261 @options = {:appsecret_proof => @appsecret_proof}
262 end
263
264 test 'performs a GET to https://graph.facebook.com/me' do
265 strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
266 strategy.stubs(:access_token).returns(@access_token)
267 params = {:params => @options}
268 @access_token.expects(:get).with('me', params).returns(stub_everything('OAuth2::Response'))
269 strategy.raw_info
270 end
271
272 test 'performs a GET to https://graph.facebook.com/me with locale' do
273 @options.merge!({ :locale => 'cs_CZ' })
274 strategy.stubs(:access_token).returns(@access_token)
275 strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
276 params = {:params => @options}
277 @access_token.expects(:get).with('me', params).returns(stub_everything('OAuth2::Response'))
278 strategy.raw_info
279 end
280
281 test 'performs a GET to https://graph.facebook.com/me with info_fields' do
282 @options.merge!({:info_fields => 'about'})
283 strategy.stubs(:access_token).returns(@access_token)
284 strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
285 params = {:params => {:appsecret_proof => @appsecret_proof, :fields => 'about'}}
286 @access_token.expects(:get).with('me', params).returns(stub_everything('OAuth2::Response'))
287 strategy.raw_info
288 end
289
290 test 'returns a Hash' do
291 strategy.stubs(:access_token).returns(@access_token)
292 strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
293 raw_response = stub('Faraday::Response')
294 raw_response.stubs(:body).returns('{ "ohai": "thar" }')
295 raw_response.stubs(:status).returns(200)
296 raw_response.stubs(:headers).returns({'Content-Type' => 'application/json' })
297 oauth2_response = OAuth2::Response.new(raw_response)
298 params = {:params => @options}
299 @access_token.stubs(:get).with('me', params).returns(oauth2_response)
300 assert_kind_of Hash, strategy.raw_info
301 assert_equal 'thar', strategy.raw_info['ohai']
302 end
303
304 test 'returns an empty hash when the response is false' do
305 strategy.stubs(:access_token).returns(@access_token)
306 strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
307 oauth2_response = stub('OAuth2::Response', :parsed => false)
308 params = {:params => @options}
309 @access_token.stubs(:get).with('me', params).returns(oauth2_response)
310 assert_kind_of Hash, strategy.raw_info
311 assert_equal({}, strategy.raw_info)
312 end
313
314 test 'should not include raw_info in extras hash when skip_info is specified' do
315 @options = { :skip_info => true }
316 strategy.stubs(:raw_info).returns({:foo => 'bar' })
317 refute_has_key 'raw_info', strategy.extra
318 end
319 end
320
321 class CredentialsTest < StrategyTestCase
322 def setup
323 super
324 @access_token = stub('OAuth2::AccessToken')
325 @access_token.stubs(:token)
326 @access_token.stubs(:expires?)
327 @access_token.stubs(:expires_at)
328 @access_token.stubs(:refresh_token)
329 strategy.stubs(:access_token).returns(@access_token)
330 end
331
332 test 'returns a Hash' do
333 assert_kind_of Hash, strategy.credentials
334 end
335
336 test 'returns the token' do
337 @access_token.stubs(:token).returns('123')
338 assert_equal '123', strategy.credentials['token']
339 end
340
341 test 'returns the expiry status' do
342 @access_token.stubs(:expires?).returns(true)
343 assert strategy.credentials['expires']
344
345 @access_token.stubs(:expires?).returns(false)
346 refute strategy.credentials['expires']
347 end
348
349 test 'returns the refresh token and expiry time when expiring' do
350 ten_mins_from_now = (Time.now + 600).to_i
351 @access_token.stubs(:expires?).returns(true)
352 @access_token.stubs(:refresh_token).returns('321')
353 @access_token.stubs(:expires_at).returns(ten_mins_from_now)
354 assert_equal '321', strategy.credentials['refresh_token']
355 assert_equal ten_mins_from_now, strategy.credentials['expires_at']
356 end
357
358 test 'does not return the refresh token when test is nil and expiring' do
359 @access_token.stubs(:expires?).returns(true)
360 @access_token.stubs(:refresh_token).returns(nil)
361 assert_nil strategy.credentials['refresh_token']
362 refute_has_key 'refresh_token', strategy.credentials
363 end
364
365 test 'does not return the refresh token when not expiring' do
366 @access_token.stubs(:expires?).returns(false)
367 @access_token.stubs(:refresh_token).returns('XXX')
368 assert_nil strategy.credentials['refresh_token']
369 refute_has_key 'refresh_token', strategy.credentials
370 end
371 end
372
373 class ExtraTest < StrategyTestCase
374 def setup
375 super
376 @raw_info = { 'name' => 'Fred Smith' }
377 strategy.stubs(:raw_info).returns(@raw_info)
378 end
379
380 test 'returns a Hash' do
381 assert_kind_of Hash, strategy.extra
382 end
383
384 test 'contains raw info' do
385 assert_equal({ 'raw_info' => @raw_info }, strategy.extra)
386 end
387 end
388
389 module SignedRequestHelpers
390 def signed_request(payload, secret)
391 encoded_payload = base64_encode_url(MultiJson.encode(payload))
392 encoded_signature = base64_encode_url(signature(encoded_payload, secret))
393 [encoded_signature, encoded_payload].join('.')
394 end
395
396 def base64_encode_url(value)
397 Base64.encode64(value).tr('+/', '-_').gsub(/\n/, '')
398 end
399
400 def signature(payload, secret, algorithm = OpenSSL::Digest::SHA256.new)
401 OpenSSL::HMAC.digest(algorithm, secret, payload)
402 end
403 end
404
405 module SignedRequestTests
406 class TestCase < StrategyTestCase
407 include SignedRequestHelpers
408 end
409
410 class CookieAndParamNotPresentTest < TestCase
411 test 'is nil' do
412 assert_nil strategy.send(:signed_request_from_cookie)
413 end
414
415 test 'throws an error on calling build_access_token' do
416 assert_raises(OmniAuth::Strategies::Facebook::NoAuthorizationCodeError) { strategy.send(:with_authorization_code!) {} }
417 end
418 end
419
420 class CookiePresentTest < TestCase
421 def setup(algo = nil)
422 super()
423 @payload = {
424 'algorithm' => algo || 'HMAC-SHA256',
425 'code' => 'm4c0d3z',
426 'issued_at' => Time.now.to_i,
427 'user_id' => '123456'
428 }
429
430 @request.stubs(:cookies).returns({"fbsr_#{@client_id}" => signed_request(@payload, @client_secret)})
431 end
432
433 test 'parses the access code out from the cookie' do
434 assert_equal @payload, strategy.send(:signed_request_from_cookie)
435 end
436
437 test 'throws an error if the algorithm is unknown' do
438 setup('UNKNOWN-ALGO')
439 assert_equal "unknown algorithm: UNKNOWN-ALGO", assert_raises(OmniAuth::Strategies::Facebook::UnknownSignatureAlgorithmError) { strategy.send(:signed_request_from_cookie) }.message
440 end
441 end
442
443 class EmptySignedRequestTest < TestCase
444 def setup
445 super
446 @request.stubs(:params).returns({'signed_request' => ''})
447 end
448
449 test 'empty param' do
450 assert_equal nil, strategy.send(:signed_request_from_cookie)
451 end
452 end
453
454 class MissingCodeInParamsRequestTest < TestCase
455 def setup
456 super
457 @request.stubs(:params).returns({})
458 end
459
460 test 'calls fail! when a code is not included in the params' do
461 strategy.expects(:fail!).times(1).with(:no_authorization_code, kind_of(OmniAuth::Strategies::Facebook::NoAuthorizationCodeError))
462 strategy.callback_phase
463 end
464 end
465
466 class MissingCodeInCookieRequestTest < TestCase
467 def setup(algo = nil)
468 super()
469 @payload = {
470 'algorithm' => algo || 'HMAC-SHA256',
471 'code' => nil,
472 'issued_at' => Time.now.to_i,
473 'user_id' => '123456'
474 }
475
476 @request.stubs(:cookies).returns({"fbsr_#{@client_id}" => signed_request(@payload, @client_secret)})
477 end
478
479 test 'calls fail! when a code is not included in the cookie' do
480 strategy.expects(:fail!).times(1).with(:no_authorization_code, kind_of(OmniAuth::Strategies::Facebook::NoAuthorizationCodeError))
481 strategy.callback_phase
482 end
483 end
484
485 class UnknownAlgorithmInCookieRequestTest < TestCase
486 def setup
487 super()
488 @payload = {
489 'algorithm' => 'UNKNOWN-ALGO',
490 'code' => nil,
491 'issued_at' => Time.now.to_i,
492 'user_id' => '123456'
493 }
494
495 @request.stubs(:cookies).returns({"fbsr_#{@client_id}" => signed_request(@payload, @client_secret)})
496 end
497
498 test 'calls fail! when an algorithm is unknown' do
499 strategy.expects(:fail!).times(1).with(:unknown_signature_algorithm, kind_of(OmniAuth::Strategies::Facebook::UnknownSignatureAlgorithmError))
500 strategy.callback_phase
501 end
502 end
503 end