omniauth-facebook 1.5.1 → 1.6.0.rc1
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 +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 [](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
|