oauth-plugin 0.4.0.rc1 → 0.4.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
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