[DRE-commits] [ruby-oauth2] 04/06: Imported Upstream version 1.2.0

Praveen Arimbrathodiyil praveen at moszumanska.debian.org
Thu Jul 14 09:55:05 UTC 2016


This is an automated email from the git hooks/post-receive script.

praveen pushed a commit to branch master
in repository ruby-oauth2.

commit a5466a12b69f2ae0c8fbeaca9d82f27a494aef2a
Author: Praveen Arimbrathodiyil <praveen at debian.org>
Date:   Thu Jul 14 14:59:21 2016 +0530

    Imported Upstream version 1.2.0
---
 .gitignore                                      |  10 ++
 .rspec                                          |   2 +
 .rubocop.yml                                    |  58 +++++++
 .travis.yml                                     |  21 +++
 CHANGELOG.md                                    |  29 ++++
 Gemfile                                         |  24 +++
 Rakefile                                        |  39 +++++
 spec/helper.rb                                  |  41 +++++
 spec/oauth2/access_token_spec.rb                | 182 ++++++++++++++++++++
 spec/oauth2/client_spec.rb                      | 218 ++++++++++++++++++++++++
 spec/oauth2/mac_token_spec.rb                   | 119 +++++++++++++
 spec/oauth2/response_spec.rb                    |  91 ++++++++++
 spec/oauth2/strategy/assertion_spec.rb          |  55 ++++++
 spec/oauth2/strategy/auth_code_spec.rb          |  88 ++++++++++
 spec/oauth2/strategy/base_spec.rb               |   7 +
 spec/oauth2/strategy/client_credentials_spec.rb |  81 +++++++++
 spec/oauth2/strategy/implicit_spec.rb           |  28 +++
 spec/oauth2/strategy/password_spec.rb           |  56 ++++++
 18 files changed, 1149 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5528b6a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,10 @@
+*.gem
+*~
+.bundle
+.rvmrc
+Gemfile.lock
+coverage/*
+log/*
+measurement/*
+pkg/*
+rdoc/*
diff --git a/.rspec b/.rspec
new file mode 100644
index 0000000..0912718
--- /dev/null
+++ b/.rspec
@@ -0,0 +1,2 @@
+--color
+--order random
diff --git a/.rubocop.yml b/.rubocop.yml
new file mode 100644
index 0000000..de3e9d9
--- /dev/null
+++ b/.rubocop.yml
@@ -0,0 +1,58 @@
+Metrics/BlockNesting:
+  Max: 2
+
+Metrics/LineLength:
+  AllowURI: true
+  Enabled: false
+
+Metrics/MethodLength:
+  CountComments: false
+  Max: 15
+
+Metrics/ParameterLists:
+  Max: 4
+  CountKeywordArgs: true
+
+Lint/UnusedBlockArgument:
+  Exclude:
+    - 'spec/**/*.rb'
+
+Style/AccessModifierIndentation:
+  EnforcedStyle: outdent
+
+Style/ClassVars:
+  Enabled: false
+
+Style/CollectionMethods:
+  PreferredMethods:
+    map:      'collect'
+    reduce:   'inject'
+    find:     'detect'
+    find_all: 'select'
+
+Style/Documentation:
+  Enabled: false
+
+Style/DotPosition:
+  EnforcedStyle: trailing
+
+Style/DoubleNegation:
+  Enabled: false
+
+Style/EachWithObject:
+  Enabled: false
+
+Style/Encoding:
+  Enabled: false
+
+Style/HashSyntax:
+  EnforcedStyle: hash_rockets
+
+Style/Lambda:
+  Enabled: false
+
+Style/SpaceInsideHashLiteralBraces:
+  EnforcedStyle: no_space
+
+Style/TrailingCommaInLiteral:
+  EnforcedStyleForMultiline: 'comma'
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..b13650e
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,21 @@
+bundler_args: --without development
+env:
+  global:
+    - JRUBY_OPTS="$JRUBY_OPTS --debug"
+language: ruby
+rvm:
+  - 1.8.7
+  - 1.9.3
+  - 2.0.0
+  - 2.1
+  - 2.2
+  - 2.3.0
+  - jruby-9.0.5.0
+  - jruby-head
+  - ruby-head
+matrix:
+  allow_failures:
+    - rvm: jruby-head
+    - rvm: ruby-head
+  fast_finish: true
+sudo: false
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..7e8959b
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,29 @@
+# Change Log
+All notable changes to this project will be documented in this file.
+
+## [unreleased]
+- No significant changes.
+
+## [1.0.0] - 2014-07-09
+
+### Added
+- Add an implementation of the MAC token spec.
+
+### Fixed
+- Fix Base64.strict_encode64 incompatibility with Ruby 1.8.7.
+
+## [unreleased]
+- No significant changes.
+
+## [0.5.0] - 2011-07-29
+
+### Changed
+- [breaking] `oauth_token` renamed to `oauth_bearer`.
+- [breaking] `authorize_path` Client option renamed to `authorize_url`.
+- [breaking] `access_token_path` Client option renamed to `token_url`.
+- [breaking] `access_token_method` Client option renamed to `token_method`.
+- [breaking] `web_server` renamed to `auth_code`.
+
+[unreleased]: https://github.com/intridea/oauth2/compare/v1.0.0...HEAD
+[1.0.0]: https://github.com/intridea/oauth2/compare/v0.9.4...v1.0.0
+[0.5.0]: https://github.com/intridea/oauth2/compare/v0.4.1...v0.5.0
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..62b9b85
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,24 @@
+source 'https://rubygems.org'
+
+gem 'jwt', '< 1.5.2', :platforms => [:jruby_18, :ruby_18]
+gem 'rake', '< 11.0'
+gem 'rdoc'
+
+group :development do
+  gem 'pry'
+end
+
+group :test do
+  gem 'addressable', '~> 2.3.8'
+  gem 'backports'
+  gem 'coveralls'
+  gem 'mime-types', '~> 1.25', :platforms => [:jruby_18, :ruby_18]
+  gem 'rack', '~> 1.2', :platforms => [:jruby_18, :jruby_19, :ruby_18, :ruby_19, :ruby_20, :ruby_21]
+  gem 'rest-client', '~> 1.6.0', :platforms => [:jruby_18, :ruby_18]
+  gem 'rspec', '>= 3'
+  gem 'rubocop', '>= 0.37', :platforms => [:ruby_19, :ruby_20, :ruby_21]
+  gem 'simplecov', '>= 0.9'
+  gem 'yardstick'
+end
+
+gemspec
diff --git a/Rakefile b/Rakefile
new file mode 100644
index 0000000..6f1b424
--- /dev/null
+++ b/Rakefile
@@ -0,0 +1,39 @@
+require 'bundler'
+Bundler::GemHelper.install_tasks
+
+require 'rspec/core/rake_task'
+RSpec::Core::RakeTask.new(:spec)
+
+task :test => :spec
+
+namespace :doc do
+  require 'rdoc/task'
+  require File.expand_path('../lib/oauth2/version', __FILE__)
+  RDoc::Task.new do |rdoc|
+    rdoc.rdoc_dir = 'rdoc'
+    rdoc.title = "oauth2 #{OAuth2::Version}"
+    rdoc.main = 'README.md'
+    rdoc.rdoc_files.include('README.md', 'LICENSE.md', 'lib/**/*.rb')
+  end
+end
+
+begin
+  require 'rubocop/rake_task'
+  RuboCop::RakeTask.new
+rescue LoadError
+  task :rubocop do
+    $stderr.puts 'RuboCop is disabled'
+  end
+end
+
+require 'yardstick/rake/measurement'
+Yardstick::Rake::Measurement.new do |measurement|
+  measurement.output = 'measurement/report.txt'
+end
+
+require 'yardstick/rake/verify'
+Yardstick::Rake::Verify.new do |verify|
+  verify.threshold = 59.7
+end
+
+task :default => [:spec, :rubocop, :verify_measurements]
diff --git a/spec/helper.rb b/spec/helper.rb
new file mode 100644
index 0000000..6f3c3af
--- /dev/null
+++ b/spec/helper.rb
@@ -0,0 +1,41 @@
+if RUBY_VERSION >= '1.9'
+  require 'simplecov'
+  require 'coveralls'
+
+  SimpleCov.formatters = [SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter]
+
+  SimpleCov.start do
+    add_filter '/spec'
+    minimum_coverage(95.33)
+  end
+end
+
+require 'oauth2'
+require 'addressable/uri'
+require 'rspec'
+
+RSpec.configure do |config|
+  config.expect_with :rspec do |c|
+    c.syntax = :expect
+  end
+end
+
+Faraday.default_adapter = :test
+
+RSpec.configure do |conf|
+  include OAuth2
+end
+
+def capture_output
+  begin
+    old_stdout = $stdout
+    $stdout = StringIO.new
+    yield
+    result = $stdout.string
+  ensure
+    $stdout = old_stdout
+  end
+  result
+end
+
+VERBS = [:get, :post, :put, :delete].freeze
diff --git a/spec/oauth2/access_token_spec.rb b/spec/oauth2/access_token_spec.rb
new file mode 100644
index 0000000..314f3ac
--- /dev/null
+++ b/spec/oauth2/access_token_spec.rb
@@ -0,0 +1,182 @@
+require 'helper'
+
+describe AccessToken do
+  let(:token) { 'monkey' }
+  let(:refresh_body) { MultiJson.encode(:access_token => 'refreshed_foo', :expires_in => 600, :refresh_token => 'refresh_bar') }
+  let(:client) do
+    Client.new('abc', 'def', :site => 'https://api.example.com') do |builder|
+      builder.request :url_encoded
+      builder.adapter :test do |stub|
+        VERBS.each do |verb|
+          stub.send(verb, '/token/header') { |env| [200, {}, env[:request_headers]['Authorization']] }
+          stub.send(verb, "/token/query?access_token=#{token}") { |env| [200, {}, Addressable::URI.parse(env[:url]).query_values['access_token']] }
+          stub.send(verb, '/token/body') { |env| [200, {}, env[:body]] }
+        end
+        stub.post('/oauth/token') { |env| [200, {'Content-Type' => 'application/json'}, refresh_body] }
+      end
+    end
+  end
+
+  subject { AccessToken.new(client, token) }
+
+  describe '#initialize' do
+    it 'assigns client and token' do
+      expect(subject.client).to eq(client)
+      expect(subject.token).to eq(token)
+    end
+
+    it 'assigns extra params' do
+      target = AccessToken.new(client, token, 'foo' => 'bar')
+      expect(target.params).to include('foo')
+      expect(target.params['foo']).to eq('bar')
+    end
+
+    def assert_initialized_token(target) # rubocop:disable Metrics/AbcSize
+      expect(target.token).to eq(token)
+      expect(target).to be_expires
+      expect(target.params.keys).to include('foo')
+      expect(target.params['foo']).to eq('bar')
+    end
+
+    it 'initializes with a Hash' do
+      hash = {:access_token => token, :expires_at => Time.now.to_i + 200, 'foo' => 'bar'}
+      target = AccessToken.from_hash(client, hash)
+      assert_initialized_token(target)
+    end
+
+    it 'does not modify opts hash' do
+      hash = {:access_token => token, :expires_at => Time.now.to_i}
+      hash_before = hash.dup
+      AccessToken.from_hash(client, hash)
+      expect(hash).to eq(hash_before)
+    end
+
+    it 'initalizes with a form-urlencoded key/value string' do
+      kvform = "access_token=#{token}&expires_at=#{Time.now.to_i + 200}&foo=bar"
+      target = AccessToken.from_kvform(client, kvform)
+      assert_initialized_token(target)
+    end
+
+    it 'sets options' do
+      target = AccessToken.new(client, token, :param_name => 'foo', :header_format => 'Bearer %', :mode => :body)
+      expect(target.options[:param_name]).to eq('foo')
+      expect(target.options[:header_format]).to eq('Bearer %')
+      expect(target.options[:mode]).to eq(:body)
+    end
+
+    it 'does not modify opts hash' do
+      opts = {:param_name => 'foo', :header_format => 'Bearer %', :mode => :body}
+      opts_before = opts.dup
+      AccessToken.new(client, token, opts)
+      expect(opts).to eq(opts_before)
+    end
+
+    it 'initializes with a string expires_at' do
+      hash = {:access_token => token, :expires_at => '1361396829', 'foo' => 'bar'}
+      target = AccessToken.from_hash(client, hash)
+      assert_initialized_token(target)
+      expect(target.expires_at).to be_a(Integer)
+    end
+  end
+
+  describe '#request' do
+    context ':mode => :header' do
+      before do
+        subject.options[:mode] = :header
+      end
+
+      VERBS.each do |verb|
+        it "sends the token in the Authorization header for a #{verb.to_s.upcase} request" do
+          expect(subject.post('/token/header').body).to include(token)
+        end
+      end
+    end
+
+    context ':mode => :query' do
+      before do
+        subject.options[:mode] = :query
+      end
+
+      VERBS.each do |verb|
+        it "sends the token in the Authorization header for a #{verb.to_s.upcase} request" do
+          expect(subject.post('/token/query').body).to eq(token)
+        end
+      end
+    end
+
+    context ':mode => :body' do
+      before do
+        subject.options[:mode] = :body
+      end
+
+      VERBS.each do |verb|
+        it "sends the token in the Authorization header for a #{verb.to_s.upcase} request" do
+          expect(subject.post('/token/body').body.split('=').last).to eq(token)
+        end
+      end
+    end
+  end
+
+  describe '#expires?' do
+    it 'is false if there is no expires_at' do
+      expect(AccessToken.new(client, token)).not_to be_expires
+    end
+
+    it 'is true if there is an expires_in' do
+      expect(AccessToken.new(client, token, :refresh_token => 'abaca', :expires_in => 600)).to be_expires
+    end
+
+    it 'is true if there is an expires_at' do
+      expect(AccessToken.new(client, token, :refresh_token => 'abaca', :expires_in => Time.now.getutc.to_i + 600)).to be_expires
+    end
+  end
+
+  describe '#expired?' do
+    it 'is false if there is no expires_in or expires_at' do
+      expect(AccessToken.new(client, token)).not_to be_expired
+    end
+
+    it 'is false if expires_in is in the future' do
+      expect(AccessToken.new(client, token, :refresh_token => 'abaca', :expires_in => 10_800)).not_to be_expired
+    end
+
+    it 'is true if expires_at is in the past' do
+      access = AccessToken.new(client, token, :refresh_token => 'abaca', :expires_in => 600)
+      @now = Time.now + 10_800
+      allow(Time).to receive(:now).and_return(@now)
+      expect(access).to be_expired
+    end
+  end
+
+  describe '#refresh!' do
+    let(:access) do
+      AccessToken.new(client, token, :refresh_token  => 'abaca',
+                                     :expires_in     => 600,
+                                     :param_name     => 'o_param')
+    end
+
+    it 'returns a refresh token with appropriate values carried over' do
+      refreshed = access.refresh!
+      expect(access.client).to eq(refreshed.client)
+      expect(access.options[:param_name]).to eq(refreshed.options[:param_name])
+    end
+
+    context 'with a nil refresh_token in the response' do
+      let(:refresh_body) { MultiJson.encode(:access_token => 'refreshed_foo', :expires_in => 600, :refresh_token => nil) }
+
+      it 'copies the refresh_token from the original token' do
+        refreshed = access.refresh!
+
+        expect(refreshed.refresh_token).to eq(access.refresh_token)
+      end
+    end
+  end
+
+  describe '#to_hash' do
+    it 'return a hash equals to the hash used to initialize access token' do
+      hash = {:access_token => token, :refresh_token => 'foobar', :expires_at => Time.now.to_i + 200, 'foo' => 'bar'}
+      access_token = AccessToken.from_hash(client, hash.clone)
+      expect(access_token.to_hash).to eq(hash)
+    end
+  end
+end
diff --git a/spec/oauth2/client_spec.rb b/spec/oauth2/client_spec.rb
new file mode 100644
index 0000000..4facce2
--- /dev/null
+++ b/spec/oauth2/client_spec.rb
@@ -0,0 +1,218 @@
+# coding: utf-8
+require 'helper'
+require 'nkf'
+
+describe OAuth2::Client do
+  let!(:error_value) { 'invalid_token' }
+  let!(:error_description_value) { 'bad bad token' }
+
+  subject do
+    OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com') do |builder|
+      builder.adapter :test do |stub|
+        stub.get('/success')            { |env| [200, {'Content-Type' => 'text/awesome'}, 'yay'] }
+        stub.get('/reflect')            { |env| [200, {}, env[:body]] }
+        stub.post('/reflect')           { |env| [200, {}, env[:body]] }
+        stub.get('/unauthorized')       { |env| [401, {'Content-Type' => 'application/json'}, MultiJson.encode(:error => error_value, :error_description => error_description_value)] }
+        stub.get('/conflict')           { |env| [409, {'Content-Type' => 'text/plain'}, 'not authorized'] }
+        stub.get('/redirect')           { |env| [302, {'Content-Type' => 'text/plain', 'location' => '/success'}, ''] }
+        stub.post('/redirect')          { |env| [303, {'Content-Type' => 'text/plain', 'location' => '/reflect'}, ''] }
+        stub.get('/error')              { |env| [500, {'Content-Type' => 'text/plain'}, 'unknown error'] }
+        stub.get('/empty_get')          { |env| [204, {}, nil] }
+        stub.get('/different_encoding') { |env| [500, {'Content-Type' => 'application/json'}, NKF.nkf('-We', MultiJson.encode(:error => error_value, :error_description => '∞'))] }
+      end
+    end
+  end
+
+  describe '#initialize' do
+    it 'assigns id and secret' do
+      expect(subject.id).to eq('abc')
+      expect(subject.secret).to eq('def')
+    end
+
+    it 'assigns site from the options hash' do
+      expect(subject.site).to eq('https://api.example.com')
+    end
+
+    it 'assigns Faraday::Connection#host' do
+      expect(subject.connection.host).to eq('api.example.com')
+    end
+
+    it 'leaves Faraday::Connection#ssl unset' do
+      expect(subject.connection.ssl).to be_empty
+    end
+
+    it 'is able to pass a block to configure the connection' do
+      connection = double('connection')
+      builder = double('builder')
+      allow(connection).to receive(:build).and_yield(builder)
+      allow(Faraday::Connection).to receive(:new).and_return(connection)
+
+      expect(builder).to receive(:adapter).with(:test)
+
+      OAuth2::Client.new('abc', 'def') do |client|
+        client.adapter :test
+      end.connection
+    end
+
+    it 'defaults raise_errors to true' do
+      expect(subject.options[:raise_errors]).to be true
+    end
+
+    it 'allows true/false for raise_errors option' do
+      client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :raise_errors => false)
+      expect(client.options[:raise_errors]).to be false
+      client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :raise_errors => true)
+      expect(client.options[:raise_errors]).to be true
+    end
+
+    it 'allows override of raise_errors option' do
+      client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :raise_errors => true) do |builder|
+        builder.adapter :test do |stub|
+          stub.get('/notfound') { |env| [404, {}, nil] }
+        end
+      end
+      expect(client.options[:raise_errors]).to be true
+      expect { client.request(:get, '/notfound') }.to raise_error(OAuth2::Error)
+      response = client.request(:get, '/notfound', :raise_errors => false)
+      expect(response.status).to eq(404)
+    end
+
+    it 'allows get/post for access_token_method option' do
+      client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :access_token_method => :get)
+      expect(client.options[:access_token_method]).to eq(:get)
+      client = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :access_token_method => :post)
+      expect(client.options[:access_token_method]).to eq(:post)
+    end
+
+    it 'does not mutate the opts hash argument' do
+      opts = {:site => 'http://example.com/'}
+      opts2 = opts.dup
+      OAuth2::Client.new 'abc', 'def', opts
+      expect(opts).to eq(opts2)
+    end
+  end
+
+  %w(authorize token).each do |url_type|
+    describe ":#{url_type}_url option" do
+      it "defaults to a path of /oauth/#{url_type}" do
+        expect(subject.send("#{url_type}_url")).to eq("https://api.example.com/oauth/#{url_type}")
+      end
+
+      it "is settable via the :#{url_type}_url option" do
+        subject.options[:"#{url_type}_url"] = '/oauth/custom'
+        expect(subject.send("#{url_type}_url")).to eq('https://api.example.com/oauth/custom')
+      end
+
+      it 'allows a different host than the site' do
+        subject.options[:"#{url_type}_url"] = 'https://api.foo.com/oauth/custom'
+        expect(subject.send("#{url_type}_url")).to eq('https://api.foo.com/oauth/custom')
+      end
+    end
+  end
+
+  describe '#request' do
+    it 'works with a null response body' do
+      expect(subject.request(:get, 'empty_get').body).to eq('')
+    end
+
+    it 'returns on a successful response' do
+      response = subject.request(:get, '/success')
+      expect(response.body).to eq('yay')
+      expect(response.status).to eq(200)
+      expect(response.headers).to eq('Content-Type' => 'text/awesome')
+    end
+
+    it 'outputs to $stdout when OAUTH_DEBUG=true' do
+      allow(ENV).to receive(:[]).with('http_proxy').and_return(nil)
+      allow(ENV).to receive(:[]).with('OAUTH_DEBUG').and_return('true')
+      output = capture_output do
+        subject.request(:get, '/success')
+      end
+
+      expect(output).to include 'INFO -- : get https://api.example.com/success', 'INFO -- : get https://api.example.com/success'
+    end
+
+    it 'posts a body' do
+      response = subject.request(:post, '/reflect', :body => 'foo=bar')
+      expect(response.body).to eq('foo=bar')
+    end
+
+    it 'follows redirects properly' do
+      response = subject.request(:get, '/redirect')
+      expect(response.body).to eq('yay')
+      expect(response.status).to eq(200)
+      expect(response.headers).to eq('Content-Type' => 'text/awesome')
+    end
+
+    it 'redirects using GET on a 303' do
+      response = subject.request(:post, '/redirect', :body => 'foo=bar')
+      expect(response.body).to be_empty
+      expect(response.status).to eq(200)
+    end
+
+    it 'obeys the :max_redirects option' do
+      max_redirects = subject.options[:max_redirects]
+      subject.options[:max_redirects] = 0
+      response = subject.request(:get, '/redirect')
+      expect(response.status).to eq(302)
+      subject.options[:max_redirects] = max_redirects
+    end
+
+    it 'returns if raise_errors is false' do
+      subject.options[:raise_errors] = false
+      response = subject.request(:get, '/unauthorized')
+
+      expect(response.status).to eq(401)
+      expect(response.headers).to eq('Content-Type' => 'application/json')
+      expect(response.error).not_to be_nil
+    end
+
+    %w(/unauthorized /conflict /error /different_encoding).each do |error_path|
+      it "raises OAuth2::Error on error response to path #{error_path}" do
+        expect { subject.request(:get, error_path) }.to raise_error(OAuth2::Error)
+      end
+    end
+
+    it 'parses OAuth2 standard error response' do
+      begin
+        subject.request(:get, '/unauthorized')
+      rescue StandardError => e
+        expect(e.code).to eq(error_value)
+        expect(e.description).to eq(error_description_value)
+        expect(e.to_s).to match(/#{error_value}/)
+        expect(e.to_s).to match(/#{error_description_value}/)
+      end
+    end
+
+    it 'provides the response in the Exception' do
+      begin
+        subject.request(:get, '/error')
+      rescue StandardError => e
+        expect(e.response).not_to be_nil
+        expect(e.to_s).to match(/unknown error/)
+      end
+    end
+  end
+
+  it 'instantiates an AuthCode strategy with this client' do
+    expect(subject.auth_code).to be_kind_of(OAuth2::Strategy::AuthCode)
+  end
+
+  it 'instantiates an Implicit strategy with this client' do
+    expect(subject.implicit).to be_kind_of(OAuth2::Strategy::Implicit)
+  end
+
+  context 'with SSL options' do
+    subject do
+      cli = OAuth2::Client.new('abc', 'def', :site => 'https://api.example.com', :ssl => {:ca_file => 'foo.pem'})
+      cli.connection.build do |b|
+        b.adapter :test
+      end
+      cli
+    end
+
+    it 'passes the SSL options along to Faraday::Connection#ssl' do
+      expect(subject.connection.ssl.fetch(:ca_file)).to eq('foo.pem')
+    end
+  end
+end
diff --git a/spec/oauth2/mac_token_spec.rb b/spec/oauth2/mac_token_spec.rb
new file mode 100644
index 0000000..595a243
--- /dev/null
+++ b/spec/oauth2/mac_token_spec.rb
@@ -0,0 +1,119 @@
+require 'helper'
+
+describe MACToken do
+  let(:token) { 'monkey' }
+  let(:client) do
+    Client.new('abc', 'def', :site => 'https://api.example.com') do |builder|
+      builder.request :url_encoded
+      builder.adapter :test do |stub|
+        VERBS.each do |verb|
+          stub.send(verb, '/token/header') { |env| [200, {}, env[:request_headers]['Authorization']] }
+        end
+      end
+    end
+  end
+
+  subject { MACToken.new(client, token, 'abc123') }
+
+  describe '#initialize' do
+    it 'assigns client and token' do
+      expect(subject.client).to eq(client)
+      expect(subject.token).to eq(token)
+    end
+
+    it 'assigns secret' do
+      expect(subject.secret).to eq('abc123')
+    end
+
+    it 'defaults algorithm to hmac-sha-256' do
+      expect(subject.algorithm).to be_instance_of(OpenSSL::Digest::SHA256)
+    end
+
+    it 'handles hmac-sha-256' do
+      mac = MACToken.new(client, token, 'abc123', :algorithm => 'hmac-sha-256')
+      expect(mac.algorithm).to be_instance_of(OpenSSL::Digest::SHA256)
+    end
+
+    it 'handles hmac-sha-1' do
+      mac = MACToken.new(client, token, 'abc123', :algorithm => 'hmac-sha-1')
+      expect(mac.algorithm).to be_instance_of(OpenSSL::Digest::SHA1)
+    end
+
+    it 'raises on improper algorithm' do
+      expect { MACToken.new(client, token, 'abc123', :algorithm => 'invalid-sha') }.to raise_error(ArgumentError)
+    end
+  end
+
+  describe '#request' do
+    VERBS.each do |verb|
+      it "sends the token in the Authorization header for a #{verb.to_s.upcase} request" do
+        expect(subject.post('/token/header').body).to include("MAC id=\"#{token}\"")
+      end
+    end
+  end
+
+  describe '#header' do
+    it 'does not generate the same header twice' do
+      header = subject.header('get', 'https://www.example.com/hello')
+      duplicate_header = subject.header('get', 'https://www.example.com/hello')
+
+      expect(header).to_not eq(duplicate_header)
+    end
+
+    it 'generates the proper format' do
+      header = subject.header('get', 'https://www.example.com/hello?a=1')
+      expect(header).to match(/MAC id="#{token}", ts="[0-9]+", nonce="[^"]+", mac="[^"]+"/)
+    end
+
+    it 'passes ArgumentError with an invalid url' do
+      expect { subject.header('get', 'this-is-not-valid') }.to raise_error(ArgumentError)
+    end
+
+    it 'passes URI::InvalidURIError through' do
+      expect { subject.header('get', nil) }.to raise_error(URI::InvalidURIError)
+    end
+  end
+
+  describe '#signature' do
+    it 'generates properly' do
+      signature = subject.signature(0, 'random-string', 'get', URI('https://www.google.com'))
+      expect(signature).to eq('rMDjVA3VJj3v1OmxM29QQljKia6msl5rjN83x3bZmi8=')
+    end
+  end
+
+  describe '#headers' do
+    it 'is an empty hash' do
+      expect(subject.headers).to eq({})
+    end
+  end
+
+  describe '.from_access_token' do
+    let(:access_token) do
+      AccessToken.new(
+        client, token,
+        :expires_at => 1,
+        :expires_in => 1,
+        :refresh_token => 'abc',
+        :random => 1
+      )
+    end
+
+    subject { MACToken.from_access_token(access_token, 'hello') }
+
+    it 'initializes client, token, and secret properly' do
+      expect(subject.client).to eq(client)
+      expect(subject.token).to eq(token)
+      expect(subject.secret).to eq('hello')
+    end
+
+    it 'initializes configuration options' do
+      expect(subject.expires_at).to eq(1)
+      expect(subject.expires_in).to eq(1)
+      expect(subject.refresh_token).to eq('abc')
+    end
+
+    it 'initializes params' do
+      expect(subject.params).to eq(:random => 1)
+    end
+  end
+end
diff --git a/spec/oauth2/response_spec.rb b/spec/oauth2/response_spec.rb
new file mode 100644
index 0000000..24f4c23
--- /dev/null
+++ b/spec/oauth2/response_spec.rb
@@ -0,0 +1,91 @@
+require 'helper'
+
+describe OAuth2::Response do
+  describe '#initialize' do
+    let(:status) { 200 }
+    let(:headers) { {'foo' => 'bar'} }
+    let(:body) { 'foo' }
+
+    it 'returns the status, headers and body' do
+      response = double('response', :headers => headers,
+                                    :status  => status,
+                                    :body    => body)
+      subject = Response.new(response)
+      expect(subject.headers).to eq(headers)
+      expect(subject.status).to eq(status)
+      expect(subject.body).to eq(body)
+    end
+  end
+
+  describe '.register_parser' do
+    let(:response) do
+      double('response', :headers => {'Content-Type' => 'application/foo-bar'},
+                         :status => 200,
+                         :body => 'baz')
+    end
+    before do
+      OAuth2::Response.register_parser(:foobar, 'application/foo-bar') do |body|
+        "foobar #{body}"
+      end
+    end
+
+    it 'adds to the content types and parsers' do
+      expect(OAuth2::Response.send(:class_variable_get, :@@parsers).keys).to include(:foobar)
+      expect(OAuth2::Response.send(:class_variable_get, :@@content_types).keys).to include('application/foo-bar')
+    end
+
+    it 'is able to parse that content type automatically' do
+      expect(OAuth2::Response.new(response).parsed).to eq('foobar baz')
+    end
+  end
+
+  describe '#parsed' do
+    it 'parses application/x-www-form-urlencoded body' do
+      headers = {'Content-Type' => 'application/x-www-form-urlencoded'}
+      body = 'foo=bar&answer=42'
+      response = double('response', :headers => headers, :body => body)
+      subject = Response.new(response)
+      expect(subject.parsed.keys.size).to eq(2)
+      expect(subject.parsed['foo']).to eq('bar')
+      expect(subject.parsed['answer']).to eq('42')
+    end
+
+    it 'parses application/json body' do
+      headers = {'Content-Type' => 'application/json'}
+      body = MultiJson.encode(:foo => 'bar', :answer => 42)
+      response = double('response', :headers => headers, :body => body)
+      subject = Response.new(response)
+      expect(subject.parsed.keys.size).to eq(2)
+      expect(subject.parsed['foo']).to eq('bar')
+      expect(subject.parsed['answer']).to eq(42)
+    end
+
+    it "doesn't try to parse other content-types" do
+      headers = {'Content-Type' => 'text/html'}
+      body = '<!DOCTYPE html><html><head></head><body></body></html>'
+
+      response = double('response', :headers => headers, :body => body)
+
+      expect(MultiJson).not_to receive(:decode)
+      expect(MultiJson).not_to receive(:load)
+      expect(Rack::Utils).not_to receive(:parse_query)
+
+      subject = Response.new(response)
+      expect(subject.parsed).to be_nil
+    end
+  end
+
+  context 'xml parser registration' do
+    it 'tries to load multi_xml and use it' do
+      expect(OAuth2::Response.send(:class_variable_get, :@@parsers)[:xml]).not_to be_nil
+    end
+
+    it 'is able to parse xml' do
+      headers = {'Content-Type' => 'text/xml'}
+      body = '<?xml version="1.0" standalone="yes" ?><foo><bar>baz</bar></foo>'
+
+      response = double('response', :headers => headers, :body => body)
+      expect(OAuth2::Response.new(response).parsed).to eq('foo' => {'bar' => 'baz'})
+    end
+  end
+end
diff --git a/spec/oauth2/strategy/assertion_spec.rb b/spec/oauth2/strategy/assertion_spec.rb
new file mode 100644
index 0000000..a574741
--- /dev/null
+++ b/spec/oauth2/strategy/assertion_spec.rb
@@ -0,0 +1,55 @@
+require 'helper'
+
+describe OAuth2::Strategy::Assertion do
+  let(:client) do
+    cli = OAuth2::Client.new('abc', 'def', :site => 'http://api.example.com')
+    cli.connection.build do |b|
+      b.adapter :test do |stub|
+        stub.post('/oauth/token') do |env|
+          case @mode
+          when 'formencoded'
+            [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, 'expires_in=600&access_token=salmon&refresh_token=trout']
+          when 'json'
+            [200, {'Content-Type' => 'application/json'}, '{"expires_in":600,"access_token":"salmon","refresh_token":"trout"}']
+          end
+        end
+      end
+    end
+    cli
+  end
+
+  let(:params) { {:hmac_secret => 'foo'} }
+
+  subject { client.assertion }
+
+  describe '#authorize_url' do
+    it 'raises NotImplementedError' do
+      expect { subject.authorize_url }.to raise_error(NotImplementedError)
+    end
+  end
+
+  %w(json formencoded).each do |mode|
+    describe "#get_token (#{mode})" do
+      before do
+        @mode = mode
+        @access = subject.get_token(params)
+      end
+
+      it 'returns AccessToken with same Client' do
+        expect(@access.client).to eq(client)
+      end
+
+      it 'returns AccessToken with #token' do
+        expect(@access.token).to eq('salmon')
+      end
+
+      it 'returns AccessToken with #expires_in' do
+        expect(@access.expires_in).to eq(600)
+      end
+
+      it 'returns AccessToken with #expires_at' do
+        expect(@access.expires_at).not_to be_nil
+      end
+    end
+  end
+end
diff --git a/spec/oauth2/strategy/auth_code_spec.rb b/spec/oauth2/strategy/auth_code_spec.rb
new file mode 100644
index 0000000..a6f5768
--- /dev/null
+++ b/spec/oauth2/strategy/auth_code_spec.rb
@@ -0,0 +1,88 @@
+require 'helper'
+
+describe OAuth2::Strategy::AuthCode do
+  let(:code) { 'sushi' }
+  let(:kvform_token) { 'expires_in=600&access_token=salmon&refresh_token=trout&extra_param=steve' }
+  let(:facebook_token) { kvform_token.gsub('_in', '') }
+  let(:json_token) { MultiJson.encode(:expires_in => 600, :access_token => 'salmon', :refresh_token => 'trout', :extra_param => 'steve') }
+
+  let(:client) do
+    OAuth2::Client.new('abc', 'def', :site => 'http://api.example.com') do |builder|
+      builder.adapter :test do |stub|
+        stub.get("/oauth/token?client_id=abc&client_secret=def&code=#{code}&grant_type=authorization_code") do |env|
+          case @mode
+          when 'formencoded'
+            [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, kvform_token]
+          when 'json'
+            [200, {'Content-Type' => 'application/json'}, json_token]
+          when 'from_facebook'
+            [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, facebook_token]
+          end
+        end
+        stub.post('/oauth/token', 'client_id' => 'abc', 'client_secret' => 'def', 'code' => 'sushi', 'grant_type' => 'authorization_code') do |env|
+          case @mode
+          when 'formencoded'
+            [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, kvform_token]
+          when 'json'
+            [200, {'Content-Type' => 'application/json'}, json_token]
+          when 'from_facebook'
+            [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, facebook_token]
+          end
+        end
+      end
+    end
+  end
+
+  subject { client.auth_code }
+
+  describe '#authorize_url' do
+    it 'includes the client_id' do
+      expect(subject.authorize_url).to include('client_id=abc')
+    end
+
+    it 'includes the type' do
+      expect(subject.authorize_url).to include('response_type=code')
+    end
+
+    it 'includes passed in options' do
+      cb = 'http://myserver.local/oauth/callback'
+      expect(subject.authorize_url(:redirect_uri => cb)).to include("redirect_uri=#{Rack::Utils.escape(cb)}")
+    end
+  end
+
+  %w(json formencoded from_facebook).each do |mode|
+    [:get, :post].each do |verb|
+      describe "#get_token (#{mode}, access_token_method=#{verb}" do
+        before do
+          @mode = mode
+          client.options[:token_method] = verb
+          @access = subject.get_token(code)
+        end
+
+        it 'returns AccessToken with same Client' do
+          expect(@access.client).to eq(client)
+        end
+
+        it 'returns AccessToken with #token' do
+          expect(@access.token).to eq('salmon')
+        end
+
+        it 'returns AccessToken with #refresh_token' do
+          expect(@access.refresh_token).to eq('trout')
+        end
+
+        it 'returns AccessToken with #expires_in' do
+          expect(@access.expires_in).to eq(600)
+        end
+
+        it 'returns AccessToken with #expires_at' do
+          expect(@access.expires_at).to be_kind_of(Integer)
+        end
+
+        it 'returns AccessToken with params accessible via []' do
+          expect(@access['extra_param']).to eq('steve')
+        end
+      end
+    end
+  end
+end
diff --git a/spec/oauth2/strategy/base_spec.rb b/spec/oauth2/strategy/base_spec.rb
new file mode 100644
index 0000000..1174413
--- /dev/null
+++ b/spec/oauth2/strategy/base_spec.rb
@@ -0,0 +1,7 @@
+require 'helper'
+
+describe OAuth2::Strategy::Base do
+  it 'initializes with a Client' do
+    expect { OAuth2::Strategy::Base.new(OAuth2::Client.new('abc', 'def')) }.not_to raise_error
+  end
+end
diff --git a/spec/oauth2/strategy/client_credentials_spec.rb b/spec/oauth2/strategy/client_credentials_spec.rb
new file mode 100644
index 0000000..a2a9f4c
--- /dev/null
+++ b/spec/oauth2/strategy/client_credentials_spec.rb
@@ -0,0 +1,81 @@
+require 'helper'
+
+describe OAuth2::Strategy::ClientCredentials do
+  let(:kvform_token) { 'expires_in=600&access_token=salmon&refresh_token=trout' }
+  let(:json_token) { '{"expires_in":600,"access_token":"salmon","refresh_token":"trout"}' }
+
+  let(:client) do
+    OAuth2::Client.new('abc', 'def', :site => 'http://api.example.com') do |builder|
+      builder.adapter :test do |stub|
+        stub.post('/oauth/token', 'grant_type' => 'client_credentials') do |env|
+          client_id, client_secret = Base64.decode64(env[:request_headers]['Authorization'].split(' ', 2)[1]).split(':', 2)
+          client_id == 'abc' && client_secret == 'def' || raise(Faraday::Adapter::Test::Stubs::NotFound)
+          case @mode
+          when 'formencoded'
+            [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, kvform_token]
+          when 'json'
+            [200, {'Content-Type' => 'application/json'}, json_token]
+          end
+        end
+        stub.post('/oauth/token', 'client_id' => 'abc', 'client_secret' => 'def', 'grant_type' => 'client_credentials') do |env|
+          case @mode
+          when 'formencoded'
+            [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, kvform_token]
+          when 'json'
+            [200, {'Content-Type' => 'application/json'}, json_token]
+          end
+        end
+      end
+    end
+  end
+
+  subject { client.client_credentials }
+
+  describe '#authorize_url' do
+    it 'raises NotImplementedError' do
+      expect { subject.authorize_url }.to raise_error(NotImplementedError)
+    end
+  end
+
+  describe '#authorization' do
+    it 'generates an Authorization header value for HTTP Basic Authentication' do
+      [
+        ['abc', 'def', 'Basic YWJjOmRlZg=='],
+        ['xxx', 'secret', 'Basic eHh4OnNlY3JldA=='],
+      ].each do |client_id, client_secret, expected|
+        expect(subject.authorization(client_id, client_secret)).to eq(expected)
+      end
+    end
+  end
+
+  %w(json formencoded).each do |mode|
+    %w(default basic_auth request_body).each do |auth_scheme|
+      describe "#get_token (#{mode}) (#{auth_scheme})" do
+        before do
+          @mode = mode
+          @access = subject.get_token({}, auth_scheme == 'default' ? {} : {'auth_scheme' => auth_scheme})
+        end
+
+        it 'returns AccessToken with same Client' do
+          expect(@access.client).to eq(client)
+        end
+
+        it 'returns AccessToken with #token' do
+          expect(@access.token).to eq('salmon')
+        end
+
+        it 'returns AccessToken without #refresh_token' do
+          expect(@access.refresh_token).to be_nil
+        end
+
+        it 'returns AccessToken with #expires_in' do
+          expect(@access.expires_in).to eq(600)
+        end
+
+        it 'returns AccessToken with #expires_at' do
+          expect(@access.expires_at).not_to be_nil
+        end
+      end
+    end
+  end
+end
diff --git a/spec/oauth2/strategy/implicit_spec.rb b/spec/oauth2/strategy/implicit_spec.rb
new file mode 100644
index 0000000..af2d043
--- /dev/null
+++ b/spec/oauth2/strategy/implicit_spec.rb
@@ -0,0 +1,28 @@
+require 'helper'
+
+describe OAuth2::Strategy::Implicit do
+  let(:client) { OAuth2::Client.new('abc', 'def', :site => 'http://api.example.com') }
+
+  subject { client.implicit }
+
+  describe '#authorize_url' do
+    it 'includes the client_id' do
+      expect(subject.authorize_url).to include('client_id=abc')
+    end
+
+    it 'includes the type' do
+      expect(subject.authorize_url).to include('response_type=token')
+    end
+
+    it 'includes passed in options' do
+      cb = 'http://myserver.local/oauth/callback'
+      expect(subject.authorize_url(:redirect_uri => cb)).to include("redirect_uri=#{Rack::Utils.escape(cb)}")
+    end
+  end
+
+  describe '#get_token' do
+    it 'raises NotImplementedError' do
+      expect { subject.get_token }.to raise_error(NotImplementedError)
+    end
+  end
+end
diff --git a/spec/oauth2/strategy/password_spec.rb b/spec/oauth2/strategy/password_spec.rb
new file mode 100644
index 0000000..bda609d
--- /dev/null
+++ b/spec/oauth2/strategy/password_spec.rb
@@ -0,0 +1,56 @@
+require 'helper'
+
+describe OAuth2::Strategy::Password do
+  let(:client) do
+    cli = OAuth2::Client.new('abc', 'def', :site => 'http://api.example.com')
+    cli.connection.build do |b|
+      b.adapter :test do |stub|
+        stub.post('/oauth/token') do |env|
+          case @mode
+          when 'formencoded'
+            [200, {'Content-Type' => 'application/x-www-form-urlencoded'}, 'expires_in=600&access_token=salmon&refresh_token=trout']
+          when 'json'
+            [200, {'Content-Type' => 'application/json'}, '{"expires_in":600,"access_token":"salmon","refresh_token":"trout"}']
+          end
+        end
+      end
+    end
+    cli
+  end
+  subject { client.password }
+
+  describe '#authorize_url' do
+    it 'raises NotImplementedError' do
+      expect { subject.authorize_url }.to raise_error(NotImplementedError)
+    end
+  end
+
+  %w(json formencoded).each do |mode|
+    describe "#get_token (#{mode})" do
+      before do
+        @mode = mode
+        @access = subject.get_token('username', 'password')
+      end
+
+      it 'returns AccessToken with same Client' do
+        expect(@access.client).to eq(client)
+      end
+
+      it 'returns AccessToken with #token' do
+        expect(@access.token).to eq('salmon')
+      end
+
+      it 'returns AccessToken with #refresh_token' do
+        expect(@access.refresh_token).to eq('trout')
+      end
+
+      it 'returns AccessToken with #expires_in' do
+        expect(@access.expires_in).to eq(600)
+      end
+
+      it 'returns AccessToken with #expires_at' do
+        expect(@access.expires_at).not_to be_nil
+      end
+    end
+  end
+end

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-ruby-extras/ruby-oauth2.git



More information about the Pkg-ruby-extras-commits mailing list