Prep for 0.5 release, update unit tests to use webmock instead of Faraday stubs (due to fragility -- sensitive to internal changes made in signet)

This commit is contained in:
Steven Bazyl 2015-12-09 15:45:22 -08:00
parent 2be5bfe375
commit b46a7dc82c
13 changed files with 238 additions and 230 deletions

View File

@ -1,3 +1,10 @@
## 0.5.0 (12/10/2015)
### Changes
* Initial support for user credentials ([@sqrrrl][])
* Update Signet to 0.7
## 0.4.2 (05/08/2015) ## 0.4.2 (05/08/2015)
### Changes ### Changes

View File

@ -15,6 +15,7 @@ group :development do
gem 'fakeredis', '~> 0.5' gem 'fakeredis', '~> 0.5'
gem 'webmock', '~> 1.21' gem 'webmock', '~> 1.21'
gem 'rack-test', '~> 0.6' gem 'rack-test', '~> 0.6'
gem 'sinatra'
end end
platforms :jruby do platforms :jruby do

View File

@ -38,7 +38,8 @@ $ gem install googleauth
require 'googleauth' require 'googleauth'
# Get the environment configured authorization # Get the environment configured authorization
scopes = ['https://www.googleapis.com/auth/cloud-platform', 'https://www.googleapis.com/auth/compute'] scopes = ['https://www.googleapis.com/auth/cloud-platform',
'https://www.googleapis.com/auth/compute']
authorization = Google::Auth.get_application_default(scopes) authorization = Google::Auth.get_application_default(scopes)
# Add the the access token obtained using the authorization to a hash, e.g # Add the the access token obtained using the authorization to a hash, e.g
@ -61,6 +62,84 @@ and authorization level for the application independent of the user. This is
the recommended approach to authorize calls to Cloud APIs, particularly when the recommended approach to authorize calls to Cloud APIs, particularly when
you're building an application that uses Google Compute Engine. you're building an application that uses Google Compute Engine.
## User Credentials
The library also provides support for requesting and storing user
credentials (3-Legged OAuth2.) Two implementations are currently available,
a generic authorizer useful for command line apps or custom integrations as
well as a web variant tailored toward Rack-based applications.
The authorizers are intended for authorization use cases. For sign-on,
see [Google Idenity Platform](https://developers.google.com/identity/)
### Example (Web)
```ruby
require 'googleauth'
require 'googleauth/web_user_authorizer'
require 'googleauth/stores/redis_token_store'
require 'redis'
client_id = Google::Auth::ClientId.from_file('/path/to/client_secrets.json')
scope = ['https://www.googleapis.com/auth/drive']
token_store = Google::Auth::Stores::RedisTokenStore.new(redis: Redis.new)
authorizer = Google::Auth::WebUserAuthorizer.new(
client_id, scope, token_store, '/oauth2callback')
get('/authorize') do
# NOTE: Assumes the user is already authenticated to the app
user_id = request.session['user_id']
credentials = authorizer.get_credentials(user_id, request)
if credentials.nil?
redirect authorizer.get_authorization_url(user_id: user_id, request: request)
end
# Credentials are valid, can call APIs
# ...
end
get('/oauth2callback') do
target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(
request)
redirect target_url
end
```
### Example (Command Line)
```ruby
require 'googleauth'
require 'googleauth/stores/file_token_store'
scope = 'https://www.googleapis.com/auth/drive'
client_id = Google::Auth::ClientId.from_file('/path/to/client_secrets.json')
token_store = Google::Auth::Stores::FileTokenStore.new(
:file => '/path/to/tokens.yaml')
authorizer = Google::Auth::UserAuthorizer.new(client_id, scope, token_store)
credentials = authorizer.get_credentials(user_id)
if credentials.nil?
url = authorizer.get_authorization_url(base_url: 'urn:ietf:wg:oauth:2.0:oob')
puts "Open #{url} in your browser and enter the resulting code:"
code = gets
credentials = authorizer.get_and_store_credentials_from_code(
user_id: user_id, code: code, base_url: OOB_URI)
end
# OK to use credentials
```
### Storage
Authorizers require a storage instance to manage long term persistence of
access and refresh tokens. Two storage implementations are included:
* Google::Auth::Stores::FileTokenStore
* Google::Auth::Stores::RedisTokenStore
Custom storage implementations can also be used. See
[token_store.rb](lib/googleauth/token_store.rb) for additional details.
## What about auth in google-apis-ruby-client? ## What about auth in google-apis-ruby-client?
The goal is for all auth done by The goal is for all auth done by

View File

@ -30,5 +30,5 @@ Gem::Specification.new do |s|
s.add_dependency 'jwt', '~> 1.4' s.add_dependency 'jwt', '~> 1.4'
s.add_dependency 'memoist', '~> 0.12' s.add_dependency 'memoist', '~> 0.12'
s.add_dependency 'multi_json', '~> 1.11' s.add_dependency 'multi_json', '~> 1.11'
s.add_dependency 'signet', '~> 0.6' s.add_dependency 'signet', '~> 0.7'
end end

View File

@ -42,7 +42,7 @@ module Signet
def apply!(a_hash, opts = {}) def apply!(a_hash, opts = {})
# fetch the access token there is currently not one, or if the client # fetch the access token there is currently not one, or if the client
# has expired # has expired
fetch_access_token!(opts) if access_token.nil? || expired? fetch_access_token!(opts) if access_token.nil? || expires_within?(60)
a_hash[AUTH_METADATA_KEY] = "Bearer #{access_token}" a_hash[AUTH_METADATA_KEY] = "Bearer #{access_token}"
end end
@ -65,7 +65,7 @@ module Signet
end end
alias_method :orig_fetch_access_token!, :fetch_access_token! alias_method :orig_fetch_access_token!, :fetch_access_token!
def fetch_access_token!(options) def fetch_access_token!(options = {})
info = orig_fetch_access_token!(options) info = orig_fetch_access_token!(options)
notify_refresh_listeners notify_refresh_listeners
info info

View File

@ -31,6 +31,6 @@ module Google
# Module Auth provides classes that provide Google-specific authorization # Module Auth provides classes that provide Google-specific authorization
# used to access Google APIs. # used to access Google APIs.
module Auth module Auth
VERSION = '0.4.2' VERSION = '0.5.0'
end end
end end

View File

@ -44,16 +44,16 @@ module Google
# user_id = request.session['user_email'] # user_id = request.session['user_email']
# credentials = authorizer.get_credentials(user_id, request) # credentials = authorizer.get_credentials(user_id, request)
# if credentials.nil? # if credentials.nil?
# redirect authorizer.get_redirect_uri(user_id, request) # redirect authorizer.get_authorization_url(user_id: user_id, request: request)
# end # end
# # Credentials are valid, can call APIs # # Credentials are valid, can call APIs
# ... # ...
# end # end
# #
# get('/oauth2callback') do # get('/oauth2callback') do
# user_id = request.session['user_email'] # target_url = Google::Auth::WebUserAuthorizer.handle_auth_callback_deferred(
# _, return_uri = authorizer.handle_auth_callback(user_id, request) # request)
# redirect return_uri # redirect target_url
# end # end
# #
# Instead of implementing the callback directly, applications are # Instead of implementing the callback directly, applications are

View File

@ -57,124 +57,101 @@ shared_examples 'apply/apply! are OK' do
# auth client # auth client
describe '#fetch_access_token' do describe '#fetch_access_token' do
let(:token) { '1/abcdef1234567890' } let(:token) { '1/abcdef1234567890' }
let(:stubs) do let(:stub) do
make_auth_stubs access_token: token make_auth_stubs access_token: token
end end
let(:connection) do
Faraday.new do |b|
b.adapter(:test, stubs)
end
end
it 'should set access_token to the fetched value' do it 'should set access_token to the fetched value' do
@client.fetch_access_token!(connection: connection) stub
@client.fetch_access_token!
expect(@client.access_token).to eq(token) expect(@client.access_token).to eq(token)
stubs.verify_stubbed_calls expect(stub).to have_been_requested
end end
it 'should notify refresh listeners after updating' do it 'should notify refresh listeners after updating' do
stub
expect do |b| expect do |b|
@client.on_refresh(&b) @client.on_refresh(&b)
@client.fetch_access_token!(connection: connection) @client.fetch_access_token!
end.to yield_with_args(have_attributes( end.to yield_with_args(have_attributes(
access_token: '1/abcdef1234567890')) access_token: '1/abcdef1234567890'))
stubs.verify_stubbed_calls expect(stub).to have_been_requested
end end
end end
describe '#apply!' do describe '#apply!' do
it 'should update the target hash with fetched access token' do it 'should update the target hash with fetched access token' do
token = '1/abcdef1234567890' token = '1/abcdef1234567890'
stubs = make_auth_stubs access_token: token stub = make_auth_stubs access_token: token
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
md = { foo: 'bar' } md = { foo: 'bar' }
@client.apply!(md, connection: c) @client.apply!(md)
want = { :foo => 'bar', auth_key => "Bearer #{token}" } want = { :foo => 'bar', auth_key => "Bearer #{token}" }
expect(md).to eq(want) expect(md).to eq(want)
stubs.verify_stubbed_calls expect(stub).to have_been_requested
end end
end end
describe 'updater_proc' do describe 'updater_proc' do
it 'should provide a proc that updates a hash with the access token' do it 'should provide a proc that updates a hash with the access token' do
token = '1/abcdef1234567890' token = '1/abcdef1234567890'
stubs = make_auth_stubs access_token: token stub = make_auth_stubs access_token: token
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
md = { foo: 'bar' } md = { foo: 'bar' }
the_proc = @client.updater_proc the_proc = @client.updater_proc
got = the_proc.call(md, connection: c) got = the_proc.call(md)
want = { :foo => 'bar', auth_key => "Bearer #{token}" } want = { :foo => 'bar', auth_key => "Bearer #{token}" }
expect(got).to eq(want) expect(got).to eq(want)
stubs.verify_stubbed_calls expect(stub).to have_been_requested
end end
end end
describe '#apply' do describe '#apply' do
it 'should not update the original hash with the access token' do it 'should not update the original hash with the access token' do
token = '1/abcdef1234567890' token = '1/abcdef1234567890'
stubs = make_auth_stubs access_token: token stub = make_auth_stubs access_token: token
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
md = { foo: 'bar' } md = { foo: 'bar' }
@client.apply(md, connection: c) @client.apply(md)
want = { foo: 'bar' } want = { foo: 'bar' }
expect(md).to eq(want) expect(md).to eq(want)
stubs.verify_stubbed_calls expect(stub).to have_been_requested
end end
it 'should add the token to the returned hash' do it 'should add the token to the returned hash' do
token = '1/abcdef1234567890' token = '1/abcdef1234567890'
stubs = make_auth_stubs access_token: token stub = make_auth_stubs access_token: token
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
md = { foo: 'bar' } md = { foo: 'bar' }
got = @client.apply(md, connection: c) got = @client.apply(md)
want = { :foo => 'bar', auth_key => "Bearer #{token}" } want = { :foo => 'bar', auth_key => "Bearer #{token}" }
expect(got).to eq(want) expect(got).to eq(want)
stubs.verify_stubbed_calls expect(stub).to have_been_requested
end end
it 'should not fetch a new token if the current is not expired' do it 'should not fetch a new token if the current is not expired' do
token = '1/abcdef1234567890' token = '1/abcdef1234567890'
stubs = make_auth_stubs access_token: token stub = make_auth_stubs access_token: token
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
n = 5 # arbitrary n = 5 # arbitrary
n.times do |_t| n.times do |_t|
md = { foo: 'bar' } md = { foo: 'bar' }
got = @client.apply(md, connection: c) got = @client.apply(md)
want = { :foo => 'bar', auth_key => "Bearer #{token}" } want = { :foo => 'bar', auth_key => "Bearer #{token}" }
expect(got).to eq(want) expect(got).to eq(want)
end end
stubs.verify_stubbed_calls expect(stub).to have_been_requested
end end
it 'should fetch a new token if the current one is expired' do it 'should fetch a new token if the current one is expired' do
token_1 = '1/abcdef1234567890' token_1 = '1/abcdef1234567890'
token_2 = '2/abcdef1234567890' token_2 = '2/abcdef1234567891'
[token_1, token_2].each do |t| [token_1, token_2].each do |t|
stubs = make_auth_stubs access_token: t make_auth_stubs access_token: t
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
md = { foo: 'bar' } md = { foo: 'bar' }
got = @client.apply(md, connection: c) got = @client.apply(md)
want = { :foo => 'bar', auth_key => "Bearer #{t}" } want = { :foo => 'bar', auth_key => "Bearer #{t}" }
expect(got).to eq(want) expect(got).to eq(want)
stubs.verify_stubbed_calls
@client.expires_at -= 3601 # default is to expire in 1hr @client.expires_at -= 3601 # default is to expire in 1hr
end end
end end

View File

@ -37,7 +37,7 @@ require 'googleauth/compute_engine'
require 'spec_helper' require 'spec_helper'
describe Google::Auth::GCECredentials do describe Google::Auth::GCECredentials do
MD_URI = '/computeMetadata/v1/instance/service-accounts/default/token' MD_URI = 'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token'
GCECredentials = Google::Auth::GCECredentials GCECredentials = Google::Auth::GCECredentials
before(:example) do before(:example) do
@ -46,16 +46,14 @@ describe Google::Auth::GCECredentials do
def make_auth_stubs(opts = {}) def make_auth_stubs(opts = {})
access_token = opts[:access_token] || '' access_token = opts[:access_token] || ''
Faraday::Adapter::Test::Stubs.new do |stub| body = MultiJson.dump('access_token' => access_token,
stub.get(MD_URI) do |env| 'token_type' => 'Bearer',
headers = env[:request_headers] 'expires_in' => 3600)
expect(headers['Metadata-Flavor']).to eq('Google') stub_request(:get, MD_URI)
build_json_response( .with(headers: { 'Metadata-Flavor' => 'Google' })
'access_token' => access_token, .to_return(body: body,
'token_type' => 'Bearer', status: 200,
'expires_in' => 3600) headers: { 'Content-Type' => 'application/json' })
end
end
end end
it_behaves_like 'apply/apply! are OK' it_behaves_like 'apply/apply! are OK'
@ -63,83 +61,48 @@ describe Google::Auth::GCECredentials do
context 'metadata is unavailable' do context 'metadata is unavailable' do
describe '#fetch_access_token' do describe '#fetch_access_token' do
it 'should fail if the metadata request returns a 404' do it 'should fail if the metadata request returns a 404' do
stubs = Faraday::Adapter::Test::Stubs.new do |stub| stub = stub_request(:get, MD_URI)
stub.get(MD_URI) do |_env| .to_return(status: 404,
[404, headers: { 'Metadata-Flavor' => 'Google' })
{ 'Metadata-Flavor' => 'Google' }, blk = proc { @client.fetch_access_token! }
'']
end
end
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
blk = proc { @client.fetch_access_token!(connection: c) }
expect(&blk).to raise_error Signet::AuthorizationError expect(&blk).to raise_error Signet::AuthorizationError
stubs.verify_stubbed_calls expect(stub).to have_been_requested
end end
it 'should fail if the metadata request returns an unexpected code' do it 'should fail if the metadata request returns an unexpected code' do
stubs = Faraday::Adapter::Test::Stubs.new do |stub| stub = stub_request(:get, MD_URI)
stub.get(MD_URI) do |_env| .to_return(status: 503,
[503, headers: { 'Metadata-Flavor' => 'Google' })
{ 'Metadata-Flavor' => 'Google' }, blk = proc { @client.fetch_access_token! }
'']
end
end
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
blk = proc { @client.fetch_access_token!(connection: c) }
expect(&blk).to raise_error Signet::AuthorizationError expect(&blk).to raise_error Signet::AuthorizationError
stubs.verify_stubbed_calls expect(stub).to have_been_requested
end end
end end
end end
describe '#on_gce?' do describe '#on_gce?' do
it 'should be true when Metadata-Flavor is Google' do it 'should be true when Metadata-Flavor is Google' do
stubs = Faraday::Adapter::Test::Stubs.new do |stub| stub = stub_request(:get, 'http://169.254.169.254')
stub.get('/') do |_env| .to_return(status: 200,
[200, headers: { 'Metadata-Flavor' => 'Google' })
{ 'Metadata-Flavor' => 'Google' }, expect(GCECredentials.on_gce?({}, true)).to eq(true)
''] expect(stub).to have_been_requested
end
end
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
expect(GCECredentials.on_gce?(connection: c)).to eq(true)
stubs.verify_stubbed_calls
end end
it 'should be false when Metadata-Flavor is not Google' do it 'should be false when Metadata-Flavor is not Google' do
stubs = Faraday::Adapter::Test::Stubs.new do |stub| stub = stub_request(:get, 'http://169.254.169.254')
stub.get('/') do |_env| .to_return(status: 200,
[200, headers: { 'Metadata-Flavor' => 'NotGoogle' })
{ 'Metadata-Flavor' => 'NotGoogle' }, expect(GCECredentials.on_gce?({}, true)).to eq(false)
''] expect(stub).to have_been_requested
end
end
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
expect(GCECredentials.on_gce?(connection: c)).to eq(false)
stubs.verify_stubbed_calls
end end
it 'should be false if the response is not 200' do it 'should be false if the response is not 200' do
stubs = Faraday::Adapter::Test::Stubs.new do |stub| stub = stub_request(:get, 'http://169.254.169.254')
stub.get('/') do |_env| .to_return(status: 404,
[404, headers: { 'Metadata-Flavor' => 'NotGoogle' })
{ 'Metadata-Flavor' => 'Google' }, expect(GCECredentials.on_gce?({}, true)).to eq(false)
''] expect(stub).to have_been_requested
end
end
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
expect(GCECredentials.on_gce?(connection: c)).to eq(false)
stubs.verify_stubbed_calls
end end
end end
end end

View File

@ -37,6 +37,9 @@ require 'googleauth'
require 'spec_helper' require 'spec_helper'
describe '#get_application_default' do describe '#get_application_default' do
# Pass unique options each time to bypass memoization
let(:options) { |example| { dememoize: example } }
before(:example) do before(:example) do
@key = OpenSSL::PKey::RSA.new(2048) @key = OpenSSL::PKey::RSA.new(2048)
@var_name = ENV_VAR @var_name = ENV_VAR
@ -59,31 +62,24 @@ describe '#get_application_default' do
Dir.mktmpdir do |dir| Dir.mktmpdir do |dir|
key_path = File.join(dir, 'does-not-exist') key_path = File.join(dir, 'does-not-exist')
ENV[@var_name] = key_path ENV[@var_name] = key_path
expect { Google::Auth.get_application_default(@scope) } expect { Google::Auth.get_application_default(@scope, options) }
.to raise_error RuntimeError .to raise_error RuntimeError
end end
end end
it 'fails without default file or env if not on compute engine' do it 'fails without default file or env if not on compute engine' do
stubs = Faraday::Adapter::Test::Stubs.new do |stub| stub = stub_request(:get, 'http://169.254.169.254')
stub.get('/') do |_env| .to_return(status: 404,
[404, headers: { 'Metadata-Flavor' => 'NotGoogle' })
{ 'Metadata-Flavor' => 'Google' },
'']
end
end # GCE not detected
Dir.mktmpdir do |dir| Dir.mktmpdir do |dir|
ENV.delete(@var_name) unless ENV[@var_name].nil? # no env var ENV.delete(@var_name) unless ENV[@var_name].nil? # no env var
ENV['HOME'] = dir # no config present in this tmp dir ENV['HOME'] = dir # no config present in this tmp dir
c = Faraday.new do |b|
b.adapter(:test, stubs)
end
blk = proc do blk = proc do
Google::Auth.get_application_default(@scope, connection: c) Google::Auth.get_application_default(@scope, options)
end end
expect(&blk).to raise_error RuntimeError expect(&blk).to raise_error RuntimeError
end end
stubs.verify_stubbed_calls expect(stub).to have_been_requested
end end
end end
@ -94,7 +90,8 @@ describe '#get_application_default' do
FileUtils.mkdir_p(File.dirname(key_path)) FileUtils.mkdir_p(File.dirname(key_path))
File.write(key_path, cred_json_text) File.write(key_path, cred_json_text)
ENV[@var_name] = key_path ENV[@var_name] = key_path
expect(Google::Auth.get_application_default(@scope)).to_not be_nil expect(Google::Auth.get_application_default(@scope, options))
.to_not be_nil
end end
end end
@ -105,7 +102,8 @@ describe '#get_application_default' do
FileUtils.mkdir_p(File.dirname(key_path)) FileUtils.mkdir_p(File.dirname(key_path))
File.write(key_path, cred_json_text) File.write(key_path, cred_json_text)
ENV['HOME'] = dir ENV['HOME'] = dir
expect(Google::Auth.get_application_default(@scope)).to_not be_nil expect(Google::Auth.get_application_default(@scope, options))
.to_not be_nil
end end
end end
@ -116,30 +114,21 @@ describe '#get_application_default' do
FileUtils.mkdir_p(File.dirname(key_path)) FileUtils.mkdir_p(File.dirname(key_path))
File.write(key_path, cred_json_text) File.write(key_path, cred_json_text)
ENV['HOME'] = dir ENV['HOME'] = dir
expect(Google::Auth.get_application_default).to_not be_nil expect(Google::Auth.get_application_default(nil, options)).to_not be_nil
end end
end end
it 'succeeds without default file or env if on compute engine' do it 'succeeds without default file or env if on compute engine' do
stubs = Faraday::Adapter::Test::Stubs.new do |stub| stub = stub_request(:get, 'http://169.254.169.254')
stub.get('/') do |_env| .to_return(status: 200,
[200, headers: { 'Metadata-Flavor' => 'Google' })
{ 'Metadata-Flavor' => 'Google' },
'']
end
end # GCE detected
Dir.mktmpdir do |dir| Dir.mktmpdir do |dir|
ENV.delete(@var_name) unless ENV[@var_name].nil? # no env var ENV.delete(@var_name) unless ENV[@var_name].nil? # no env var
ENV['HOME'] = dir # no config present in this tmp dir ENV['HOME'] = dir # no config present in this tmp dir
c = Faraday.new do |b| creds = Google::Auth.get_application_default(@scope, options)
b.adapter(:test, stubs)
end
creds = Google::Auth.get_application_default(
@scope,
connection: c)
expect(creds).to_not be_nil expect(creds).to_not be_nil
end end
stubs.verify_stubbed_calls expect(stub).to have_been_requested
end end
it 'succeeds with system default file' do it 'succeeds with system default file' do
@ -148,7 +137,8 @@ describe '#get_application_default' do
key_path = File.join('/etc/google/auth/', CREDENTIALS_FILE_NAME) key_path = File.join('/etc/google/auth/', CREDENTIALS_FILE_NAME)
FileUtils.mkdir_p(File.dirname(key_path)) FileUtils.mkdir_p(File.dirname(key_path))
File.write(key_path, cred_json_text) File.write(key_path, cred_json_text)
expect(Google::Auth.get_application_default(@scope)).to_not be_nil expect(Google::Auth.get_application_default(@scope, options))
.to_not be_nil
File.delete(key_path) File.delete(key_path)
end end
end end
@ -161,7 +151,8 @@ describe '#get_application_default' do
ENV[CLIENT_SECRET_VAR] = cred_json[:client_secret] ENV[CLIENT_SECRET_VAR] = cred_json[:client_secret]
ENV[REFRESH_TOKEN_VAR] = cred_json[:refresh_token] ENV[REFRESH_TOKEN_VAR] = cred_json[:refresh_token]
ENV[ACCOUNT_TYPE_VAR] = cred_json[:type] ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
expect(Google::Auth.get_application_default(@scope)).to_not be_nil expect(Google::Auth.get_application_default(@scope, options))
.to_not be_nil
end end
end end
@ -225,7 +216,7 @@ describe '#get_application_default' do
File.write(key_path, cred_json_text) File.write(key_path, cred_json_text)
ENV[@var_name] = key_path ENV[@var_name] = key_path
blk = proc do blk = proc do
Google::Auth.get_application_default(@scope) Google::Auth.get_application_default(@scope, options)
end end
expect(&blk).to raise_error RuntimeError expect(&blk).to raise_error RuntimeError
end end
@ -239,7 +230,7 @@ describe '#get_application_default' do
File.write(key_path, cred_json_text) File.write(key_path, cred_json_text)
ENV['HOME'] = dir ENV['HOME'] = dir
blk = proc do blk = proc do
Google::Auth.get_application_default(@scope) Google::Auth.get_application_default(@scope, options)
end end
expect(&blk).to raise_error RuntimeError expect(&blk).to raise_error RuntimeError
end end
@ -249,7 +240,7 @@ describe '#get_application_default' do
ENV[PRIVATE_KEY_VAR] = cred_json[:private_key] ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email] ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
blk = proc do blk = proc do
Google::Auth.get_application_default(@scope) Google::Auth.get_application_default(@scope, options)
end end
expect(&blk).to raise_error RuntimeError expect(&blk).to raise_error RuntimeError
end end

View File

@ -129,16 +129,21 @@ describe Google::Auth::ServiceAccountCredentials do
def make_auth_stubs(opts = {}) def make_auth_stubs(opts = {})
access_token = opts[:access_token] || '' access_token = opts[:access_token] || ''
Faraday::Adapter::Test::Stubs.new do |stub| body = MultiJson.dump('access_token' => access_token,
stub.post('/oauth2/v3/token') do |env| 'token_type' => 'Bearer',
params = Addressable::URI.form_unencode(env[:body]) 'expires_in' => 3600)
_claim, _header = JWT.decode(params.assoc('assertion').last, blk = proc do |request|
@key.public_key) params = Addressable::URI.form_unencode(request.body)
want = ['grant_type', 'urn:ietf:params:oauth:grant-type:jwt-bearer'] _claim, _header = JWT.decode(params.assoc('assertion').last,
expect(params.assoc('grant_type')).to eq(want) @key.public_key)
build_access_token_json(access_token)
end
end end
stub_request(:post, 'https://www.googleapis.com/oauth2/v3/token')
.with(body: hash_including(
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer'),
&blk)
.to_return(body: body,
status: 200,
headers: { 'Content-Type' => 'application/json' })
end end
def cred_json_text def cred_json_text

View File

@ -50,16 +50,21 @@ describe Signet::OAuth2::Client do
def make_auth_stubs(opts) def make_auth_stubs(opts)
access_token = opts[:access_token] || '' access_token = opts[:access_token] || ''
Faraday::Adapter::Test::Stubs.new do |stub| body = MultiJson.dump('access_token' => access_token,
stub.post('/o/oauth2/token') do |env| 'token_type' => 'Bearer',
params = Addressable::URI.form_unencode(env[:body]) 'expires_in' => 3600)
_claim, _header = JWT.decode(params.assoc('assertion').last, blk = proc do |request|
@key.public_key) params = Addressable::URI.form_unencode(request.body)
want = ['grant_type', 'urn:ietf:params:oauth:grant-type:jwt-bearer'] _claim, _header = JWT.decode(params.assoc('assertion').last,
expect(params.assoc('grant_type')).to eq(want) @key.public_key)
build_access_token_json(access_token)
end
end end
stub_request(:post, 'https://accounts.google.com/o/oauth2/token')
.with(body: hash_including(
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer'),
&blk)
.to_return(body: body,
status: 200,
headers: { 'Content-Type' => 'application/json' })
end end
it_behaves_like 'apply/apply! are OK' it_behaves_like 'apply/apply! are OK'

View File

@ -65,14 +65,14 @@ describe Google::Auth::UserRefreshCredentials do
def make_auth_stubs(opts = {}) def make_auth_stubs(opts = {})
access_token = opts[:access_token] || '' access_token = opts[:access_token] || ''
Faraday::Adapter::Test::Stubs.new do |stub| body = MultiJson.dump('access_token' => access_token,
stub.post('/oauth2/v3/token') do |env| 'token_type' => 'Bearer',
params = Addressable::URI.form_unencode(env[:body]) 'expires_in' => 3600)
want = %w(grant_type refresh_token) stub_request(:post, 'https://www.googleapis.com/oauth2/v3/token')
expect(params.assoc('grant_type')).to eq(want) .with(body: hash_including('grant_type' => 'refresh_token'))
build_access_token_json(access_token) .to_return(body: body,
end status: 200,
end headers: { 'Content-Type' => 'application/json' })
end end
def cred_json_text(missing = nil) def cred_json_text(missing = nil)
@ -244,70 +244,50 @@ describe Google::Auth::UserRefreshCredentials do
end end
describe 'when revoking a refresh token' do describe 'when revoking a refresh token' do
let(:stubs) do let(:stub) do
Faraday::Adapter::Test::Stubs.new do |stub| stub_request(:get, 'https://accounts.google.com/o/oauth2/revoke' \
stub.get('/o/oauth2/revoke') do |env| '?token=refreshtoken')
expect(env.params['token']).to eql 'refreshtoken' .to_return(status: 200,
[200] headers: { 'Content-Type' => 'application/json' })
end
end
end
let(:connection) do
Faraday.new do |c|
c.adapter(:test, stubs)
end
end end
before(:example) do before(:example) do
@client.revoke!(connection: connection) stub
@client.revoke!
end end
it_behaves_like 'revoked token' it_behaves_like 'revoked token'
end end
describe 'when revoking an access token' do describe 'when revoking an access token' do
let(:stubs) do let(:stub) do
Faraday::Adapter::Test::Stubs.new do |stub| stub_request(:get, 'https://accounts.google.com/o/oauth2/revoke' \
stub.get('/o/oauth2/revoke') do |env| '?token=accesstoken')
expect(env.params['token']).to eql 'accesstoken' .to_return(status: 200,
[200] headers: { 'Content-Type' => 'application/json' })
end
end
end
let(:connection) do
Faraday.new do |c|
c.adapter(:test, stubs)
end
end end
before(:example) do before(:example) do
stub
@client.refresh_token = nil @client.refresh_token = nil
@client.access_token = 'accesstoken' @client.access_token = 'accesstoken'
@client.revoke!(connection: connection) @client.revoke!
end end
it_behaves_like 'revoked token' it_behaves_like 'revoked token'
end end
describe 'when revoking an invalid token' do describe 'when revoking an invalid token' do
let(:stubs) do let(:stub) do
Faraday::Adapter::Test::Stubs.new do |stub| stub_request(:get, 'https://accounts.google.com/o/oauth2/revoke' \
stub.get('/o/oauth2/revoke') do |_env| '?token=refreshtoken')
[400] .to_return(status: 400,
end headers: { 'Content-Type' => 'application/json' })
end
end
let(:connection) do
Faraday.new do |c|
c.adapter(:test, stubs)
end
end end
it 'raises an authorization error' do it 'raises an authorization error' do
expect { @client.revoke!(connection: connection) }.to raise_error( stub
expect { @client.revoke! }.to raise_error(
Signet::AuthorizationError) Signet::AuthorizationError)
end end
end end