Skip to content

Commit a082a09

Browse files
committed
Better OAuth2 support. Refactored authorization code into an Authorizer object
1 parent 6b35ab3 commit a082a09

File tree

5 files changed

+357
-118
lines changed

5 files changed

+357
-118
lines changed

lib/oauth/controllers/provider_controller.rb

Lines changed: 14 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
require 'oauth/provider/authorizer'
12
module OAuth
23
module Controllers
34

@@ -9,7 +10,7 @@ def self.included(controller)
910
oauthenticate :strategies => :token, :interactive => false, :only => [:invalidate,:capabilities]
1011
oauthenticate :strategies => :two_legged, :interactive => false, :only => [:request_token]
1112
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]
1314
end
1415
end
1516

@@ -37,7 +38,10 @@ def token
3738
oauth2_error "invalid_client"
3839
return
3940
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])
4145
send "oauth2_token_#{params[:grant_type].underscore}"
4246
else
4347
oauth2_error "unsupported_grant_type"
@@ -52,10 +56,14 @@ def authorize
5256
if params[:oauth_token]
5357
@token = ::RequestToken.find_by_token! params[:oauth_token]
5458
oauth1_authorize
55-
elsif ["code","token"].include?(params[:response_type]) # pick flow
56-
send "oauth2_authorize_#{params[:response_type]}"
5759
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
5967
end
6068
end
6169

@@ -121,59 +129,6 @@ def oauth1_authorize
121129
end
122130
end
123131

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
177132

178133
# http://tools.ietf.org/html/draft-ietf-oauth-v2-22#section-4.1.1
179134
def oauth2_token_authorization_code
@@ -207,7 +162,7 @@ def authenticate_user(username,password)
207162
end
208163

209164
# autonomous authorization which creates a token for client_applications user
210-
def oauth2_token_none
165+
def oauth2_token_client_credentials
211166
@token = Oauth2Token.create :client_application=>@client_application, :user=>@client_application.user, :scope=>params[:scope]
212167
render :json=>@token
213168
end

lib/oauth/provider/authorizer.rb

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

spec/dummy_provider_models.rb

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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 commit comments

Comments
 (0)