Permalink
Browse files

supercharge OAuth2 middleware

Changes:

 - existing "Authorization" header not overriden
 - configure param name instead of "access_token"
 - TomDoc
 - write ALL THE TESTS
 - backwards-compatible!
  • Loading branch information...
mislav committed Jan 22, 2012
1 parent 1d7510d commit a9d67d2f66d7079f668f2fda39b6b73e6cad5fd5
Showing with 127 additions and 39 deletions.
  1. +32 −6 lib/faraday_middleware/request/oauth2.rb
  2. +95 −33 spec/oauth2_spec.rb
@@ -2,25 +2,51 @@
require 'forwardable'
module FaradayMiddleware
+ # Public: A simple middleware that adds an access token to each request.
+ #
+ # The token is added as both "access_token" query parameter and the
+ # "Authorization" HTTP request header. However, an explicit "access_token"
+ # parameter or "Authorization" header for the current request are not
+ # overriden.
+ #
+ # Examples
+ #
+ # # configure default token:
+ # OAuth2.new(app, 'abc123')
+ #
+ # # configure query parameter name:
+ # OAuth2.new(app, 'abc123', :param_name => 'my_oauth_token')
+ #
+ # # default token value is optional:
+ # OAuth2.new(app, :param_name => 'my_oauth_token')
class OAuth2 < Faraday::Middleware
dependency 'oauth2'
+ PARAM_NAME = 'access_token'.freeze
+ AUTH_HEADER = 'Authorization'.freeze
+
+ attr_reader :param_name
+
extend Forwardable
def_delegators :'Faraday::Utils', :parse_query, :build_query
def call(env)
- params = { 'access_token' => @token }.update query_params(env[:url])
- token = params['access_token']
+ params = { param_name => @token }.update query_params(env[:url])
- env[:url].query = build_query params
- env[:request_headers]['Authorization'] = %(Token token="#{token}")
+ if token = params[param_name] and !token.empty?
+ env[:url].query = build_query params
+ env[:request_headers][AUTH_HEADER] ||= %(Token token="#{token}")
+ end
@app.call env
end
- def initialize(app, *args)
+ def initialize(app, token = nil, options = {})
super(app)
- @token = args.shift
+ options, token = token, nil if token.is_a? Hash
+ @token = token && token.to_s
+ @param_name = options.fetch(:param_name, PARAM_NAME).to_s
+ raise ArgumentError, ":param_name can't be blank" if @param_name.empty?
end
def query_params(url)
View
@@ -1,56 +1,118 @@
require 'helper'
require 'uri'
require 'faraday_middleware/request/oauth2'
+require 'faraday/utils'
describe FaradayMiddleware::OAuth2 do
- def query_params(request)
- Faraday::Utils.parse_query request[:url].query
+ def query_params(env)
+ Faraday::Utils.parse_query env[:url].query
end
- context 'when used with a access token in the initializer' do
- let(:oauth2) { described_class.new(lambda{|env| env}, '1234') }
+ def auth_header(env)
+ env[:request_headers]['Authorization']
+ end
+
+ def perform(params = {}, headers = {})
+ env = {
+ :url => URI('http://example.com/?' + Faraday::Utils.build_query(params)),
+ :request_headers => Faraday::Utils::Headers.new.update(headers)
+ }
+ app = make_app
+ app.call(env)
+ end
+
+ def make_app
+ described_class.new(lambda{|env| env}, *Array(options))
+ end
+
+ context "no token configured" do
+ let(:options) { nil }
+
+ it "doesn't add params" do
+ request = perform(:q => 'hello')
+ query_params(request).should eq('q' => 'hello')
+ end
- it 'should add the access token to the request' do
- env = {
- :request_headers => {},
- :url => URI('http://www.github.com')
- }
+ it "doesn't add headers" do
+ auth_header(perform).should be_nil
+ end
- request = oauth2.call(env)
- request[:request_headers]["Authorization"].should == "Token token=\"1234\""
- query_params(request)["access_token"].should == "1234"
+ it "creates header for explicit token" do
+ request = perform(:q => 'hello', :access_token => 'abc123')
+ query_params(request).should eq('q' => 'hello', 'access_token' => 'abc123')
+ auth_header(request).should eq(%(Token token="abc123"))
end
end
- context 'when used with a access token in the query_values' do
- let(:oauth2) { described_class.new(lambda{|env| env}) }
+ context "default token configured" do
+ let(:options) { 'XYZ' }
+
+ it "adds token param" do
+ query_params(perform(:q => 'hello')).should eq('q' => 'hello', 'access_token' => 'XYZ')
+ end
+
+ it "adds token header" do
+ auth_header(perform).should eq(%(Token token="XYZ"))
+ end
- it 'should add the access token to the request' do
- env = {
- :request_headers => {},
- :url => URI('http://www.github.com/?access_token=1234')
- }
+ it "overrides default with explicit token" do
+ request = perform(:q => 'hello', :access_token => 'abc123')
+ query_params(request).should eq('q' => 'hello', 'access_token' => 'abc123')
+ auth_header(request).should eq(%(Token token="abc123"))
+ end
- request = oauth2.call(env)
- request[:request_headers]["Authorization"].should == "Token token=\"1234\""
- query_params(request)["access_token"].should == "1234"
+ it "clears default with empty explicit token" do
+ request = perform(:q => 'hello', :access_token => nil)
+ query_params(request).should eq('q' => 'hello', 'access_token' => nil)
+ auth_header(request).should be_nil
end
end
- context 'integration test' do
- let(:stubs) { Faraday::Adapter::Test::Stubs.new }
- let(:connection) do
- Faraday::Connection.new do |builder|
- builder.use described_class, '1234'
- builder.adapter :test, stubs
- end
+ context "existing Authorization header" do
+ let(:options) { 'XYZ' }
+ subject { perform({:q => 'hello'}, 'Authorization' => 'custom') }
+
+ it "adds token param" do
+ query_params(subject).should eq('q' => 'hello', 'access_token' => 'XYZ')
end
- it 'should add the access token to the query string' do
- stubs.get('/me?access_token=1234') {[200, {}, 'sferik']}
- me = connection.get('/me')
- me.body.should == 'sferik'
+ it "doesn't override existing header" do
+ auth_header(subject).should eq('custom')
+ end
+ end
+
+ context "custom param name configured" do
+ let(:options) { ['XYZ', {:param_name => :oauth}] }
+
+ it "adds token param" do
+ query_params(perform).should eq('oauth' => 'XYZ')
+ end
+
+ it "overrides default with explicit token" do
+ request = perform(:oauth => 'abc123')
+ query_params(request).should eq('oauth' => 'abc123')
+ auth_header(request).should eq(%(Token token="abc123"))
+ end
+ end
+
+ context "options without token configuration" do
+ let(:options) { [{:param_name => :oauth}] }
+
+ it "doesn't add param" do
+ query_params(perform).should be_empty
+ end
+
+ it "overrides default with explicit token" do
+ query_params(perform(:oauth => 'abc123')).should eq('oauth' => 'abc123')
+ end
+ end
+
+ context "invalid param name configured" do
+ let(:options) { ['XYZ', {:param_name => nil}] }
+
+ it "raises error" do
+ expect { make_app }.to raise_error(ArgumentError, ":param_name can't be blank")
end
end
end

0 comments on commit a9d67d2

Please sign in to comment.