Created
January 31, 2012 02:45
-
-
Save khy/1708389 to your computer and use it in GitHub Desktop.
useless.io Authentication
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Useless | |
module Authentication | |
# The `Authentication::AccessToken` module defines the behavior for access- | |
# token-based authentication middleware. The middlewares are responsible | |
# only for providing the access token via the `#access_token_for_env` | |
# method. | |
module AccessToken | |
def initialize(app) | |
@app = app | |
end | |
def call(env) | |
# If we don't already have a user set in the environment, | |
unless env['useless.user'] | |
# check to see if an access token was specified. | |
if access_token = access_token_for_env(env) | |
# If so, and a corresponding user can be found, | |
if user = Useless.mongo['users'].find_one('access_token' => access_token) | |
# set 'useless.user' in the environment. | |
env['useless.user'] = user | |
else | |
# Otherwise, return a 401 Unauthorized. | |
return [401, {'Content-Type' => 'text/plain'}, ["Invalid access token: #{access_token}"]] | |
end | |
end | |
end | |
@app.call(env) | |
end | |
private | |
def access_token_for_env(env) | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
source :rubygems | |
gem 'rack' | |
gem 'mongo' | |
gem 'bson' | |
gem 'bson_ext' | |
group :test do | |
gem 'rspec' | |
end | |
group :development do | |
gem 'heroku' | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Useless | |
# The `Useless::Mongo` module defines the interface for a Mongo helper | |
# class. Each helper class must override `#database`. | |
module Mongo | |
# Returns an instance of the appropriate helper class based upon the | |
# `RACK_ENV` environment variable (or the `env` parameter, if specified). | |
def self.for_env(env = nil) | |
case (env || ENV['RACK_ENV']) | |
when 'test' then Test.new | |
when 'production' then Production.new | |
else Development.new | |
end | |
end | |
# Simple access to a Mongo::Collection instance. | |
def [](collection) | |
db[collection] | |
end | |
# The environment's Mongo::DB instance. | |
def db | |
@db ||= self.connection.db(database) | |
end | |
# The environment's Mongo::Grid instance - a file store. | |
def grid | |
@grid ||= ::Mongo::Grid.new(db) | |
end | |
# The environment's Mongo::Connection instance. | |
def connection | |
@connection ||= ::Mongo::Connection.new(host) | |
end | |
# The host that `#connection` will use. | |
def host | |
'localhost' | |
end | |
# The database `#db` will use - must be overriden. | |
def database | |
end | |
class Development | |
include Mongo | |
def database | |
'useless_development' | |
end | |
end | |
class Test | |
include Mongo | |
def database | |
'useless_test' | |
end | |
end | |
class Production | |
include Mongo | |
# In production - on Heroku - we will need to use a URI to connect. | |
def connection | |
@connection ||= ::Mongo::Connection.from_uri(uri) | |
end | |
# The database can be extracted from the URI, | |
def database | |
uri.match(/.*\/(.*)$/)[1] | |
end | |
private | |
# and the URI is specified in the environment variable `MONGOLAB_URI`. | |
def uri | |
ENV['MONGOLAB_URI'] | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Useless | |
module Authentication | |
# The `Authentication::QueryString` middleware attempt to retrieve the | |
# access token from the query string. | |
class QueryString | |
include AccessToken | |
private | |
def access_token_for_env(env) | |
Rack::Utils.parse_query(env['QUERY_STRING'])['access_token'] | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require File.dirname(__FILE__) + '/../../../spec_helper' | |
describe Useless::Authentication::QueryString do | |
def authenticated_app | |
app = lambda do |env| | |
body = env['useless.user'] ? | |
"user authenticated: #{env['useless.user']['handle']}" : | |
"unauthenticated" | |
[200, {'Content-Type' => 'text/plain'}, [body]] | |
end | |
Useless::Authentication::QueryString.new(app) | |
end | |
it 'should do nothing if `useless.user` is already set' do | |
Useless.mongo['users'].insert({'handle' => 'dph', 'access_token' => 'def456'}) | |
res = Rack::MockRequest.new(authenticated_app).get('/resource?access_token=def456', | |
'useless.user' => {'handle' => 'khy', 'access_token' => 'abc123'}) | |
res.should be_ok | |
res.body.should == 'user authenticated: khy' | |
end | |
it 'should do nothing if no access token is specified' do | |
res = Rack::MockRequest.new(authenticated_app).get('/resource') | |
res.should be_ok | |
res.body.should == 'unauthenticated' | |
end | |
it 'should return a 401 Unauthenticated if an access token is specified, but | |
does not correspond to a user' do | |
res = Rack::MockRequest.new(authenticated_app).get('/resource?access_token=abc123') | |
res.status.should == 401 | |
res.body.should == 'Invalid access token: abc123' | |
end | |
it 'should set `useless.user` in the environment if a user can be found for | |
the specified access token' do | |
Useless.mongo['users'].insert({'handle' => 'khy', 'access_token' => 'abc123'}) | |
res = Rack::MockRequest.new(authenticated_app).get('/resource?access_token=abc123') | |
res.should be_ok | |
res.body.should == 'user authenticated: khy' | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Useless | |
module Authentication | |
# The `Authentication::RequestHeader` middleware attempts to retrieve the | |
# access token from the `Authorization` request header. | |
class RequestHeader | |
include AccessToken | |
private | |
def access_token_for_env(env) | |
env['Authorization'] | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
RSpec.configure do |config| | |
def clean_database | |
Useless.mongo.db.collections.each do |collection| | |
if !(collection.name =~ /^system\./) | |
collection.drop | |
end | |
end | |
end | |
config.before(:suite){ clean_database } | |
config.after(:each){ clean_database } | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$:.unshift File.dirname(__FILE__) | |
require 'rubygems' | |
require 'bundler/setup' | |
require 'mongo' | |
module Useless | |
autoload :Mongo, 'useless/mongo' | |
def self.mongo | |
@mongo ||= Useless::Mongo.for_env | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Useless | |
module Authentication | |
autoload :AccessToken, 'useless/middleware/authentication/access_token' | |
autoload :QueryString, 'useless/middleware/authentication/query_string' | |
autoload :RequestHeader, 'useless/middleware/authentication/request_header' | |
end | |
def self.call(env) | |
map = SubdomainMap.new Base.new, | |
'street-art' => StreetArt.new | |
Rack::Builder.app do | |
use Authentication::QueryString | |
use Authentication::RequestHeader | |
run map | |
end.call(env) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment