omniauth-facebook 1.6.0 → 2.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4677ad45ee69e9f54dbeb1e1c8ed9f2bcb2fc700
4
- data.tar.gz: c7a065dc7b1797deb2bcde494497c2cbfb7d0e85
3
+ metadata.gz: 2ebd19468f518b73f27667950e1a9805080526cb
4
+ data.tar.gz: bfc3af66227345e6a8e14add2ec059afa57af1e1
5
5
  SHA512:
6
- metadata.gz: ae45b099fd7c2231ad04cf1047d7644e7f2840c186f9ee0ccc5e993aef791d71a873d314a758cad0c9e19fbd0daee055c38b2245af180ec307e46804f9d11db4
7
- data.tar.gz: 02cc3808e8f7ac24ce2495ad41f98b77e8fc5ce9e5de1884916a34fd737d638865bb49fd18bf4c145390b9aacdd6b166a3c4ce087227be6d365900789133b326
6
+ metadata.gz: 0f6a3d45b85f5a5e6a91f9c6391be42436592fef653a093afc943e6d4952eef5db5239da761f25fff04ed223342e1a848ddd2dbbcc61abc5c9286f765d4160ef
7
+ data.tar.gz: 9e3562e5a443441c142fce21825461f33b8c81e56fb68eda385571fc6c064d476c35a8113957f8f962a1e5846edd0ae54400887f7a0c0584820c4b45fe1d1373
data/.gitignore CHANGED
@@ -6,3 +6,4 @@ pkg/*
6
6
  .powenv
7
7
  tmp
8
8
  bin
9
+ example/app.log
@@ -8,4 +8,9 @@ rvm:
8
8
  - 1.9.2
9
9
  - 1.9.3
10
10
  - 2.0.0
11
+ - 2.1
11
12
  - jruby
13
+ - rbx
14
+ matrix:
15
+ allow_failures:
16
+ - rvm: rbx
@@ -55,9 +55,6 @@ Changes:
55
55
  - have `raw_info` return an empty hash if the Facebook response returns false (#44, @brianjlandau)
56
56
  - prevent oauth2 from interpreting Facebook's expires field as `expires_in`, when it's really `expires_at` (#39, @watsonbox)
57
57
  - remove deprecated `offline_access` permission (@mkdynamic)
58
-
59
- Changes:
60
-
61
58
  - tidy up the `callback_url` option (@mkdynamic)
62
59
 
63
60
  ## 1.2.0 (2012-01-06)
data/Gemfile CHANGED
@@ -2,4 +2,6 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'jruby-openssl', :platform => :jruby
5
+ platforms :rbx do
6
+ gem 'rubysl', '~> 2.0'
7
+ end
data/README.md CHANGED
@@ -1,10 +1,12 @@
1
- **NOTE: If you're running < 1.5.1, please upgrade to address 2 security vulnerabilities.
1
+ **IMPORTANT: If you're running < 1.5.1, please upgrade to address 2 security vulnerabilities.
2
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).**
3
3
 
4
4
  ---
5
5
 
6
6
  # OmniAuth Facebook &nbsp;[![Build Status](https://secure.travis-ci.org/mkdynamic/omniauth-facebook.png?branch=master)](https://travis-ci.org/mkdynamic/omniauth-facebook)
7
7
 
8
+ **These notes are based on master, please see tags for README pertaining to specific releases.**
9
+
8
10
  Facebook OAuth2 Strategy for OmniAuth.
9
11
 
10
12
  Supports the OAuth 2.0 server-side and client-side flows. Read the Facebook docs for more details: http://developers.facebook.com/docs/authentication
@@ -37,14 +39,16 @@ end
37
39
 
38
40
  You can configure several options, which you pass in to the `provider` method via a `Hash`:
39
41
 
40
- * `scope`: A comma-separated list of permissions you want to request from the user. See the Facebook docs for a full list of available permissions: http://developers.facebook.com/docs/reference/api/permissions. Default: `email`
41
- * `display`: 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/. Default: `page`
42
- * `auth_type`: Optionally specifies the requested authentication features as a comma-separated list, as per https://developers.facebook.com/docs/authentication/reauthentication/.
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`.
44
- * `secure_image_url`: Set to `true` to use https for the avatar image url returned in the auth hash. Default is `false`.
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/.
42
+ Option name | Default | Explanation
43
+ --- | --- | ---
44
+ `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/
45
+ `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/
46
+ `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.
47
+ `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).
48
+ `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/.
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). Default is `nil`.
50
+ `secure_image_url` | `false` | Set to `true` to use https for the avatar image url returned in the auth hash.
51
+ `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).
48
52
 
49
53
  For example, to request `email`, `user_birthday` and `read_stream` permissions and display the authentication page in a popup window:
50
54
 
@@ -59,10 +63,6 @@ end
59
63
 
60
64
  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`.
61
65
 
62
- ### Custom Callback URL/Path
63
-
64
- You can set a custom `callback_url` or `callback_path` option to override the default value. See [OmniAuth::Strategy#callback_url](https://github.com/intridea/omniauth/blob/master/lib/omniauth/strategy.rb#L411) for more details on the default.
65
-
66
66
  ## Auth Hash
67
67
 
68
68
  Here's an example *Auth Hash* available in `request.env['omniauth.auth']`:
@@ -109,13 +109,13 @@ Here's an example *Auth Hash* available in `request.env['omniauth.auth']`:
109
109
 
110
110
  The precise information available may depend on the permissions which you request.
111
111
 
112
- ## Client-side Flow
112
+ ## Client-side Flow with Facebook Javascript SDK
113
113
 
114
114
  You can use the Facebook Javascript SDK with `FB.login`, and just hit the callback endpoint (`/auth/facebook/callback` by default) once the user has authenticated in the success callback.
115
115
 
116
- Note that you must enable cookies in the `FB.init` config for this process to work.
116
+ **Note that you must enable cookies in the `FB.init` config for this process to work.**
117
117
 
118
- See the example Sinatra app under `example/` and read the [Facebook docs on Client-Side Authentication](https://developers.facebook.com/docs/authentication/client-side/) for more details.
118
+ See the example Sinatra app under `example/` and read the [Facebook docs on Login for JavaScript](https://developers.facebook.com/docs/facebook-login/login-flow-for-web/) for more details.
119
119
 
120
120
  ### How it Works
121
121
 
@@ -127,53 +127,31 @@ When you call `/auth/facebook/callback` in the success callback of `FB.login` th
127
127
  2. extract the authorization code contained in it
128
128
  3. and hit Facebook and obtain an access token which will get placed in the `request.env['omniauth.auth']['credentials']` hash.
129
129
 
130
- Note that this access token will be the same token obtained and available in the client through the hash [as detailed in the Facebook docs](https://developers.facebook.com/docs/authentication/client-side/).
131
-
132
- ## Canvas Apps
133
-
134
- Canvas apps will send a signed request with the initial POST, therefore you *can* (if it makes sense for your app) pass this to the authorize endpoint (`/auth/facebook` by default) in the querystring.
135
-
136
- There are then 2 scenarios for what happens next:
137
-
138
- 1. A user has already granted access to your app, this will contain an access token. In this case, omniauth-facebook will skip asking the user for authentication and immediately redirect to the callback endpoint (`/auth/facebook/callback` by default) with the access token present in the `request.env['omniauth.auth']['credentials']` hash.
139
-
140
- 2. A user has not granted access to your app, and the signed request *will not* contain an access token. In this case omniauth-facebook will simply follow the standard auth flow.
141
-
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).
143
-
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.
145
-
146
130
  ## Token Expiry
147
131
 
148
- Since Facebook deprecated the `offline_access` permission, this has become more complex. The expiration time of the access token you obtain will depend on which flow you are using. See below for more details.
132
+ The expiration time of the access token you obtain will depend on which flow you are using.
149
133
 
150
134
  ### Client-Side Flow
151
135
 
152
136
  If you use the client-side flow, Facebook will give you back a short lived access token (~ 2 hours).
153
137
 
154
- You can exchange this short lived access token for a longer lived version. Read the [Facebook docs about the offline_access deprecation](https://developers.facebook.com/roadmap/offline-access-removal/) for more information.
138
+ You can exchange this short lived access token for a longer lived version. Read the [Facebook docs](https://developers.facebook.com/docs/facebook-login/access-tokens/) for more information on exchanging a short lived token for a long lived token.
155
139
 
156
140
  ### Server-Side Flow
157
141
 
158
142
  If you use the server-side flow, Facebook will give you back a longer lived access token (~ 60 days).
159
143
 
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.
161
-
162
144
  ## Supported Rubies
163
145
 
164
146
  Actively tested with the following Ruby versions:
165
147
 
148
+ - MRI 2.1.0
166
149
  - MRI 2.0.0
167
150
  - MRI 1.9.3
168
151
  - MRI 1.9.2
169
152
  - MRI 1.8.7
170
- - JRuby 1.7.4
171
-
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:
173
-
174
- ```ruby
175
- gem 'jruby-openssl', :platform => :jruby
176
- ```
153
+ - JRuby 1.7.9
154
+ - Rubinius (latest stable)
177
155
 
178
156
  ## License
179
157
 
@@ -184,3 +162,7 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
184
162
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
185
163
 
186
164
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
165
+
166
+
167
+ [![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/mkdynamic/omniauth-facebook/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
168
+
@@ -1,4 +1,5 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem 'sinatra'
4
+ gem 'sinatra-reloader'
4
5
  gem 'omniauth-facebook', :path => '../'
@@ -1,39 +1,53 @@
1
1
  PATH
2
2
  remote: ../
3
3
  specs:
4
- omniauth-facebook (1.6.0.rc1)
4
+ omniauth-facebook (1.6.0)
5
5
  omniauth-oauth2 (~> 1.1)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- faraday (0.8.8)
11
- multipart-post (~> 1.2.0)
10
+ backports (3.3.5)
11
+ faraday (0.9.0)
12
+ multipart-post (>= 1.2, < 3)
12
13
  hashie (2.0.5)
13
- httpauth (0.2.0)
14
- jwt (0.1.8)
14
+ jwt (0.1.11)
15
15
  multi_json (>= 1.5)
16
16
  multi_json (1.8.2)
17
- multipart-post (1.2.0)
18
- oauth2 (0.8.1)
19
- faraday (~> 0.8)
20
- httpauth (~> 0.1)
21
- jwt (~> 0.1.4)
22
- multi_json (~> 1.0)
17
+ multi_xml (0.5.5)
18
+ multipart-post (2.0.0)
19
+ oauth2 (0.9.3)
20
+ faraday (>= 0.8, < 0.10)
21
+ jwt (~> 0.1.8)
22
+ multi_json (~> 1.3)
23
+ multi_xml (~> 0.5)
23
24
  rack (~> 1.2)
24
- omniauth (1.1.4)
25
+ omniauth (1.2.1)
25
26
  hashie (>= 1.2, < 3)
26
- rack
27
- omniauth-oauth2 (1.1.1)
28
- oauth2 (~> 0.8.0)
29
- omniauth (~> 1.0)
27
+ rack (~> 1.0)
28
+ omniauth-oauth2 (1.1.2)
29
+ faraday (>= 0.8, < 0.10)
30
+ multi_json (~> 1.3)
31
+ oauth2 (~> 0.9.3)
32
+ omniauth (~> 1.2)
30
33
  rack (1.5.2)
31
34
  rack-protection (1.5.1)
32
35
  rack
36
+ rack-test (0.6.2)
37
+ rack (>= 1.0)
33
38
  sinatra (1.4.4)
34
39
  rack (~> 1.4)
35
40
  rack-protection (~> 1.4)
36
41
  tilt (~> 1.3, >= 1.3.4)
42
+ sinatra-contrib (1.4.2)
43
+ backports (>= 2.0)
44
+ multi_json
45
+ rack-protection
46
+ rack-test
47
+ sinatra (~> 1.4.0)
48
+ tilt (~> 1.3)
49
+ sinatra-reloader (1.0)
50
+ sinatra-contrib
37
51
  tilt (1.4.1)
38
52
 
39
53
  PLATFORMS
@@ -42,3 +56,4 @@ PLATFORMS
42
56
  DEPENDENCIES
43
57
  omniauth-facebook!
44
58
  sinatra
59
+ sinatra-reloader
@@ -0,0 +1,93 @@
1
+ require 'sinatra'
2
+ require "sinatra/reloader"
3
+ require 'yaml'
4
+
5
+ # configure sinatra
6
+ set :run, false
7
+ set :raise_errors, true
8
+
9
+ # setup logging to file
10
+ log = File.new("app.log", "a+")
11
+ $stdout.reopen(log)
12
+ $stderr.reopen(log)
13
+ $stderr.sync = true
14
+ $stdout.sync = true
15
+
16
+ # server-side flow
17
+ get '/server-side' do
18
+ # NOTE: You would just hit this endpoint directly from the browser in a real app. The redirect is just here to
19
+ # explicit declare this server-side flow.
20
+ redirect '/auth/facebook'
21
+ end
22
+
23
+ # client-side flow
24
+ get '/client-side' do
25
+ content_type 'text/html'
26
+ # NOTE: When you enable cookie below in the FB.init call the GET request in the FB.login callback will send a signed
27
+ # request in a cookie back the OmniAuth callback which will parse out the authorization code and obtain an
28
+ # access_token with it.
29
+ <<-END
30
+ <html>
31
+ <head>
32
+ <title>Client-side Flow Example</title>
33
+ <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js" type="text/javascript"></script>
34
+ </head>
35
+ <body>
36
+ <div id="fb-root"></div>
37
+
38
+ <script type="text/javascript">
39
+ window.fbAsyncInit = function() {
40
+ FB.init({
41
+ appId : '#{ENV['APP_ID']}',
42
+ status : true, // check login status
43
+ cookie : true, // enable cookies to allow the server to access the session
44
+ xfbml : true // parse XFBML
45
+ });
46
+ };
47
+
48
+ (function(d) {
49
+ var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
50
+ js = d.createElement('script'); js.id = id; js.async = true;
51
+ js.src = "//connect.facebook.net/en_US/all.js";
52
+ d.getElementsByTagName('head')[0].appendChild(js);
53
+ }(document));
54
+
55
+ $(function() {
56
+ $('a').click(function(e) {
57
+ e.preventDefault();
58
+
59
+ FB.login(function(response) {
60
+ if (response.authResponse) {
61
+ $('#connect').html('Connected! Hitting OmniAuth callback (GET /auth/facebook/callback)...');
62
+
63
+ // since we have cookies enabled, this request will allow omniauth to parse
64
+ // out the auth code from the signed request in the fbsr_XXX cookie
65
+ $.getJSON('/auth/facebook/callback', function(json) {
66
+ $('#connect').html('Connected! Callback complete.');
67
+ $('#results').html(JSON.stringify(json));
68
+ });
69
+ }
70
+ }, { scope: 'email,read_stream', state: 'abc123' });
71
+ });
72
+ });
73
+ </script>
74
+
75
+ <p id="connect">
76
+ <a href="#">Connect to FB!</a>
77
+ </p>
78
+
79
+ <p id="results" />
80
+ </body>
81
+ </html>
82
+ END
83
+ end
84
+
85
+ get '/auth/:provider/callback' do
86
+ content_type 'application/json'
87
+ MultiJson.encode(request.env)
88
+ end
89
+
90
+ get '/auth/failure' do
91
+ content_type 'application/json'
92
+ MultiJson.encode(request.env)
93
+ end
@@ -1,110 +1,11 @@
1
1
  require 'bundler/setup'
2
- require 'sinatra/base'
3
2
  require 'omniauth-facebook'
3
+ require './app.rb'
4
4
 
5
- SCOPE = 'email,read_stream'
6
-
7
- class App < Sinatra::Base
8
- # turn off sinatra default X-Frame-Options for FB canvas
9
- set :protection, :except => :frame_options
10
-
11
- # server-side flow
12
- get '/' do
13
- # NOTE: you would just hit this endpoint directly from the browser
14
- # in a real app. the redirect is just here to setup the root
15
- # path in this example sinatra app.
16
- redirect '/auth/facebook'
17
- end
18
-
19
- # client-side flow
20
- get '/client-side' do
21
- content_type 'text/html'
22
- # NOTE: when you enable cookie below in the FB.init call
23
- # the GET request in the FB.login callback will send
24
- # a signed request in a cookie back the OmniAuth callback
25
- # which will parse out the authorization code and obtain
26
- # the access_token. This will be the exact same access_token
27
- # returned to the client in response.authResponse.accessToken.
28
- <<-END
29
- <html>
30
- <head>
31
- <title>Client-side Flow Example</title>
32
- <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.0/jquery.min.js" type="text/javascript"></script>
33
- </head>
34
- <body>
35
- <div id="fb-root"></div>
36
-
37
- <script type="text/javascript">
38
- window.fbAsyncInit = function() {
39
- FB.init({
40
- appId : '#{ENV['APP_ID']}',
41
- status : true, // check login status
42
- cookie : true, // enable cookies to allow the server to access the session
43
- xfbml : true // parse XFBML
44
- });
45
- };
46
-
47
- (function(d) {
48
- var js, id = 'facebook-jssdk'; if (d.getElementById(id)) {return;}
49
- js = d.createElement('script'); js.id = id; js.async = true;
50
- js.src = "//connect.facebook.net/en_US/all.js";
51
- d.getElementsByTagName('head')[0].appendChild(js);
52
- }(document));
53
-
54
- $(function() {
55
- $('a').click(function(e) {
56
- e.preventDefault();
57
-
58
- FB.login(function(response) {
59
- if (response.authResponse) {
60
- $('#connect').html('Connected! Hitting OmniAuth callback (GET /auth/facebook/callback)...');
61
-
62
- // since we have cookies enabled, this request will allow omniauth to parse
63
- // out the auth code from the signed request in the fbsr_XXX cookie
64
- $.getJSON('/auth/facebook/callback', function(json) {
65
- $('#connect').html('Connected! Callback complete.');
66
- $('#results').html(JSON.stringify(json));
67
- });
68
- }
69
- }, { scope: '#{SCOPE}' });
70
- });
71
- });
72
- </script>
73
-
74
- <p id="connect">
75
- <a href="#">Connect to FB</a>
76
- </p>
77
-
78
- <p id="results" />
79
- </body>
80
- </html>
81
- END
82
- end
83
-
84
- # auth via FB canvas and signed request param
85
- post '/canvas/' do
86
- # we just redirect to /auth/facebook here which will parse the
87
- # signed_request FB sends us, asking for auth if the user has
88
- # not already granted access, or simply moving straight to the
89
- # callback where they have already granted access.
90
- redirect "/auth/facebook?signed_request=#{request.params['signed_request']}"
91
- end
92
-
93
- get '/auth/:provider/callback' do
94
- content_type 'application/json'
95
- MultiJson.encode(request.env)
96
- end
97
-
98
- get '/auth/failure' do
99
- content_type 'application/json'
100
- MultiJson.encode(request.env)
101
- end
102
- end
103
-
104
- use Rack::Session::Cookie
5
+ use Rack::Session::Cookie, :secret => 'abc123'
105
6
 
106
7
  use OmniAuth::Builder do
107
- provider :facebook, ENV['APP_ID'], ENV['APP_SECRET'], :scope => SCOPE
8
+ provider :facebook, ENV['APP_ID'], ENV['APP_SECRET'], :scope => 'email,read_stream'
108
9
  end
109
10
 
110
- run App.new
11
+ run Sinatra::Application
@@ -1,5 +1,5 @@
1
1
  module OmniAuth
2
2
  module Facebook
3
- VERSION = "1.6.0"
3
+ VERSION = "2.0.0.pre1"
4
4
  end
5
5
  end
@@ -68,35 +68,20 @@ module OmniAuth
68
68
  end
69
69
 
70
70
  def callback_phase
71
- super
71
+ with_authorization_code! do
72
+ super
73
+ end
72
74
  rescue NoAuthorizationCodeError => e
73
75
  fail!(:no_authorization_code, e)
74
76
  rescue UnknownSignatureAlgorithmError => e
75
77
  fail!(:unknown_signature_algoruthm, e)
76
78
  end
77
79
 
78
- def request_phase
79
- if signed_request_contains_access_token?
80
- # If we already have an access token, we can just hit the callback URL directly and pass the signed request.
81
- params = { :signed_request => raw_signed_request }
82
- query = Rack::Utils.build_query(params)
83
-
84
- url = callback_url
85
- url << "?" unless url.match(/\?/)
86
- url << "&" unless url.match(/[\&\?]$/)
87
- url << query
88
-
89
- redirect url
90
- else
91
- super
92
- end
93
- end
94
-
95
80
  # NOTE If we're using code from the signed request then FB sets the redirect_uri to '' during the authorize
96
81
  # phase and it must match during the access_token phase:
97
- # https://github.com/facebook/php-sdk/blob/master/src/base_facebook.php#L348
82
+ # https://github.com/facebook/facebook-php-sdk/blob/master/src/base_facebook.php#L477
98
83
  def callback_url
99
- if @authorization_code_from_signed_request
84
+ if @authorization_code_from_signed_request_in_cookie
100
85
  ''
101
86
  else
102
87
  options[:callback_url] || super
@@ -110,7 +95,7 @@ module OmniAuth
110
95
  # You can pass +display+, +scope+, or +auth_type+ params to the auth request, if you need to set them dynamically.
111
96
  # You can also set these options in the OmniAuth config :authorize_params option.
112
97
  #
113
- # /auth/facebook?display=popup
98
+ # For example: /auth/facebook?display=popup
114
99
  def authorize_params
115
100
  super.tap do |params|
116
101
  %w[display scope auth_type].each do |v|
@@ -123,63 +108,47 @@ module OmniAuth
123
108
  end
124
109
  end
125
110
 
126
- # Parse signed request in order, from:
127
- #
128
- # 1. The request 'signed_request' param (server-side flow from canvas pages) or
129
- # 2. A cookie (client-side flow via JS SDK)
130
- def signed_request
131
- @signed_request ||= raw_signed_request && parse_signed_request(raw_signed_request)
132
- end
133
-
134
111
  protected
135
112
 
136
113
  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
114
+ super.tap do |token|
115
+ token.options.merge!(access_token_options)
148
116
  end
149
117
  end
150
118
 
151
119
  private
152
120
 
153
- def raw_signed_request
154
- request.params['signed_request'] || request.cookies["fbsr_#{client.id}"]
121
+ def signed_request_from_cookie
122
+ @signed_request_from_cookie ||= raw_signed_request_from_cookie && parse_signed_request(raw_signed_request_from_cookie)
155
123
  end
156
124
 
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.
159
- #
160
- # https://developers.facebook.com/docs/authentication/canvas/
161
- def signed_request_contains_access_token?
162
- signed_request && signed_request['oauth_token']
125
+ def raw_signed_request_from_cookie
126
+ request.cookies["fbsr_#{client.id}"]
163
127
  end
164
128
 
165
129
  # Picks the authorization code in order, from:
166
130
  #
167
131
  # 1. The request 'code' param (manual callback from standard server-side flow)
168
- # 2. A signed request (see #signed_request for more)
132
+ # 2. A signed request from cookie (passed from the client during the client-side flow)
169
133
  def with_authorization_code!
170
134
  if request.params.key?('code')
171
135
  yield
172
- elsif code_from_signed_request = signed_request && signed_request['code']
136
+ elsif code_from_signed_request = signed_request_from_cookie && signed_request_from_cookie['code']
173
137
  request.params['code'] = code_from_signed_request
174
- @authorization_code_from_signed_request = true
138
+ @authorization_code_from_signed_request_in_cookie = true
139
+ # NOTE The code from the signed fbsr_XXX cookie is set by the FB JS SDK will confirm that the identity of the
140
+ # user contained in the signed request matches the user loading the app.
141
+ original_provider_ignores_state = options.provider_ignores_state
142
+ options.provider_ignores_state = true
175
143
  begin
176
144
  yield
177
145
  ensure
178
146
  request.params.delete('code')
179
- @authorization_code_from_signed_request = false
147
+ @authorization_code_from_signed_request_in_cookie = false
148
+ options.provider_ignores_state = original_provider_ignores_state
180
149
  end
181
150
  else
182
- raise NoAuthorizationCodeError, 'must pass either a `code` parameter or a signed request (via `signed_request` parameter or a `fbsr_XXX` cookie)'
151
+ raise NoAuthorizationCodeError, 'must pass either a `code` (via URL or by an `fbsr_XXX` signed request cookie)'
183
152
  end
184
153
  end
185
154
 
@@ -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(:scheme).returns({})
39
40
  @request.stubs(:ssl?).returns(false)
40
41
 
41
42
  @client_id = '123'
@@ -115,13 +115,9 @@ class InfoTest < StrategyTestCase
115
115
  @options = { :image_size => { :width => 123, :height => 987 } }
116
116
  raw_info = { 'name' => 'Fred Smith', 'id' => '321' }
117
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']
118
+ assert_match 'width=123', strategy.info['image']
119
+ assert_match 'height=987', strategy.info['image']
120
+ assert_match 'http://graph.facebook.com/321/picture?', strategy.info['image']
125
121
  end
126
122
  end
127
123
 
@@ -398,12 +394,11 @@ module SignedRequestTests
398
394
 
399
395
  class CookieAndParamNotPresentTest < TestCase
400
396
  test 'is nil' do
401
- assert_nil strategy.send(:signed_request)
397
+ assert_nil strategy.send(:signed_request_from_cookie)
402
398
  end
403
399
 
404
400
  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
401
+ assert_raises(OmniAuth::Strategies::Facebook::NoAuthorizationCodeError) { strategy.send(:with_authorization_code!) {} }
407
402
  end
408
403
  end
409
404
 
@@ -421,125 +416,54 @@ module SignedRequestTests
421
416
  end
422
417
 
423
418
  test 'parses the access code out from the cookie' do
424
- assert_equal @payload, strategy.send(:signed_request)
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
431
- end
432
-
433
- class ParamPresentTest < TestCase
434
- def setup(algo = nil)
435
- super()
436
- @payload = {
437
- 'algorithm' => algo || 'HMAC-SHA256',
438
- 'oauth_token' => 'XXX',
439
- 'issued_at' => Time.now.to_i,
440
- 'user_id' => '123456'
441
- }
442
-
443
- @request.stubs(:params).returns({'signed_request' => signed_request(@payload, @client_secret)})
444
- end
445
-
446
- test 'parses the access code out from the param' do
447
- assert_equal @payload, strategy.send(:signed_request)
419
+ assert_equal @payload, strategy.send(:signed_request_from_cookie)
448
420
  end
449
421
 
450
422
  test 'throws an error if the algorithm is unknown' do
451
423
  setup('UNKNOWN-ALGO')
452
- assert_equal "unknown algorithm: UNKNOWN-ALGO", assert_raises(OmniAuth::Strategies::Facebook::UnknownSignatureAlgorithmError) { strategy.send(:signed_request) }.message
424
+ assert_equal "unknown algorithm: UNKNOWN-ALGO", assert_raises(OmniAuth::Strategies::Facebook::UnknownSignatureAlgorithmError) { strategy.send(:signed_request_from_cookie) }.message
453
425
  end
454
426
  end
455
427
 
456
- class CookieAndParamPresentTest < TestCase
428
+ class EmptySignedRequestTest < TestCase
457
429
  def setup
458
430
  super
459
- @payload_from_cookie = {
460
- 'algorithm' => 'HMAC-SHA256',
461
- 'from' => 'cookie'
462
- }
463
-
464
- @request.stubs(:cookies).returns({"fbsr_#{@client_id}" => signed_request(@payload_from_cookie, @client_secret)})
465
-
466
- @payload_from_param = {
467
- 'algorithm' => 'HMAC-SHA256',
468
- 'from' => 'param'
469
- }
470
-
471
- @request.stubs(:params).returns({'signed_request' => signed_request(@payload_from_param, @client_secret)})
431
+ @request.stubs(:params).returns({'signed_request' => ''})
472
432
  end
473
433
 
474
- test 'picks param over cookie' do
475
- assert_equal @payload_from_param, strategy.send(:signed_request)
434
+ test 'empty param' do
435
+ assert_equal nil, strategy.send(:signed_request_from_cookie)
476
436
  end
477
437
  end
478
438
 
479
- class EmptySignedRequestTest < TestCase
439
+ class MissingCodeInParamsRequestTest < TestCase
480
440
  def setup
481
441
  super
482
- @request.stubs(:params).returns({'signed_request' => ''})
442
+ @request.stubs(:params).returns({})
483
443
  end
484
444
 
485
- test 'empty param' do
486
- assert_equal nil, strategy.send(:signed_request)
445
+ test 'calls fail! when a code is not included in the params' do
446
+ strategy.expects(:fail!).times(1).with(:no_authorization_code, kind_of(Exception))
447
+ strategy.callback_phase
487
448
  end
488
449
  end
489
450
 
490
- end
491
-
492
- class RequestPhaseWithSignedRequestTest < StrategyTestCase
493
- include SignedRequestHelpers
494
-
495
- def setup
496
- super
497
-
498
- payload = {
499
- 'algorithm' => 'HMAC-SHA256',
500
- 'oauth_token' => 'm4c0d3z'
501
- }
502
- @raw_signed_request = signed_request(payload, @client_secret)
503
- @request.stubs(:params).returns("signed_request" => @raw_signed_request)
504
-
505
- strategy.stubs(:callback_url).returns('/')
506
- end
507
-
508
- test 'redirects to callback passing along signed request' do
509
- strategy.expects(:redirect).with("/?signed_request=#{Rack::Utils.escape(@raw_signed_request)}").once
510
- strategy.request_phase
511
- end
512
- end
513
-
514
- module BuildAccessTokenTests
515
- class TestCase < StrategyTestCase
516
- include SignedRequestHelpers
517
- end
518
-
519
- class ParamsContainSignedRequestWithAccessTokenTest < TestCase
520
- def setup
521
- super
522
-
451
+ class MissingCodeInCookieRequestTest < TestCase
452
+ def setup(algo = nil)
453
+ super()
523
454
  @payload = {
524
- 'algorithm' => 'HMAC-SHA256',
525
- 'oauth_token' => 'm4c0d3z',
526
- 'expires' => Time.now.to_i
455
+ 'algorithm' => algo || 'HMAC-SHA256',
456
+ 'code' => nil,
457
+ 'issued_at' => Time.now.to_i,
458
+ 'user_id' => '123456'
527
459
  }
528
- @raw_signed_request = signed_request(@payload, @client_secret)
529
- @request.stubs(:params).returns({"signed_request" => @raw_signed_request})
530
460
 
531
- strategy.stubs(:callback_url).returns('/')
532
- end
533
-
534
- test 'returns a new access token from the signed request' do
535
- result = strategy.send(:build_access_token)
536
- assert_kind_of ::OAuth2::AccessToken, result
537
- assert_equal @payload['oauth_token'], result.token
461
+ @request.stubs(:cookies).returns({"fbsr_#{@client_id}" => signed_request(@payload, @client_secret)})
538
462
  end
539
463
 
540
- test 'returns an access token with the correct expiry time' do
541
- result = strategy.send(:build_access_token)
542
- assert_equal @payload['expires'], result.expires_at
464
+ test 'calls fail! when a code is not included in the cookie' do
465
+ strategy.expects(:fail!).times(1).with(:no_authorization_code, kind_of(Exception))
466
+ strategy.callback_phase
543
467
  end
544
468
  end
545
469
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: omniauth-facebook
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.0
4
+ version: 2.0.0.pre1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Dodwell
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-01-11 00:00:00.000000000 Z
12
+ date: 2014-05-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: omniauth-oauth2
@@ -83,6 +83,7 @@ files:
83
83
  - Rakefile
84
84
  - example/Gemfile
85
85
  - example/Gemfile.lock
86
+ - example/app.rb
86
87
  - example/config.ru
87
88
  - lib/omniauth-facebook.rb
88
89
  - lib/omniauth/facebook.rb
@@ -107,12 +108,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
107
108
  version: '0'
108
109
  required_rubygems_version: !ruby/object:Gem::Requirement
109
110
  requirements:
110
- - - '>='
111
+ - - '>'
111
112
  - !ruby/object:Gem::Version
112
- version: '0'
113
+ version: 1.3.1
113
114
  requirements: []
114
115
  rubyforge_project:
115
- rubygems_version: 2.0.2
116
+ rubygems_version: 2.2.2
116
117
  signing_key:
117
118
  specification_version: 4
118
119
  summary: Facebook OAuth2 Strategy for OmniAuth