oauth-plugin 0.4.0.rc1 → 0.4.0.rc2

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.
data/CHANGELOG CHANGED
@@ -1,3 +1,6 @@
1
+ 0.4.0-rc2
2
+ - Better OAuth2 support.
3
+ - Refactored authorizer into a Authorizer object which is now better tested
1
4
  0.4.0-rc1
2
5
  PLEASE help test this so we can mark it as final
3
6
  - Update to OAuth2 draft 22 which is likely the final release. [pelle] ACTION REQUIRED BY YOU, see README.
@@ -1,5 +1,5 @@
1
1
  module Oauth
2
2
  module Plugin
3
- VERSION = "0.4.0.rc1"
3
+ VERSION = "0.4.0.rc2"
4
4
  end
5
5
  end
@@ -1,3 +1,4 @@
1
+ require 'oauth/provider/authorizer'
1
2
  module OAuth
2
3
  module Controllers
3
4
 
@@ -9,7 +10,7 @@ module OAuth
9
10
  oauthenticate :strategies => :token, :interactive => false, :only => [:invalidate,:capabilities]
10
11
  oauthenticate :strategies => :two_legged, :interactive => false, :only => [:request_token]
11
12
  oauthenticate :strategies => :oauth10_request_token, :interactive => false, :only => [:access_token]
12
- skip_before_filter :verify_authenticity_token, :only=>[:request_token, :access_token, :invalidate, :test_request]
13
+ skip_before_filter :verify_authenticity_token, :only=>[:request_token, :access_token, :invalidate, :test_request, :token]
13
14
  end
14
15
  end
15
16
 
@@ -37,7 +38,10 @@ module OAuth
37
38
  oauth2_error "invalid_client"
38
39
  return
39
40
  end
40
- if ["authorization_code","password","none"].include?(params[:grant_type])
41
+ # older drafts used none for client_credentials
42
+ params[:grant_type] = 'client_credentials' if params[:grant_type] == 'none'
43
+ logger.info "grant_type=#{params[:grant_type]}"
44
+ if ["authorization_code", "password", "client_credentials"].include?(params[:grant_type])
41
45
  send "oauth2_token_#{params[:grant_type].underscore}"
42
46
  else
43
47
  oauth2_error "unsupported_grant_type"
@@ -52,10 +56,14 @@ module OAuth
52
56
  if params[:oauth_token]
53
57
  @token = ::RequestToken.find_by_token! params[:oauth_token]
54
58
  oauth1_authorize
55
- elsif ["code","token"].include?(params[:response_type]) # pick flow
56
- send "oauth2_authorize_#{params[:response_type]}"
57
59
  else
58
- render :status=>404, :text=>"No token provided"
60
+ if request.post?
61
+ @authorizer = OAuth::Provider::Authorizer.new current_user, user_authorizes_token?, params
62
+ redirect_to @authorizer.redirect_uri
63
+ else
64
+ @client_application = ClientApplication.find_by_key! params[:client_id]
65
+ render :action => "oauth2_authorize"
66
+ end
59
67
  end
60
68
  end
61
69
 
@@ -121,59 +129,6 @@ module OAuth
121
129
  end
122
130
  end
123
131
 
124
- def oauth2_authorize_code
125
- @client_application = ClientApplication.find_by_key params[:client_id]
126
- # Using ||= allows us to override this and customize the verification_code and call super to handle the rest
127
- @token ||= Oauth2Verifier.new :client_application=>@client_application, :user=>current_user, :callback_url=>@redirect_url.to_s, :scope => params[:scope], :state => params[:state]
128
- if request.post?
129
- @redirect_url = URI.parse(params[:redirect_uri] || @client_application.callback_url) if params[:redirect_uri] || @client_application.callback_url
130
- if user_authorizes_token? && @token.save
131
- unless @redirect_url.to_s.blank?
132
- @redirect_url.query = @redirect_url.query.blank? ? @token.to_query : @redirect_url.query + @token.to_query
133
- redirect_to @redirect_url.to_s
134
- else
135
- render :action => "authorize_success"
136
- end
137
- else
138
- unless @redirect_url.to_s.blank?
139
- @redirect_url.query = @redirect_url.query.blank? ?
140
- "error=user_denied" :
141
- @redirect_url.query + "&error=user_denied"
142
- redirect_to @redirect_url.to_s
143
- else
144
- render :action => "authorize_failure"
145
- end
146
- end
147
- else
148
- render :action => "oauth2_authorize"
149
- end
150
- end
151
-
152
- def oauth2_authorize_token
153
- @client_application = ClientApplication.find_by_key params[:client_id]
154
- @token = Oauth2Token.new :client_application=>@client_application, :user=>current_user, :scope=>params[:scope]
155
- if request.post?
156
- @redirect_url = URI.parse(params[:redirect_uri] || @client_application.callback_url)
157
- if user_authorizes_token? && @token.save
158
- unless @redirect_url.to_s.blank?
159
- redirect_to "#{@redirect_url.to_s}##{@token.to_query}"
160
- else
161
- render :action => "authorize_success"
162
- end
163
- else
164
- unless @redirect_url.to_s.blank?
165
- @redirect_url.query = @redirect_url.query.blank? ?
166
- "error=user_denied" :
167
- @redirect_url.query + "&error=user_denied"
168
- redirect_to @redirect_url.to_s
169
- else
170
- render :action => "authorize_failure"
171
- end
172
- end
173
- else
174
- render :action => "oauth2_authorize"
175
- end
176
- end
177
132
 
178
133
  # http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-4.1.1
179
134
  def oauth2_token_authorization_code
@@ -207,7 +162,7 @@ module OAuth
207
162
  end
208
163
 
209
164
  # autonomous authorization which creates a token for client_applications user
210
- def oauth2_token_none
165
+ def oauth2_token_client_credentials
211
166
  @token = Oauth2Token.create :client_application=>@client_application, :user=>@client_application.user, :scope=>params[:scope]
212
167
  render :json=>@token
213
168
  end
@@ -0,0 +1,83 @@
1
+ require 'uri'
2
+
3
+ module OAuth
4
+ module Provider
5
+ class Authorizer
6
+ attr_accessor :user, :params, :app
7
+
8
+ def initialize(user, authorized, params = {})
9
+ @user = user
10
+ @params = params
11
+ @authorized = authorized
12
+ end
13
+
14
+ def app
15
+ @app ||= ::ClientApplication.find_by_key!(params[:client_id])
16
+ end
17
+
18
+ def code
19
+ @code ||= ::Oauth2Verifier.create! :client_application => app,
20
+ :user => @user,
21
+ :scope => @params[:scope],
22
+ :callback_url => @params[:redirect_uri]
23
+ end
24
+
25
+ def token
26
+ @token ||= ::Oauth2Token.create! :client_application => app,
27
+ :user => @user,
28
+ :scope => @params[:scope],
29
+ :callback_url => @params[:redirect_uri]
30
+ end
31
+
32
+ def authorized?
33
+ @authorized == true
34
+ end
35
+
36
+ def redirect_uri
37
+ uri = base_uri
38
+ if params[:response_type] == 'code'
39
+ if uri.query
40
+ uri.query << '&'
41
+ else
42
+ uri.query = ''
43
+ end
44
+ uri.query << encode_response
45
+ else
46
+ uri.fragment = encode_response
47
+ end
48
+ uri.to_s
49
+ end
50
+
51
+ def response
52
+ r = {}
53
+ if ['token','code'].include? params[:response_type]
54
+ if authorized?
55
+ if params[:response_type] == 'code'
56
+ r[:code] = code.token
57
+ else
58
+ r[:access_token] = token.token
59
+ end
60
+ else
61
+ r[:error] = 'access_denied'
62
+ end
63
+ else
64
+ r[:error] = 'unsupported_response_type'
65
+ end
66
+ r[:state] = params[:state] if params[:state]
67
+ r
68
+ end
69
+
70
+ def encode_response
71
+ response.map do |k, v|
72
+ [URI.escape(k.to_s),URI.escape(v)] * "="
73
+ end * "&"
74
+ end
75
+
76
+ protected
77
+
78
+ def base_uri
79
+ URI.parse(params[:redirect_uri] || app.callback_url)
80
+ end
81
+ end
82
+ end
83
+ end
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
8
8
 
9
9
  s.required_rubygems_version = Gem::Requirement.new("> 1.3.1") if s.respond_to? :required_rubygems_version=
10
10
  s.authors = ["Pelle Braendgaard"]
11
- s.date = %q{2011-06-28}
11
+ s.date = %q{2011-10-20}
12
12
  s.description = %q{Rails plugin for implementing an OAuth Provider or Consumer}
13
13
  s.email = %q{oauth-ruby@googlegroups.com}
14
14
  s.extra_rdoc_files = [
@@ -0,0 +1,53 @@
1
+ # Dummy implementation
2
+ class ClientApplication
3
+ attr_accessor :key
4
+
5
+ def self.find_by_key(key)
6
+ ClientApplication.new(key)
7
+ end
8
+
9
+ def initialize(key)
10
+ @key = key
11
+ end
12
+
13
+ def tokens
14
+ @tokens||=[]
15
+ end
16
+
17
+ def secret
18
+ "secret"
19
+ end
20
+ end
21
+
22
+ class OauthToken
23
+ attr_accessor :token
24
+
25
+ def self.first(conditions_hash)
26
+ case conditions_hash[:conditions].last
27
+ when "not_authorized", "invalidated"
28
+ nil
29
+ else
30
+ OauthToken.new(conditions_hash[:conditions].last)
31
+ end
32
+ end
33
+
34
+ def initialize(token)
35
+ @token = token
36
+ end
37
+
38
+ def secret
39
+ "secret"
40
+ end
41
+ end
42
+
43
+ class Oauth2Token < OauthToken ; end
44
+ class Oauth2Verifier < OauthToken ; end
45
+ class AccessToken < OauthToken ; end
46
+ class RequestToken < OauthToken ; end
47
+
48
+ class OauthNonce
49
+ # Always remember
50
+ def self.remember(nonce,timestamp)
51
+ true
52
+ end
53
+ end
@@ -0,0 +1,202 @@
1
+ require 'spec_helper'
2
+ require 'multi_json'
3
+ require 'oauth/provider/authorizer'
4
+ require 'dummy_provider_models'
5
+
6
+ describe OAuth::Provider::Authorizer do
7
+
8
+
9
+ describe "Authorization code" do
10
+
11
+ describe "should issue code" do
12
+
13
+ before(:each) do
14
+ @user = double("user")
15
+ @app = double("app")
16
+ @code = double("code", :token => "secret auth code")
17
+
18
+ ::ClientApplication.should_receive(:find_by_key!).with('client id').and_return(@app)
19
+ end
20
+
21
+ it "should allow" do
22
+ ::Oauth2Verifier.should_receive(:create!).with( :client_application=>@app,
23
+ :user=>@user,
24
+ :callback_url=>'http://mysite.com/callback',
25
+ :scope => 'a b').and_return(@code)
26
+
27
+ @authorizer = OAuth::Provider::Authorizer.new @user, true, :response_type => 'code',
28
+ :scope => "a b",
29
+ :client_id => 'client id',
30
+ :redirect_uri => 'http://mysite.com/callback'
31
+
32
+ @authorizer.redirect_uri.should == "http://mysite.com/callback?code=secret%20auth%20code"
33
+ @authorizer.should be_authorized
34
+
35
+ end
36
+
37
+ it "should include state" do
38
+ ::Oauth2Verifier.should_receive(:create!).with( :client_application=>@app,
39
+ :user=>@user,
40
+ :callback_url=>'http://mysite.com/callback',
41
+ :scope => 'a b').and_return(@code)
42
+
43
+ @authorizer = OAuth::Provider::Authorizer.new @user, true, :response_type => 'code',
44
+ :state => 'customer id',
45
+ :scope => "a b",
46
+ :client_id => 'client id',
47
+ :redirect_uri => 'http://mysite.com/callback'
48
+
49
+ @authorizer.redirect_uri.should == "http://mysite.com/callback?code=secret%20auth%20code&state=customer%20id"
50
+ @authorizer.should be_authorized
51
+
52
+ end
53
+
54
+ it "should allow query string in callback" do
55
+ ::Oauth2Verifier.should_receive(:create!).with( :client_application=>@app,
56
+ :user=>@user,
57
+ :callback_url=>'http://mysite.com/callback?this=one',
58
+ :scope => 'a b').and_return(@code)
59
+
60
+ @authorizer = OAuth::Provider::Authorizer.new @user, true, :response_type => 'code',
61
+ :scope => "a b",
62
+ :client_id => 'client id',
63
+ :redirect_uri => 'http://mysite.com/callback?this=one'
64
+ @authorizer.should be_authorized
65
+ @authorizer.redirect_uri.should == "http://mysite.com/callback?this=one&code=secret%20auth%20code"
66
+ end
67
+ end
68
+
69
+
70
+ end
71
+
72
+ describe "user does not authorize" do
73
+
74
+ it "should send error" do
75
+ @authorizer = OAuth::Provider::Authorizer.new @user, false, :response_type => 'code',
76
+ :scope => "a b",
77
+ :client_id => 'client id',
78
+ :redirect_uri => 'http://mysite.com/callback'
79
+
80
+ @authorizer.redirect_uri.should == "http://mysite.com/callback?error=access_denied"
81
+ @authorizer.should_not be_authorized
82
+
83
+ end
84
+
85
+ it "should send error with state and query params in callback" do
86
+ @authorizer = OAuth::Provider::Authorizer.new @user, false, :response_type => 'code',
87
+ :scope => "a b",
88
+ :client_id => 'client id',
89
+ :redirect_uri=>'http://mysite.com/callback?this=one',
90
+ :state => "my customer"
91
+
92
+ @authorizer.redirect_uri.should == "http://mysite.com/callback?this=one&error=access_denied&state=my%20customer"
93
+ @authorizer.should_not be_authorized
94
+
95
+ end
96
+
97
+ end
98
+
99
+ describe "Implict Grant" do
100
+
101
+ describe "should issue token" do
102
+
103
+ before(:each) do
104
+ @user = double("user")
105
+ @app = double("app")
106
+ @token = double("token", :token => "secret auth code")
107
+
108
+ ::ClientApplication.should_receive(:find_by_key!).with('client id').and_return(@app)
109
+ end
110
+
111
+ it "should allow" do
112
+ ::Oauth2Token.should_receive(:create!).with( :client_application=>@app,
113
+ :user=>@user,
114
+ :callback_url=>'http://mysite.com/callback',
115
+ :scope => 'a b').and_return(@token)
116
+
117
+ @authorizer = OAuth::Provider::Authorizer.new @user, true, :response_type => 'token',
118
+ :scope => "a b",
119
+ :client_id => 'client id',
120
+ :redirect_uri => 'http://mysite.com/callback'
121
+
122
+ @authorizer.redirect_uri.should == "http://mysite.com/callback#access_token=secret%20auth%20code"
123
+ @authorizer.should be_authorized
124
+
125
+ end
126
+
127
+ it "should include state" do
128
+ ::Oauth2Token.should_receive(:create!).with( :client_application=>@app,
129
+ :user=>@user,
130
+ :callback_url=>'http://mysite.com/callback',
131
+ :scope => 'a b').and_return(@token)
132
+
133
+ @authorizer = OAuth::Provider::Authorizer.new @user, true, :response_type => 'token',
134
+ :state => 'customer id',
135
+ :scope => "a b",
136
+ :client_id => 'client id',
137
+ :redirect_uri => 'http://mysite.com/callback'
138
+
139
+ @authorizer.redirect_uri.should == "http://mysite.com/callback#access_token=secret%20auth%20code&state=customer%20id"
140
+ @authorizer.should be_authorized
141
+
142
+ end
143
+
144
+ it "should allow query string in callback" do
145
+ ::Oauth2Token.should_receive(:create!).with( :client_application=>@app,
146
+ :user=>@user,
147
+ :callback_url=>'http://mysite.com/callback?this=one',
148
+ :scope => 'a b').and_return(@token)
149
+
150
+ @authorizer = OAuth::Provider::Authorizer.new @user, true, :response_type => 'token',
151
+ :scope => "a b",
152
+ :client_id => 'client id',
153
+ :redirect_uri => 'http://mysite.com/callback?this=one'
154
+ @authorizer.should be_authorized
155
+ @authorizer.redirect_uri.should == "http://mysite.com/callback?this=one#access_token=secret%20auth%20code"
156
+ end
157
+ end
158
+
159
+
160
+ end
161
+
162
+ describe "user does not authorize" do
163
+
164
+ it "should send error" do
165
+ @authorizer = OAuth::Provider::Authorizer.new @user, false, :response_type => 'token',
166
+ :scope => "a b",
167
+ :client_id => 'client id',
168
+ :redirect_uri => 'http://mysite.com/callback'
169
+
170
+ @authorizer.redirect_uri.should == "http://mysite.com/callback#error=access_denied"
171
+ @authorizer.should_not be_authorized
172
+
173
+ end
174
+
175
+ it "should send error with state and query params in callback" do
176
+ @authorizer = OAuth::Provider::Authorizer.new @user, false, :response_type => 'token',
177
+ :scope => "a b",
178
+ :client_id => 'client id',
179
+ :redirect_uri=>'http://mysite.com/callback?this=one',
180
+ :state => "my customer"
181
+
182
+ @authorizer.redirect_uri.should == "http://mysite.com/callback?this=one#error=access_denied&state=my%20customer"
183
+ @authorizer.should_not be_authorized
184
+
185
+ end
186
+
187
+ end
188
+
189
+ it "should handle unsupported response type" do
190
+ @user = double("user")
191
+
192
+ @authorizer = OAuth::Provider::Authorizer.new @user, false, :response_type => 'my new',
193
+ :scope => "a b",
194
+ :client_id => 'client id',
195
+ :redirect_uri => 'http://mysite.com/callback'
196
+
197
+ @authorizer.redirect_uri.should == "http://mysite.com/callback#error=unsupported_response_type"
198
+ @authorizer.should_not be_authorized
199
+
200
+ end
201
+
202
+ end
@@ -3,6 +3,7 @@ require 'rack/test'
3
3
  require 'oauth/rack/oauth_filter'
4
4
  require 'multi_json'
5
5
  require 'forwardable'
6
+ require 'dummy_provider_models'
6
7
 
7
8
  class OAuthEcho
8
9
  def call(env)
@@ -28,7 +29,7 @@ describe OAuth::Rack::OAuthFilter do
28
29
  response = MultiJson.decode(last_response.body)
29
30
  response.should == {}
30
31
  end
31
-
32
+
32
33
  describe 'OAuth1' do
33
34
  describe 'with optional white space' do
34
35
  it "should sign with consumer" do
@@ -57,7 +58,7 @@ describe OAuth::Rack::OAuthFilter do
57
58
  response = MultiJson.decode(last_response.body)
58
59
  response.should == {"client_application" => "my_consumer", "oauth_token"=>"my_token","oauth_version"=>1, "strategies"=>["oauth10_token","oauth10_request_token"]}
59
60
  end
60
- end
61
+ end
61
62
 
62
63
  describe 'without optional white space' do
63
64
  it "should sign with consumer" do
@@ -86,9 +87,9 @@ describe OAuth::Rack::OAuthFilter do
86
87
  response = MultiJson.decode(last_response.body)
87
88
  response.should == {"client_application" => "my_consumer", "oauth_token"=>"my_token","oauth_version"=>1, "strategies"=>["oauth10_token","oauth10_request_token"]}
88
89
  end
89
- end
90
+ end
90
91
  end
91
-
92
+
92
93
  describe "OAuth2" do
93
94
  describe "token given through a HTTP Auth Header" do
94
95
  context "authorized and non-invalidated token" do
@@ -240,59 +241,4 @@ describe OAuth::Rack::OAuthFilter do
240
241
  end
241
242
  end
242
243
  end
243
-
244
-
245
- # Dummy implementation
246
- class ClientApplication
247
- attr_accessor :key
248
-
249
- def self.find_by_key(key)
250
- ClientApplication.new(key)
251
- end
252
-
253
- def initialize(key)
254
- @key = key
255
- end
256
-
257
- def tokens
258
- @tokens||=[]
259
- end
260
-
261
- def secret
262
- "secret"
263
- end
264
- end
265
-
266
- class OauthToken
267
- attr_accessor :token
268
-
269
- def self.first(conditions_hash)
270
- case conditions_hash[:conditions].last
271
- when "not_authorized", "invalidated"
272
- nil
273
- else
274
- OauthToken.new(conditions_hash[:conditions].last)
275
- end
276
- end
277
-
278
- def initialize(token)
279
- @token = token
280
- end
281
-
282
- def secret
283
- "secret"
284
- end
285
- end
286
-
287
- class Oauth2Token < OauthToken ; end
288
- class AccessToken < OauthToken ; end
289
- class RequestToken < OauthToken ; end
290
-
291
- class OauthNonce
292
- # Always remember
293
- def self.remember(nonce,timestamp)
294
- true
295
- end
296
- end
297
-
298
244
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: oauth-plugin
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: 6
5
- version: 0.4.0.rc1
5
+ version: 0.4.0.rc2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Pelle Braendgaard
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-06-28 00:00:00 Z
13
+ date: 2011-10-20 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: opentransact
@@ -297,9 +297,12 @@ files:
297
297
  - lib/oauth/models/consumers/services/twitter_token.rb
298
298
  - lib/oauth/models/consumers/simple_client.rb
299
299
  - lib/oauth/models/consumers/token.rb
300
+ - lib/oauth/provider/authorizer.rb
300
301
  - lib/oauth/rack/oauth_filter.rb
301
302
  - oauth-plugin.gemspec
302
303
  - rails/init.rb
304
+ - spec/dummy_provider_models.rb
305
+ - spec/oauth/provider/authorizer_spec.rb
303
306
  - spec/rack/oauth_filter_spec.rb
304
307
  - spec/spec_helper.rb
305
308
  - tasks/oauth_tasks.rake
@@ -332,5 +335,7 @@ signing_key:
332
335
  specification_version: 3
333
336
  summary: Ruby on Rails Plugin for OAuth Provider and Consumer
334
337
  test_files:
338
+ - spec/dummy_provider_models.rb
339
+ - spec/oauth/provider/authorizer_spec.rb
335
340
  - spec/rack/oauth_filter_spec.rb
336
341
  - spec/spec_helper.rb