omniauth-facebook 1.5.1 → 1.6.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +99 -0
- data/Gemfile +1 -1
- data/README.md +17 -9
- data/example/Gemfile +1 -1
- data/example/Gemfile.lock +22 -23
- data/lib/omniauth/facebook/version.rb +1 -1
- data/lib/omniauth/strategies/facebook.rb +72 -47
- data/omniauth-facebook.gemspec +5 -4
- data/test/helper.rb +3 -2
- data/test/test.rb +89 -16
- metadata +14 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f7b030284d8a9bc6fbcf3906a96421b08624cf21
|
4
|
+
data.tar.gz: 4884decdc889f23340364cf73b94d827246c8df7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ece06ac88f1c8122aa22e54a81740611446af348ce4fb9ce91dcc586311a5d45086ad7ccf5f4b724641dcc3ce7bee171ffdfc1bc0c428a98647308da0077422b
|
7
|
+
data.tar.gz: 113c6ba0645ee31730f662cadd48f30f8292b12d3b72921f419bb0e5e4ecf63e54fa982323e16b4d3b9620054ac05112f8a15390c2da639c48f33e883f554cb2
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
## 1.6.0.rc1 (Unreleased)
|
2
|
+
|
3
|
+
Features:
|
4
|
+
|
5
|
+
- ability to specify `auth_type` per-request (#78, @sebastian-stylesaint)
|
6
|
+
- image dimension can be set using `image_size` option (#91, @weilu)
|
7
|
+
- update Facebook authorize URL to fix broken authorization (#103, @dlackty)
|
8
|
+
- adds `info_fields` option (#109, @bloudermilk)
|
9
|
+
- adds `locale` parameter (#133, @donbobka, @simi)
|
10
|
+
- add automatically `appsecret_proof` (#140, @nlsrchtr, @simi)
|
11
|
+
|
12
|
+
Changes:
|
13
|
+
|
14
|
+
- `NoAuthorizationCodeError` and `UnknownSignatureAlgorithmError` will now `fail!` (#117, @nchelluri)
|
15
|
+
- don't try to parse the signature if it's nil (#127, @oriolgual)
|
16
|
+
|
17
|
+
## 1.5.1 (2013-11-18)
|
18
|
+
|
19
|
+
Changes:
|
20
|
+
|
21
|
+
- don't use `access_token` in URL [CVE-2013-4593](https://github.com/mkdynamic/omniauth-facebook/wiki/Access-token-vulnerability:-CVE-2013-4593) (@homakov, @mkdynamic, @simi)
|
22
|
+
|
23
|
+
## 1.5.0 (2013-11-13)
|
24
|
+
|
25
|
+
Changes:
|
26
|
+
|
27
|
+
- remove `state` param to fix CSRF vulnerabilty [CVE-2013-4562](https://github.com/mkdynamic/omniauth-facebook/wiki/CSRF-vulnerability:-CVE-2013-4562) (@homakov, @mkdynamic, @simi)
|
28
|
+
|
29
|
+
## 1.4.1 (2012-07-07)
|
30
|
+
|
31
|
+
Changes:
|
32
|
+
|
33
|
+
- update to omniauth-oauth2 1.1.0 for csrf protection (@mkdynamic)
|
34
|
+
|
35
|
+
## 1.4.0 (2012-06-24)
|
36
|
+
|
37
|
+
Features:
|
38
|
+
|
39
|
+
- obey `skip_info?` config (@mkdynamic)
|
40
|
+
- add support of the `:auth_type` option to `:authorize_options` (#58, @JHeidinga, @mkdynamic)
|
41
|
+
- support `access_token` parameter as part of the callback request (#62, @steverandy)
|
42
|
+
|
43
|
+
## 1.3.0 (2012-05-05)
|
44
|
+
|
45
|
+
Features:
|
46
|
+
|
47
|
+
- dynamic permissions in the auth params (#30, @famoseagle)
|
48
|
+
- add support for facebook canvas (@mkdynamic)
|
49
|
+
- add verified key to the info hash (#34, @ryansobol)
|
50
|
+
- add option to use secure url for image in auth hash (@mkdynamic)
|
51
|
+
- add option to specify image size (@mkdynamic)
|
52
|
+
|
53
|
+
Changes:
|
54
|
+
|
55
|
+
- have `raw_info` return an empty hash if the Facebook response returns false (#44, @brianjlandau)
|
56
|
+
- prevent oauth2 from interpreting Facebook's expires field as `expires_in`, when it's really `expires_at` (#39, @watsonbox)
|
57
|
+
- remove deprecated `offline_access` permission (@mkdynamic)
|
58
|
+
|
59
|
+
Changes:
|
60
|
+
|
61
|
+
- tidy up the `callback_url` option (@mkdynamic)
|
62
|
+
|
63
|
+
## 1.2.0 (2012-01-06)
|
64
|
+
|
65
|
+
Features:
|
66
|
+
|
67
|
+
- add `state` to authorization params (#19, @GermanDZ)
|
68
|
+
|
69
|
+
Changes:
|
70
|
+
|
71
|
+
- lock to `rack ~> 1.3.6` (@mkdynamic)
|
72
|
+
|
73
|
+
## 1.1.0 (2011-12-10)
|
74
|
+
|
75
|
+
Features:
|
76
|
+
|
77
|
+
- add `callback_url` option (#13, @gumayunov)
|
78
|
+
- support for parsing code from signed request cookie (client-side flow) (@mkdynamic)
|
79
|
+
|
80
|
+
## 1.0.0 (2011-11-19)
|
81
|
+
|
82
|
+
Features:
|
83
|
+
|
84
|
+
- allow passing of display via option (@mkdynamic)
|
85
|
+
|
86
|
+
Bugfixes:
|
87
|
+
|
88
|
+
- fix `ten_mins_from_now` calculation (#7, @olegkovalenko)
|
89
|
+
|
90
|
+
## 1.0.0.rc2 (2011-11-11)
|
91
|
+
|
92
|
+
Features:
|
93
|
+
|
94
|
+
- allow passing `display` parameter (@mkdynamic)
|
95
|
+
- included default scope (@mkdynamic)
|
96
|
+
|
97
|
+
## 1.0.0.rc1 (2011-10-29)
|
98
|
+
|
99
|
+
- first public gem release (@mkdynamic)
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,11 @@
|
|
1
|
-
|
1
|
+
**NOTE: If you're running < 1.5.1, please upgrade to address 2 security vulnerabilities.
|
2
|
+
More details [here](https://github.com/mkdynamic/omniauth-facebook/wiki/CSRF-vulnerability:-CVE-2013-4562) and [here](https://github.com/mkdynamic/omniauth-facebook/wiki/Access-token-vulnerability:-CVE-2013-4593).**
|
2
3
|
|
3
|
-
|
4
|
+
---
|
5
|
+
|
6
|
+
# OmniAuth Facebook [![Build Status](https://secure.travis-ci.org/mkdynamic/omniauth-facebook.png?branch=master)](https://travis-ci.org/mkdynamic/omniauth-facebook)
|
7
|
+
|
8
|
+
Facebook OAuth2 Strategy for OmniAuth.
|
4
9
|
|
5
10
|
Supports the OAuth 2.0 server-side and client-side flows. Read the Facebook docs for more details: http://developers.facebook.com/docs/authentication
|
6
11
|
|
@@ -16,7 +21,7 @@ Then `bundle install`.
|
|
16
21
|
|
17
22
|
## Usage
|
18
23
|
|
19
|
-
`OmniAuth::Strategies::Facebook` is simply a Rack middleware. Read the OmniAuth
|
24
|
+
`OmniAuth::Strategies::Facebook` is simply a Rack middleware. Read the OmniAuth docs for detailed instructions: https://github.com/intridea/omniauth.
|
20
25
|
|
21
26
|
Here's a quick example, adding the middleware to a Rails app in `config/initializers/omniauth.rb`:
|
22
27
|
|
@@ -37,7 +42,9 @@ You can configure several options, which you pass in to the `provider` method vi
|
|
37
42
|
* `auth_type`: Optionally specifies the requested authentication features as a comma-separated list, as per https://developers.facebook.com/docs/authentication/reauthentication/.
|
38
43
|
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`.
|
39
44
|
* `secure_image_url`: Set to `true` to use https for the avatar image url returned in the auth hash. Default is `false`.
|
40
|
-
* `image_size`: Set the size for the returned image url in the auth hash. Valid options
|
45
|
+
* `image_size`: 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/reference/api/user/ (only /me endpoint).
|
47
|
+
* `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/.
|
41
48
|
|
42
49
|
For example, to request `email`, `user_birthday` and `read_stream` permissions and display the authentication page in a popup window:
|
43
50
|
|
@@ -50,7 +57,7 @@ end
|
|
50
57
|
|
51
58
|
### Per-Request Options
|
52
59
|
|
53
|
-
If you want to set the `display` format or `scope` on a per-request basis, you can just pass it to the OmniAuth request phase URL, for example: `/auth/facebook?display=popup` or `/auth/facebook?scope=email`.
|
60
|
+
If you want to set the `display` format, `auth_type`, or `scope` on a per-request basis, you can just pass it to the OmniAuth request phase URL, for example: `/auth/facebook?display=popup` or `/auth/facebook?scope=email`.
|
54
61
|
|
55
62
|
### Custom Callback URL/Path
|
56
63
|
|
@@ -134,7 +141,7 @@ There are then 2 scenarios for what happens next:
|
|
134
141
|
|
135
142
|
Take a look at [the example Sinatra app for one option of how you can integrate with a canvas page](https://github.com/mkdynamic/omniauth-facebook/blob/master/example/config.ru).
|
136
143
|
|
137
|
-
Bear in mind you have several options
|
144
|
+
Bear in mind you have several [options](https://developers.facebook.com/docs/opengraph/authentication). Read [the Facebook docs on canvas page authentication](https://developers.facebook.com/docs/authentication/canvas/) for more info.
|
138
145
|
|
139
146
|
## Token Expiry
|
140
147
|
|
@@ -148,7 +155,7 @@ You can exchange this short lived access token for a longer lived version. Read
|
|
148
155
|
|
149
156
|
### Server-Side Flow
|
150
157
|
|
151
|
-
If you use the server-side flow, Facebook will give you back a longer
|
158
|
+
If you use the server-side flow, Facebook will give you back a longer lived access token (~ 60 days).
|
152
159
|
|
153
160
|
If you're having issue getting a long lived token with the server-side flow, make sure to enable the 'deprecate offline_access setting' in you Facebook app config. Read the [Facebook docs about the offline_access deprecation](https://developers.facebook.com/roadmap/offline-access-removal/) for more information.
|
154
161
|
|
@@ -156,12 +163,13 @@ If you're having issue getting a long lived token with the server-side flow, mak
|
|
156
163
|
|
157
164
|
Actively tested with the following Ruby versions:
|
158
165
|
|
166
|
+
- MRI 2.0.0
|
159
167
|
- MRI 1.9.3
|
160
168
|
- MRI 1.9.2
|
161
169
|
- MRI 1.8.7
|
162
|
-
- JRuby 1.
|
170
|
+
- JRuby 1.7.4
|
163
171
|
|
164
|
-
*NB.* For JRuby, you'll need to install the `jruby-openssl` gem. There's no way to automatically specify this in a Rubygem gemspec, so you need to manually add it your project's own Gemfile:
|
172
|
+
*NB.* For JRuby < 1.7, you'll need to install the `jruby-openssl` gem. There's no way to automatically specify this in a Rubygem gemspec, so you need to manually add it your project's own Gemfile:
|
165
173
|
|
166
174
|
```ruby
|
167
175
|
gem 'jruby-openssl', :platform => :jruby
|
data/example/Gemfile
CHANGED
data/example/Gemfile.lock
CHANGED
@@ -1,41 +1,40 @@
|
|
1
1
|
PATH
|
2
2
|
remote: ../
|
3
3
|
specs:
|
4
|
-
omniauth-facebook (1.
|
5
|
-
omniauth-oauth2 (~> 1.1
|
4
|
+
omniauth-facebook (1.6.0.rc1)
|
5
|
+
omniauth-oauth2 (~> 1.1)
|
6
6
|
|
7
7
|
GEM
|
8
|
-
remote:
|
8
|
+
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
faraday (0.8.
|
11
|
-
multipart-post (~> 1.
|
12
|
-
hashie (
|
13
|
-
httpauth (0.
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
oauth2 (0.8.0)
|
10
|
+
faraday (0.8.8)
|
11
|
+
multipart-post (~> 1.2.0)
|
12
|
+
hashie (2.0.5)
|
13
|
+
httpauth (0.2.0)
|
14
|
+
jwt (0.1.8)
|
15
|
+
multi_json (>= 1.5)
|
16
|
+
multi_json (1.8.2)
|
17
|
+
multipart-post (1.2.0)
|
18
|
+
oauth2 (0.8.1)
|
20
19
|
faraday (~> 0.8)
|
21
20
|
httpauth (~> 0.1)
|
22
21
|
jwt (~> 0.1.4)
|
23
22
|
multi_json (~> 1.0)
|
24
23
|
rack (~> 1.2)
|
25
|
-
omniauth (1.1.
|
26
|
-
hashie (
|
24
|
+
omniauth (1.1.4)
|
25
|
+
hashie (>= 1.2, < 3)
|
27
26
|
rack
|
28
|
-
omniauth-oauth2 (1.1.
|
27
|
+
omniauth-oauth2 (1.1.1)
|
29
28
|
oauth2 (~> 0.8.0)
|
30
29
|
omniauth (~> 1.0)
|
31
|
-
rack (1.
|
32
|
-
rack-protection (1.
|
30
|
+
rack (1.5.2)
|
31
|
+
rack-protection (1.5.1)
|
33
32
|
rack
|
34
|
-
sinatra (1.
|
35
|
-
rack (~> 1.
|
36
|
-
rack-protection (~> 1.
|
37
|
-
tilt (~> 1.3, >= 1.3.
|
38
|
-
tilt (1.
|
33
|
+
sinatra (1.4.4)
|
34
|
+
rack (~> 1.4)
|
35
|
+
rack-protection (~> 1.4)
|
36
|
+
tilt (~> 1.3, >= 1.3.4)
|
37
|
+
tilt (1.4.1)
|
39
38
|
|
40
39
|
PLATFORMS
|
41
40
|
ruby
|
@@ -2,16 +2,19 @@ require 'omniauth/strategies/oauth2'
|
|
2
2
|
require 'base64'
|
3
3
|
require 'openssl'
|
4
4
|
require 'rack/utils'
|
5
|
+
require 'uri'
|
5
6
|
|
6
7
|
module OmniAuth
|
7
8
|
module Strategies
|
8
9
|
class Facebook < OmniAuth::Strategies::OAuth2
|
9
10
|
class NoAuthorizationCodeError < StandardError; end
|
11
|
+
class UnknownSignatureAlgorithmError < NotImplementedError; end
|
10
12
|
|
11
13
|
DEFAULT_SCOPE = 'email'
|
12
14
|
|
13
15
|
option :client_options, {
|
14
16
|
:site => 'https://graph.facebook.com',
|
17
|
+
:authorize_url => "https://www.facebook.com/dialog/oauth",
|
15
18
|
:token_url => '/oauth/access_token'
|
16
19
|
}
|
17
20
|
|
@@ -35,7 +38,7 @@ module OmniAuth
|
|
35
38
|
'name' => raw_info['name'],
|
36
39
|
'first_name' => raw_info['first_name'],
|
37
40
|
'last_name' => raw_info['last_name'],
|
38
|
-
'image' =>
|
41
|
+
'image' => image_url(uid, options),
|
39
42
|
'description' => raw_info['bio'],
|
40
43
|
'urls' => {
|
41
44
|
'Facebook' => raw_info['link'],
|
@@ -53,28 +56,28 @@ module OmniAuth
|
|
53
56
|
end
|
54
57
|
|
55
58
|
def raw_info
|
56
|
-
@raw_info ||= access_token.get('/me').parsed || {}
|
59
|
+
@raw_info ||= access_token.get('/me', info_options).parsed || {}
|
57
60
|
end
|
58
61
|
|
59
|
-
def
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
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
|
+
super
|
72
|
+
rescue NoAuthorizationCodeError => e
|
73
|
+
fail!(:no_authorization_code, e)
|
74
|
+
rescue UnknownSignatureAlgorithmError => e
|
75
|
+
fail!(:unknown_signature_algoruthm, e)
|
72
76
|
end
|
73
77
|
|
74
78
|
def request_phase
|
75
79
|
if signed_request_contains_access_token?
|
76
|
-
#
|
77
|
-
# callback URL directly and pass the signed request along
|
80
|
+
# If we already have an access token, we can just hit the callback URL directly and pass the signed request.
|
78
81
|
params = { :signed_request => raw_signed_request }
|
79
82
|
query = Rack::Utils.build_query(params)
|
80
83
|
|
@@ -89,10 +92,9 @@ module OmniAuth
|
|
89
92
|
end
|
90
93
|
end
|
91
94
|
|
92
|
-
# NOTE
|
93
|
-
#
|
94
|
-
#
|
95
|
-
# https://github.com/facebook/php-sdk/blob/master/src/base_facebook.php#L348
|
95
|
+
# NOTE If we're using code from the signed request then FB sets the redirect_uri to '' during the authorize
|
96
|
+
# phase and it must match during the access_token phase:
|
97
|
+
# https://github.com/facebook/php-sdk/blob/master/src/base_facebook.php#L348
|
96
98
|
def callback_url
|
97
99
|
if @authorization_code_from_signed_request
|
98
100
|
''
|
@@ -105,16 +107,13 @@ module OmniAuth
|
|
105
107
|
options.access_token_options.inject({}) { |h,(k,v)| h[k.to_sym] = v; h }
|
106
108
|
end
|
107
109
|
|
108
|
-
|
109
|
-
# You can
|
110
|
-
# you need to set them dynamically. You can also set these options
|
111
|
-
# in the OmniAuth config :authorize_params option.
|
110
|
+
# You can pass +display+, +scope+, or +auth_type+ params to the auth request, if you need to set them dynamically.
|
111
|
+
# You can also set these options in the OmniAuth config :authorize_params option.
|
112
112
|
#
|
113
113
|
# /auth/facebook?display=popup
|
114
|
-
#
|
115
114
|
def authorize_params
|
116
115
|
super.tap do |params|
|
117
|
-
%w[display scope].each do |v|
|
116
|
+
%w[display scope auth_type].each do |v|
|
118
117
|
if request.params[v]
|
119
118
|
params[v.to_sym] = request.params[v]
|
120
119
|
end
|
@@ -124,42 +123,49 @@ module OmniAuth
|
|
124
123
|
end
|
125
124
|
end
|
126
125
|
|
127
|
-
##
|
128
126
|
# Parse signed request in order, from:
|
129
127
|
#
|
130
|
-
# 1.
|
131
|
-
# 2.
|
132
|
-
#
|
128
|
+
# 1. The request 'signed_request' param (server-side flow from canvas pages) or
|
129
|
+
# 2. A cookie (client-side flow via JS SDK)
|
133
130
|
def signed_request
|
134
|
-
@signed_request ||= raw_signed_request &&
|
135
|
-
|
131
|
+
@signed_request ||= raw_signed_request && parse_signed_request(raw_signed_request)
|
132
|
+
end
|
133
|
+
|
134
|
+
protected
|
135
|
+
|
136
|
+
def build_access_token
|
137
|
+
if signed_request_contains_access_token?
|
138
|
+
hash = signed_request.clone
|
139
|
+
::OAuth2::AccessToken.new(
|
140
|
+
client,
|
141
|
+
hash.delete('oauth_token'),
|
142
|
+
hash.merge!(access_token_options.merge(:expires_at => hash.delete('expires')))
|
143
|
+
)
|
144
|
+
else
|
145
|
+
with_authorization_code! { super }.tap do |token|
|
146
|
+
token.options.merge!(access_token_options)
|
147
|
+
end
|
148
|
+
end
|
136
149
|
end
|
137
150
|
|
138
151
|
private
|
139
152
|
|
140
153
|
def raw_signed_request
|
141
|
-
request.params['signed_request'] ||
|
142
|
-
request.cookies["fbsr_#{client.id}"]
|
154
|
+
request.params['signed_request'] || request.cookies["fbsr_#{client.id}"]
|
143
155
|
end
|
144
156
|
|
145
|
-
|
146
|
-
#
|
147
|
-
# has already authorized your application, the JSON object will be
|
148
|
-
# contain the access token.
|
157
|
+
# If the signed_request comes from a FB canvas page and the user has already authorized your application, the JSON
|
158
|
+
# object will be contain the access token.
|
149
159
|
#
|
150
160
|
# https://developers.facebook.com/docs/authentication/canvas/
|
151
|
-
#
|
152
161
|
def signed_request_contains_access_token?
|
153
|
-
signed_request &&
|
154
|
-
signed_request['oauth_token']
|
162
|
+
signed_request && signed_request['oauth_token']
|
155
163
|
end
|
156
164
|
|
157
|
-
##
|
158
165
|
# Picks the authorization code in order, from:
|
159
166
|
#
|
160
|
-
# 1.
|
161
|
-
# 2.
|
162
|
-
#
|
167
|
+
# 1. The request 'code' param (manual callback from standard server-side flow)
|
168
|
+
# 2. A signed request (see #signed_request for more)
|
163
169
|
def with_authorization_code!
|
164
170
|
if request.params.key?('code')
|
165
171
|
yield
|
@@ -186,12 +192,13 @@ module OmniAuth
|
|
186
192
|
|
187
193
|
def parse_signed_request(value)
|
188
194
|
signature, encoded_payload = value.split('.')
|
195
|
+
return if signature.nil?
|
189
196
|
|
190
197
|
decoded_hex_signature = base64_decode_url(signature)
|
191
198
|
decoded_payload = MultiJson.decode(base64_decode_url(encoded_payload))
|
192
199
|
|
193
200
|
unless decoded_payload['algorithm'] == 'HMAC-SHA256'
|
194
|
-
raise
|
201
|
+
raise UnknownSignatureAlgorithmError, "unknown algorithm: #{decoded_payload['algorithm']}"
|
195
202
|
end
|
196
203
|
|
197
204
|
if valid_signature?(client.secret, decoded_hex_signature, encoded_payload)
|
@@ -207,6 +214,24 @@ module OmniAuth
|
|
207
214
|
value += '=' * (4 - value.size.modulo(4))
|
208
215
|
Base64.decode64(value.tr('-_', '+/'))
|
209
216
|
end
|
217
|
+
|
218
|
+
def image_url(uid, options)
|
219
|
+
uri_class = options[:secure_image_url] ? URI::HTTPS : URI::HTTP
|
220
|
+
url = uri_class.build({:host => 'graph.facebook.com', :path => "/#{uid}/picture"})
|
221
|
+
|
222
|
+
query = if options[:image_size].is_a?(String)
|
223
|
+
{ :type => options[:image_size] }
|
224
|
+
elsif options[:image_size].is_a?(Hash)
|
225
|
+
options[:image_size]
|
226
|
+
end
|
227
|
+
url.query = Rack::Utils.build_query(query) if query
|
228
|
+
|
229
|
+
url.to_s
|
230
|
+
end
|
231
|
+
|
232
|
+
def appsecret_proof
|
233
|
+
@appsecret_proof ||= OpenSSL::HMAC.hexdigest(OpenSSL::Digest::SHA256.new, client.secret, access_token.token)
|
234
|
+
end
|
210
235
|
end
|
211
236
|
end
|
212
237
|
end
|
data/omniauth-facebook.gemspec
CHANGED
@@ -5,17 +5,18 @@ require 'omniauth/facebook/version'
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = 'omniauth-facebook'
|
7
7
|
s.version = OmniAuth::Facebook::VERSION
|
8
|
-
s.authors = ['Mark Dodwell']
|
9
|
-
s.email = ['mark@
|
10
|
-
s.summary = 'Facebook
|
8
|
+
s.authors = ['Mark Dodwell', 'Josef Šimánek']
|
9
|
+
s.email = ['mark@madeofcode.com', 'retro@ballgag.cz']
|
10
|
+
s.summary = 'Facebook OAuth2 Strategy for OmniAuth'
|
11
11
|
s.homepage = 'https://github.com/mkdynamic/omniauth-facebook'
|
12
|
+
s.license = 'MIT'
|
12
13
|
|
13
14
|
s.files = `git ls-files`.split("\n")
|
14
15
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
15
16
|
s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
|
16
17
|
s.require_paths = ['lib']
|
17
18
|
|
18
|
-
s.add_runtime_dependency 'omniauth-oauth2', '~> 1.1
|
19
|
+
s.add_runtime_dependency 'omniauth-oauth2', '~> 1.1'
|
19
20
|
|
20
21
|
s.add_development_dependency 'minitest'
|
21
22
|
s.add_development_dependency 'mocha'
|
data/test/helper.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'bundler/setup'
|
2
2
|
require 'minitest/autorun'
|
3
|
-
require 'mocha'
|
3
|
+
require 'mocha/setup'
|
4
4
|
require 'omniauth/strategies/facebook'
|
5
5
|
|
6
6
|
OmniAuth.config.test_mode = true
|
@@ -25,7 +25,7 @@ module CustomAssertions
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
-
class TestCase <
|
28
|
+
class TestCase < Minitest::Test
|
29
29
|
extend BlockTestHelper
|
30
30
|
include CustomAssertions
|
31
31
|
end
|
@@ -36,6 +36,7 @@ class StrategyTestCase < TestCase
|
|
36
36
|
@request.stubs(:params).returns({})
|
37
37
|
@request.stubs(:cookies).returns({})
|
38
38
|
@request.stubs(:env).returns({})
|
39
|
+
@request.stubs(:ssl?).returns(false)
|
39
40
|
|
40
41
|
@client_id = '123'
|
41
42
|
@client_secret = '53cr3tz'
|
data/test/test.rb
CHANGED
@@ -13,7 +13,7 @@ class ClientTest < StrategyTestCase
|
|
13
13
|
end
|
14
14
|
|
15
15
|
test 'has correct authorize url' do
|
16
|
-
assert_equal '/oauth
|
16
|
+
assert_equal 'https://www.facebook.com/dialog/oauth', strategy.client.options[:authorize_url]
|
17
17
|
end
|
18
18
|
|
19
19
|
test 'has correct token url' do
|
@@ -56,6 +56,12 @@ class AuthorizeParamsTest < StrategyTestCase
|
|
56
56
|
assert_equal 'touch', strategy.authorize_params[:display]
|
57
57
|
end
|
58
58
|
|
59
|
+
test 'includes auth_type parameter from request when present' do
|
60
|
+
@request.stubs(:params).returns({ 'auth_type' => 'reauthenticate' })
|
61
|
+
assert strategy.authorize_params.is_a?(Hash)
|
62
|
+
assert_equal 'reauthenticate', strategy.authorize_params[:auth_type]
|
63
|
+
end
|
64
|
+
|
59
65
|
test 'overrides default scope with parameter passed from request' do
|
60
66
|
@request.stubs(:params).returns({ 'scope' => 'email' })
|
61
67
|
assert strategy.authorize_params.is_a?(Hash)
|
@@ -95,15 +101,28 @@ class InfoTest < StrategyTestCase
|
|
95
101
|
@options = { :secure_image_url => true }
|
96
102
|
raw_info = { 'name' => 'Fred Smith', 'id' => '321' }
|
97
103
|
strategy.stubs(:raw_info).returns(raw_info)
|
98
|
-
assert_equal 'https://graph.facebook.com/321/picture
|
104
|
+
assert_equal 'https://graph.facebook.com/321/picture', strategy.info['image']
|
99
105
|
end
|
100
106
|
|
101
|
-
test 'returns the image size specified in the `image_size` option' do
|
107
|
+
test 'returns the image with size specified in the `image_size` option' do
|
102
108
|
@options = { :image_size => 'normal' }
|
103
109
|
raw_info = { 'name' => 'Fred Smith', 'id' => '321' }
|
104
110
|
strategy.stubs(:raw_info).returns(raw_info)
|
105
111
|
assert_equal 'http://graph.facebook.com/321/picture?type=normal', strategy.info['image']
|
106
112
|
end
|
113
|
+
|
114
|
+
test 'returns the image with width and height specified in the `image_size` option' do
|
115
|
+
@options = { :image_size => { :width => 123, :height => 987 } }
|
116
|
+
raw_info = { 'name' => 'Fred Smith', 'id' => '321' }
|
117
|
+
strategy.stubs(:raw_info).returns(raw_info)
|
118
|
+
image_url = strategy.info['image']
|
119
|
+
path, query = image_url.split("?")
|
120
|
+
query_params = Hash[*query.split("&").map {|pair| pair.split("=") }.flatten]
|
121
|
+
|
122
|
+
assert_equal 'http://graph.facebook.com/321/picture', path
|
123
|
+
assert_equal '123', query_params['width']
|
124
|
+
assert_equal '987', query_params['height']
|
125
|
+
end
|
107
126
|
end
|
108
127
|
|
109
128
|
class InfoTestOptionalDataPresent < StrategyTestCase
|
@@ -147,9 +166,9 @@ class InfoTestOptionalDataPresent < StrategyTestCase
|
|
147
166
|
assert_equal 'I am great', strategy.info['description']
|
148
167
|
end
|
149
168
|
|
150
|
-
test 'returns the
|
169
|
+
test 'returns the facebook avatar url' do
|
151
170
|
@raw_info['id'] = '321'
|
152
|
-
assert_equal 'http://graph.facebook.com/321/picture
|
171
|
+
assert_equal 'http://graph.facebook.com/321/picture', strategy.info['image']
|
153
172
|
end
|
154
173
|
|
155
174
|
test 'returns the Facebook link as the Facebook url' do
|
@@ -227,31 +246,58 @@ class RawInfoTest < StrategyTestCase
|
|
227
246
|
def setup
|
228
247
|
super
|
229
248
|
@access_token = stub('OAuth2::AccessToken')
|
249
|
+
@appsecret_proof = 'appsecret_proof'
|
250
|
+
@options = {:appsecret_proof => @appsecret_proof}
|
230
251
|
end
|
231
252
|
|
232
253
|
test 'performs a GET to https://graph.facebook.com/me' do
|
254
|
+
strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
|
255
|
+
strategy.stubs(:access_token).returns(@access_token)
|
256
|
+
params = {:params => @options}
|
257
|
+
@access_token.expects(:get).with('/me', params).returns(stub_everything('OAuth2::Response'))
|
258
|
+
strategy.raw_info
|
259
|
+
end
|
260
|
+
|
261
|
+
test 'performs a GET to https://graph.facebook.com/me with locale' do
|
262
|
+
@options.merge!({ :locale => 'cs_CZ' })
|
233
263
|
strategy.stubs(:access_token).returns(@access_token)
|
234
|
-
|
264
|
+
strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
|
265
|
+
params = {:params => @options}
|
266
|
+
@access_token.expects(:get).with('/me', params).returns(stub_everything('OAuth2::Response'))
|
267
|
+
strategy.raw_info
|
268
|
+
end
|
269
|
+
|
270
|
+
test 'performs a GET to https://graph.facebook.com/me with info_fields' do
|
271
|
+
@options.merge!({:info_fields => 'about'})
|
272
|
+
strategy.stubs(:access_token).returns(@access_token)
|
273
|
+
strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
|
274
|
+
params = {:params => {:appsecret_proof => @appsecret_proof, :fields => 'about'}}
|
275
|
+
@access_token.expects(:get).with('/me', params).returns(stub_everything('OAuth2::Response'))
|
235
276
|
strategy.raw_info
|
236
277
|
end
|
237
278
|
|
238
279
|
test 'returns a Hash' do
|
239
280
|
strategy.stubs(:access_token).returns(@access_token)
|
281
|
+
strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
|
240
282
|
raw_response = stub('Faraday::Response')
|
241
283
|
raw_response.stubs(:body).returns('{ "ohai": "thar" }')
|
242
284
|
raw_response.stubs(:status).returns(200)
|
243
285
|
raw_response.stubs(:headers).returns({'Content-Type' => 'application/json' })
|
244
286
|
oauth2_response = OAuth2::Response.new(raw_response)
|
245
|
-
@
|
287
|
+
params = {:params => @options}
|
288
|
+
@access_token.stubs(:get).with('/me', params).returns(oauth2_response)
|
246
289
|
assert_kind_of Hash, strategy.raw_info
|
247
290
|
assert_equal 'thar', strategy.raw_info['ohai']
|
248
291
|
end
|
249
292
|
|
250
293
|
test 'returns an empty hash when the response is false' do
|
251
294
|
strategy.stubs(:access_token).returns(@access_token)
|
295
|
+
strategy.stubs(:appsecret_proof).returns(@appsecret_proof)
|
252
296
|
oauth2_response = stub('OAuth2::Response', :parsed => false)
|
253
|
-
@
|
297
|
+
params = {:params => @options}
|
298
|
+
@access_token.stubs(:get).with('/me', params).returns(oauth2_response)
|
254
299
|
assert_kind_of Hash, strategy.raw_info
|
300
|
+
assert_equal({}, strategy.raw_info)
|
255
301
|
end
|
256
302
|
|
257
303
|
test 'should not include raw_info in extras hash when skip_info is specified' do
|
@@ -354,13 +400,18 @@ module SignedRequestTests
|
|
354
400
|
test 'is nil' do
|
355
401
|
assert_nil strategy.send(:signed_request)
|
356
402
|
end
|
403
|
+
|
404
|
+
test 'throws an error on calling build_access_token' do
|
405
|
+
assert_equal 'must pass either a `code` parameter or a signed request (via `signed_request` parameter or a `fbsr_XXX` cookie)',
|
406
|
+
assert_raises(OmniAuth::Strategies::Facebook::NoAuthorizationCodeError) { strategy.send(:build_access_token) }.message
|
407
|
+
end
|
357
408
|
end
|
358
409
|
|
359
410
|
class CookiePresentTest < TestCase
|
360
|
-
def setup
|
361
|
-
super
|
411
|
+
def setup(algo = nil)
|
412
|
+
super()
|
362
413
|
@payload = {
|
363
|
-
'algorithm' => 'HMAC-SHA256',
|
414
|
+
'algorithm' => algo || 'HMAC-SHA256',
|
364
415
|
'code' => 'm4c0d3z',
|
365
416
|
'issued_at' => Time.now.to_i,
|
366
417
|
'user_id' => '123456'
|
@@ -372,13 +423,18 @@ module SignedRequestTests
|
|
372
423
|
test 'parses the access code out from the cookie' do
|
373
424
|
assert_equal @payload, strategy.send(:signed_request)
|
374
425
|
end
|
426
|
+
|
427
|
+
test 'throws an error if the algorithm is unknown' do
|
428
|
+
setup('UNKNOWN-ALGO')
|
429
|
+
assert_equal "unknown algorithm: UNKNOWN-ALGO", assert_raises(OmniAuth::Strategies::Facebook::UnknownSignatureAlgorithmError) { strategy.send(:signed_request) }.message
|
430
|
+
end
|
375
431
|
end
|
376
432
|
|
377
433
|
class ParamPresentTest < TestCase
|
378
|
-
def setup
|
379
|
-
super
|
434
|
+
def setup(algo = nil)
|
435
|
+
super()
|
380
436
|
@payload = {
|
381
|
-
'algorithm' => 'HMAC-SHA256',
|
437
|
+
'algorithm' => algo || 'HMAC-SHA256',
|
382
438
|
'oauth_token' => 'XXX',
|
383
439
|
'issued_at' => Time.now.to_i,
|
384
440
|
'user_id' => '123456'
|
@@ -390,6 +446,11 @@ module SignedRequestTests
|
|
390
446
|
test 'parses the access code out from the param' do
|
391
447
|
assert_equal @payload, strategy.send(:signed_request)
|
392
448
|
end
|
449
|
+
|
450
|
+
test 'throws an error if the algorithm is unknown' do
|
451
|
+
setup('UNKNOWN-ALGO')
|
452
|
+
assert_equal "unknown algorithm: UNKNOWN-ALGO", assert_raises(OmniAuth::Strategies::Facebook::UnknownSignatureAlgorithmError) { strategy.send(:signed_request) }.message
|
453
|
+
end
|
393
454
|
end
|
394
455
|
|
395
456
|
class CookieAndParamPresentTest < TestCase
|
@@ -414,6 +475,18 @@ module SignedRequestTests
|
|
414
475
|
assert_equal @payload_from_param, strategy.send(:signed_request)
|
415
476
|
end
|
416
477
|
end
|
478
|
+
|
479
|
+
class EmptySignedRequestTest < TestCase
|
480
|
+
def setup
|
481
|
+
super
|
482
|
+
@request.stubs(:params).returns({'signed_request' => ''})
|
483
|
+
end
|
484
|
+
|
485
|
+
test 'empty param' do
|
486
|
+
assert_equal nil, strategy.send(:signed_request)
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
417
490
|
end
|
418
491
|
|
419
492
|
class RequestPhaseWithSignedRequestTest < StrategyTestCase
|
@@ -459,13 +532,13 @@ module BuildAccessTokenTests
|
|
459
532
|
end
|
460
533
|
|
461
534
|
test 'returns a new access token from the signed request' do
|
462
|
-
result = strategy.build_access_token
|
535
|
+
result = strategy.send(:build_access_token)
|
463
536
|
assert_kind_of ::OAuth2::AccessToken, result
|
464
537
|
assert_equal @payload['oauth_token'], result.token
|
465
538
|
end
|
466
539
|
|
467
540
|
test 'returns an access token with the correct expiry time' do
|
468
|
-
result = strategy.build_access_token
|
541
|
+
result = strategy.send(:build_access_token)
|
469
542
|
assert_equal @payload['expires'], result.expires_at
|
470
543
|
end
|
471
544
|
end
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: omniauth-facebook
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.6.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Dodwell
|
8
|
+
- Josef Šimánek
|
8
9
|
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date: 2013-
|
12
|
+
date: 2013-12-03 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: omniauth-oauth2
|
@@ -16,14 +17,14 @@ dependencies:
|
|
16
17
|
requirements:
|
17
18
|
- - ~>
|
18
19
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.1
|
20
|
+
version: '1.1'
|
20
21
|
type: :runtime
|
21
22
|
prerelease: false
|
22
23
|
version_requirements: !ruby/object:Gem::Requirement
|
23
24
|
requirements:
|
24
25
|
- - ~>
|
25
26
|
- !ruby/object:Gem::Version
|
26
|
-
version: 1.1
|
27
|
+
version: '1.1'
|
27
28
|
- !ruby/object:Gem::Dependency
|
28
29
|
name: minitest
|
29
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -68,13 +69,15 @@ dependencies:
|
|
68
69
|
version: '0'
|
69
70
|
description:
|
70
71
|
email:
|
71
|
-
- mark@
|
72
|
+
- mark@madeofcode.com
|
73
|
+
- retro@ballgag.cz
|
72
74
|
executables: []
|
73
75
|
extensions: []
|
74
76
|
extra_rdoc_files: []
|
75
77
|
files:
|
76
78
|
- .gitignore
|
77
79
|
- .travis.yml
|
80
|
+
- CHANGELOG.md
|
78
81
|
- Gemfile
|
79
82
|
- README.md
|
80
83
|
- Rakefile
|
@@ -90,7 +93,8 @@ files:
|
|
90
93
|
- test/support/shared_examples.rb
|
91
94
|
- test/test.rb
|
92
95
|
homepage: https://github.com/mkdynamic/omniauth-facebook
|
93
|
-
licenses:
|
96
|
+
licenses:
|
97
|
+
- MIT
|
94
98
|
metadata: {}
|
95
99
|
post_install_message:
|
96
100
|
rdoc_options: []
|
@@ -103,15 +107,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
103
107
|
version: '0'
|
104
108
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
109
|
requirements:
|
106
|
-
- - '
|
110
|
+
- - '>'
|
107
111
|
- !ruby/object:Gem::Version
|
108
|
-
version:
|
112
|
+
version: 1.3.1
|
109
113
|
requirements: []
|
110
114
|
rubyforge_project:
|
111
|
-
rubygems_version: 2.
|
115
|
+
rubygems_version: 2.1.11
|
112
116
|
signing_key:
|
113
117
|
specification_version: 4
|
114
|
-
summary: Facebook
|
118
|
+
summary: Facebook OAuth2 Strategy for OmniAuth
|
115
119
|
test_files:
|
116
120
|
- test/helper.rb
|
117
121
|
- test/support/shared_examples.rb
|