[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