Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Take Rack env objects instead of request objects from frameworks.

  • Loading branch information...
commit d3df406d9755a3f02b03cb4ca9c09177d4ab84b6 1 parent 21b2e74
@jcoglan jcoglan authored
View
25 README.rdoc
@@ -7,13 +7,9 @@ without affecting your application code at all. All you have to deal with is
authenticating your users and letting them grant access to client apps.
It is also designed to be usable within any web frontend, at least those of
-Rails and Sinatra. It assumes very little about the request objects in your
-environment, namely they:
-
-* respond to <tt>#params</tt> with a <tt>Hash</tt> of request parameters
-* respond to <tt>#get?</tt> and <tt>#post?</tt>
-* respond to <tt>#url</tt> with the full URL string of the request
-* respond to <tt>#env</tt>, returning the HTTP environment <tt>Hash</tt>
+Rails and Sinatra. Its API uses Rack request-environment hashes rather than
+framework-specific request objects, though you can pass those in and their
+<tt>request.env</tt> property will be used internally.
It stores the clients and authorizations using ActiveRecord.
@@ -186,7 +182,7 @@ the client:
[:get, :post].each do |method|
__send__ method, '/oauth/authorize' do
@owner = User.find_by_id(session[:user_id])
- @oauth2 = OAuth2::Provider.parse(@owner, request)
+ @oauth2 = OAuth2::Provider.parse(@owner, env)
if @oauth2.redirect?
redirect @oauth2.redirect_uri, @oauth2.response_status
@@ -318,7 +314,7 @@ simple, for example a call to get a user's notes:
get '/user/:username/notes' do
user = User.find_by_username(params[:username])
- token = OAuth2::Provider.access_token(user, ['read_notes'], request)
+ token = OAuth2::Provider.access_token(user, ['read_notes'], env)
headers token.response_headers
status token.response_status
@@ -331,9 +327,9 @@ simple, for example a call to get a user's notes:
end
<tt>OAuth2::Provider.access_token()</tt> takes a <tt>ResourceOwner</tt>, a list
-of scopes required to access the resource, and a request object. If the token
-was not granted for the required scopes, has expired or is simply invalid,
-headers and a status code are set to indicate this to the client.
+of scopes required to access the resource, and a request environment object. If
+the token was not granted for the required scopes, has expired or is simply
+invalid, headers and a status code are set to indicate this to the client.
<tt>token.valid?</tt> is the call you should use to determine whether to serve
the request or not.
@@ -342,7 +338,7 @@ about a user by supplying their access token. This can be done by passing
<tt>nil</tt> as the resource owner:
get '/me' do
- token = OAuth2::Provider.access_token(nil, [], request)
+ token = OAuth2::Provider.access_token(nil, [], env)
if token.valid?
JSON.unparse('username' => token.owner.username)
else
@@ -357,7 +353,7 @@ permissions.
== License
-Copyright (c) 2010-2011 Songkick.com
+Copyright (c) 2010-2012 Songkick.com
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -376,3 +372,4 @@ 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.
+
View
8 example/application.rb
@@ -64,7 +64,7 @@
[:get, :post].each do |method|
__send__ method, '/oauth/authorize' do
@user = User.find_by_id(session[:user_id])
- @oauth2 = OAuth2::Provider.parse(@user, request)
+ @oauth2 = OAuth2::Provider.parse(@user, env)
if @oauth2.redirect?
redirect @oauth2.redirect_uri, @oauth2.response_status
@@ -79,7 +79,7 @@
post '/login' do
@user = User.find_by_username(params[:username])
- @oauth2 = OAuth2::Provider.parse(@user, request)
+ @oauth2 = OAuth2::Provider.parse(@user, env)
session[:user_id] = @user.id
erb(@user ? :authorize : :login)
end
@@ -99,7 +99,7 @@
# Domain API
get '/me' do
- authorization = OAuth2::Provider.access_token(nil, [], request)
+ authorization = OAuth2::Provider.access_token(nil, [], env)
headers authorization.response_headers
status authorization.response_status
@@ -134,7 +134,7 @@
# Check for OAuth access before rendering a resource
def verify_access(scope)
user = User.find_by_username(params[:username])
- token = OAuth2::Provider.access_token(user, [scope.to_s], request)
+ token = OAuth2::Provider.access_token(user, [scope.to_s], env)
headers token.response_headers
status token.response_status
View
94 lib/oauth2/router.rb
@@ -3,56 +3,66 @@
module OAuth2
class Router
- def self.auth_params(request, params = nil)
- return {} unless basic = request.env['HTTP_AUTHORIZATION']
- parts = basic.split(/\s+/)
- username, password = Base64.decode64(parts.last).split(':')
- {CLIENT_ID => username, CLIENT_SECRET => password}
- end
+ # Public methods in the namespace take either Rack env objects, or Request
+ # objects from Rails/Sinatra and an optional params hash which it then
+ # coerces to Rack requests. This is for backward compatibility; originally
+ # it only took request objects.
- def self.detect_transport_error(request)
- uri = URI.parse(request.url)
-
- if Provider.enforce_ssl and not uri.is_a?(URI::HTTPS)
- Provider::Error.new("must make requests using HTTPS")
+ class << self
+ def parse(resource_owner, env)
+ error = detect_transport_error(env)
+ request = Rack::Request.new(env.respond_to?(:env) ? env.env : env)
+ params = request.params
+ auth = auth_params(env)
+
+ if auth[CLIENT_ID] and auth[CLIENT_ID] != params[CLIENT_ID]
+ error ||= Provider::Error.new("#{CLIENT_ID} from Basic Auth and request body do not match")
+ end
+
+ params = params.merge(auth)
+
+ if params[GRANT_TYPE]
+ error ||= Provider::Error.new('must be a POST request') unless request.post?
+ Provider::Exchange.new(resource_owner, params, error)
+ else
+ Provider::Authorization.new(resource_owner, params, error)
+ end
end
- end
-
- def self.parse(resource_owner, request, params = nil)
- error = detect_transport_error(request)
-
- params ||= request.params
- auth = auth_params(request, params)
- if auth[CLIENT_ID] and auth[CLIENT_ID] != params[CLIENT_ID]
- error ||= Provider::Error.new("#{CLIENT_ID} from Basic Auth and request body do not match")
+ def access_token(resource_owner, scopes, env)
+ access_token = access_token_from_request(env)
+ Provider::AccessToken.new(resource_owner,
+ scopes,
+ access_token,
+ detect_transport_error(env))
+ end
+
+ def access_token_from_request(env)
+ request = Rack::Request.new(env.respond_to?(:env) ? env.env : env)
+ params = request.params
+ header = request.env['HTTP_AUTHORIZATION']
+
+ header && header =~ /^OAuth\s+/ ?
+ header.gsub(/^OAuth\s+/, '') :
+ params[OAUTH_TOKEN]
end
- params = params.merge(auth)
+ private
- if params[GRANT_TYPE]
- error ||= Provider::Error.new('must be a POST request') unless request.post?
- Provider::Exchange.new(resource_owner, params, error)
- else
- Provider::Authorization.new(resource_owner, params, error)
+ def auth_params(env)
+ return {} unless basic = env['HTTP_AUTHORIZATION']
+ parts = basic.split(/\s+/)
+ username, password = Base64.decode64(parts.last).split(':')
+ {CLIENT_ID => username, CLIENT_SECRET => password}
end
- end
-
- def self.access_token(resource_owner, scopes, request, params = nil)
- access_token = access_token_from_request(request, params)
- Provider::AccessToken.new(resource_owner,
- scopes,
- access_token,
- detect_transport_error(request))
- end
-
- def self.access_token_from_request(request, params = nil)
- params ||= request.params
- header = request.env['HTTP_AUTHORIZATION']
- header && header =~ /^OAuth\s+/ ?
- header.gsub(/^OAuth\s+/, '') :
- params[OAUTH_TOKEN]
+ def detect_transport_error(env)
+ request = Rack::Request.new(env.respond_to?(:env) ? env.env : env)
+
+ if Provider.enforce_ssl and not request.ssl?
+ Provider::Error.new("must make requests using HTTPS")
+ end
+ end
end
end
View
1  oauth2-provider.gemspec
@@ -15,6 +15,7 @@ spec = Gem::Specification.new do |s|
s.add_dependency("activerecord")
s.add_dependency("bcrypt-ruby")
s.add_dependency("json")
+ s.add_dependency("rack")
s.add_development_dependency("activerecord", "~> 3.0.0") # The SQLite adapter in 3.1 is broken
s.add_development_dependency("rspec")
View
4 spec/test_app/provider/application.rb
@@ -10,7 +10,7 @@ class Provider < Sinatra::Base
set :views, File.dirname(__FILE__) + '/views'
def handle_authorize
- @oauth2 = OAuth2::Provider.parse(User['Bob'], request)
+ @oauth2 = OAuth2::Provider.parse(User['Bob'], env)
redirect(@oauth2.redirect_uri, @oauth2.response_status) if @oauth2.redirect?
headers @oauth2.response_headers
@@ -20,7 +20,7 @@ def handle_authorize
end
def protect_resource_for(user = nil, scopes = [])
- access_token = OAuth2::Provider.access_token(user, scopes, request)
+ access_token = OAuth2::Provider.access_token(user, scopes, env)
headers access_token.response_headers
status access_token.response_status
yield access_token
Please sign in to comment.
Something went wrong with that request. Please try again.