Merge pull request #76 from shicholas/update_tests
added ruby 2.3 to travis w/ other small changes.
This commit is contained in:
commit
37ed189b2e
|
@ -1,6 +1,7 @@
|
||||||
sudo: false
|
sudo: false
|
||||||
language: ruby
|
language: ruby
|
||||||
rvm:
|
rvm:
|
||||||
|
- 2.3
|
||||||
- 2.2
|
- 2.2
|
||||||
- 2.0.0
|
- 2.0.0
|
||||||
- 2.1
|
- 2.1
|
||||||
|
|
|
@ -42,7 +42,7 @@ 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
|
||||||
NOT_FOUND_ERROR = <<END
|
NOT_FOUND_ERROR = <<END.freeze
|
||||||
Could not load the default credentials. Browse to
|
Could not load the default credentials. Browse to
|
||||||
https://developers.google.com/accounts/docs/application-default-credentials
|
https://developers.google.com/accounts/docs/application-default-credentials
|
||||||
for more information
|
for more information
|
||||||
|
@ -70,14 +70,14 @@ END
|
||||||
def self.read_creds
|
def self.read_creds
|
||||||
env_var = CredentialsLoader::ACCOUNT_TYPE_VAR
|
env_var = CredentialsLoader::ACCOUNT_TYPE_VAR
|
||||||
type = ENV[env_var]
|
type = ENV[env_var]
|
||||||
fail "#{env_var} is undefined in env" unless type
|
raise "#{env_var} is undefined in env" unless type
|
||||||
case type
|
case type
|
||||||
when 'service_account'
|
when 'service_account'
|
||||||
ServiceAccountCredentials
|
ServiceAccountCredentials
|
||||||
when 'authorized_user'
|
when 'authorized_user'
|
||||||
UserRefreshCredentials
|
UserRefreshCredentials
|
||||||
else
|
else
|
||||||
fail "credentials type '#{type}' is not supported"
|
raise "credentials type '#{type}' is not supported"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ END
|
||||||
def self.determine_creds_class(json_key_io)
|
def self.determine_creds_class(json_key_io)
|
||||||
json_key = MultiJson.load(json_key_io.read)
|
json_key = MultiJson.load(json_key_io.read)
|
||||||
key = 'type'
|
key = 'type'
|
||||||
fail "the json is missing the '#{key}' field" unless json_key.key?(key)
|
raise "the json is missing the '#{key}' field" unless json_key.key?(key)
|
||||||
type = json_key[key]
|
type = json_key[key]
|
||||||
case type
|
case type
|
||||||
when 'service_account'
|
when 'service_account'
|
||||||
|
@ -93,7 +93,7 @@ END
|
||||||
when 'authorized_user'
|
when 'authorized_user'
|
||||||
[json_key, UserRefreshCredentials]
|
[json_key, UserRefreshCredentials]
|
||||||
else
|
else
|
||||||
fail "credentials type '#{type}' is not supported"
|
raise "credentials type '#{type}' is not supported"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -116,7 +116,7 @@ END
|
||||||
DefaultCredentials.from_well_known_path(scope) ||
|
DefaultCredentials.from_well_known_path(scope) ||
|
||||||
DefaultCredentials.from_system_default_path(scope)
|
DefaultCredentials.from_system_default_path(scope)
|
||||||
return creds unless creds.nil?
|
return creds unless creds.nil?
|
||||||
fail NOT_FOUND_ERROR unless GCECredentials.on_gce?(options)
|
raise NOT_FOUND_ERROR unless GCECredentials.on_gce?(options)
|
||||||
GCECredentials.new
|
GCECredentials.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -34,12 +34,12 @@ module Google
|
||||||
# Representation of an application's identity for user authorization
|
# Representation of an application's identity for user authorization
|
||||||
# flows.
|
# flows.
|
||||||
class ClientId
|
class ClientId
|
||||||
INSTALLED_APP = 'installed'
|
INSTALLED_APP = 'installed'.freeze
|
||||||
WEB_APP = 'web'
|
WEB_APP = 'web'.freeze
|
||||||
CLIENT_ID = 'client_id'
|
CLIENT_ID = 'client_id'.freeze
|
||||||
CLIENT_SECRET = 'client_secret'
|
CLIENT_SECRET = 'client_secret'.freeze
|
||||||
MISSING_TOP_LEVEL_ELEMENT_ERROR =
|
MISSING_TOP_LEVEL_ELEMENT_ERROR =
|
||||||
"Expected top level property 'installed' or 'web' to be present."
|
"Expected top level property 'installed' or 'web' to be present.".freeze
|
||||||
|
|
||||||
# Text identifier of the client ID
|
# Text identifier of the client ID
|
||||||
# @return [String]
|
# @return [String]
|
||||||
|
@ -63,8 +63,8 @@ module Google
|
||||||
# & secrets in source. See {#from_file} to load from
|
# & secrets in source. See {#from_file} to load from
|
||||||
# `client_secrets.json` files.
|
# `client_secrets.json` files.
|
||||||
def initialize(id, secret)
|
def initialize(id, secret)
|
||||||
fail 'Client id can not be nil' if id.nil?
|
raise 'Client id can not be nil' if id.nil?
|
||||||
fail 'Client secret can not be nil' if secret.nil?
|
raise 'Client secret can not be nil' if secret.nil?
|
||||||
@id = id
|
@id = id
|
||||||
@secret = secret
|
@secret = secret
|
||||||
end
|
end
|
||||||
|
@ -76,7 +76,7 @@ module Google
|
||||||
# Path of file to read from
|
# Path of file to read from
|
||||||
# @return [Google::Auth::ClientID]
|
# @return [Google::Auth::ClientID]
|
||||||
def self.from_file(file)
|
def self.from_file(file)
|
||||||
fail 'File can not be nil.' if file.nil?
|
raise 'File can not be nil.' if file.nil?
|
||||||
File.open(file.to_s) do |f|
|
File.open(file.to_s) do |f|
|
||||||
json = f.read
|
json = f.read
|
||||||
config = MultiJson.load(json)
|
config = MultiJson.load(json)
|
||||||
|
@ -92,9 +92,9 @@ module Google
|
||||||
# Parsed contents of the JSON file
|
# Parsed contents of the JSON file
|
||||||
# @return [Google::Auth::ClientID]
|
# @return [Google::Auth::ClientID]
|
||||||
def self.from_hash(config)
|
def self.from_hash(config)
|
||||||
fail 'Hash can not be nil.' if config.nil?
|
raise 'Hash can not be nil.' if config.nil?
|
||||||
raw_detail = config[INSTALLED_APP] || config[WEB_APP]
|
raw_detail = config[INSTALLED_APP] || config[WEB_APP]
|
||||||
fail MISSING_TOP_LEVEL_ELEMENT_ERROR if raw_detail.nil?
|
raise MISSING_TOP_LEVEL_ELEMENT_ERROR if raw_detail.nil?
|
||||||
ClientId.new(raw_detail[CLIENT_ID], raw_detail[CLIENT_SECRET])
|
ClientId.new(raw_detail[CLIENT_ID], raw_detail[CLIENT_SECRET])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,13 +35,13 @@ 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
|
||||||
NO_METADATA_SERVER_ERROR = <<END
|
NO_METADATA_SERVER_ERROR = <<END.freeze
|
||||||
Error code 404 trying to get security access token
|
Error code 404 trying to get security access token
|
||||||
from Compute Engine metadata for the default service account. This
|
from Compute Engine metadata for the default service account. This
|
||||||
may be because the virtual machine instance does not have permission
|
may be because the virtual machine instance does not have permission
|
||||||
scopes specified.
|
scopes specified.
|
||||||
END
|
END
|
||||||
UNEXPECTED_ERROR_SUFFIX = <<END
|
UNEXPECTED_ERROR_SUFFIX = <<END.freeze
|
||||||
trying to get security access token from Compute Engine metadata for
|
trying to get security access token from Compute Engine metadata for
|
||||||
the default service account
|
the default service account
|
||||||
END
|
END
|
||||||
|
@ -52,8 +52,8 @@ END
|
||||||
# The IP Address is used in the URIs to speed up failures on non-GCE
|
# The IP Address is used in the URIs to speed up failures on non-GCE
|
||||||
# systems.
|
# systems.
|
||||||
COMPUTE_AUTH_TOKEN_URI = 'http://169.254.169.254/computeMetadata/v1/'\
|
COMPUTE_AUTH_TOKEN_URI = 'http://169.254.169.254/computeMetadata/v1/'\
|
||||||
'instance/service-accounts/default/token'
|
'instance/service-accounts/default/token'.freeze
|
||||||
COMPUTE_CHECK_URI = 'http://169.254.169.254'
|
COMPUTE_CHECK_URI = 'http://169.254.169.254'.freeze
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
extend Memoist
|
extend Memoist
|
||||||
|
@ -94,10 +94,10 @@ END
|
||||||
Signet::OAuth2.parse_credentials(resp.body,
|
Signet::OAuth2.parse_credentials(resp.body,
|
||||||
resp.headers['content-type'])
|
resp.headers['content-type'])
|
||||||
when 404
|
when 404
|
||||||
fail(Signet::AuthorizationError, NO_METADATA_SERVER_ERROR)
|
raise(Signet::AuthorizationError, NO_METADATA_SERVER_ERROR)
|
||||||
else
|
else
|
||||||
msg = "Unexpected error code #{resp.status}" + UNEXPECTED_ERROR_SUFFIX
|
msg = "Unexpected error code #{resp.status}" + UNEXPECTED_ERROR_SUFFIX
|
||||||
fail(Signet::AuthorizationError, msg)
|
raise(Signet::AuthorizationError, msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,22 +39,23 @@ module Google
|
||||||
# credentials files on the file system.
|
# credentials files on the file system.
|
||||||
module CredentialsLoader
|
module CredentialsLoader
|
||||||
extend Memoist
|
extend Memoist
|
||||||
ENV_VAR = 'GOOGLE_APPLICATION_CREDENTIALS'
|
ENV_VAR = 'GOOGLE_APPLICATION_CREDENTIALS'.freeze
|
||||||
|
|
||||||
PRIVATE_KEY_VAR = 'GOOGLE_PRIVATE_KEY'
|
PRIVATE_KEY_VAR = 'GOOGLE_PRIVATE_KEY'.freeze
|
||||||
CLIENT_EMAIL_VAR = 'GOOGLE_CLIENT_EMAIL'
|
CLIENT_EMAIL_VAR = 'GOOGLE_CLIENT_EMAIL'.freeze
|
||||||
CLIENT_ID_VAR = 'GOOGLE_CLIENT_ID'
|
CLIENT_ID_VAR = 'GOOGLE_CLIENT_ID'.freeze
|
||||||
CLIENT_SECRET_VAR = 'GOOGLE_CLIENT_SECRET'
|
CLIENT_SECRET_VAR = 'GOOGLE_CLIENT_SECRET'.freeze
|
||||||
REFRESH_TOKEN_VAR = 'GOOGLE_REFRESH_TOKEN'
|
REFRESH_TOKEN_VAR = 'GOOGLE_REFRESH_TOKEN'.freeze
|
||||||
ACCOUNT_TYPE_VAR = 'GOOGLE_ACCOUNT_TYPE'
|
ACCOUNT_TYPE_VAR = 'GOOGLE_ACCOUNT_TYPE'.freeze
|
||||||
|
|
||||||
CREDENTIALS_FILE_NAME = 'application_default_credentials.json'
|
CREDENTIALS_FILE_NAME = 'application_default_credentials.json'.freeze
|
||||||
NOT_FOUND_ERROR =
|
NOT_FOUND_ERROR =
|
||||||
"Unable to read the credential file specified by #{ENV_VAR}"
|
"Unable to read the credential file specified by #{ENV_VAR}".freeze
|
||||||
WELL_KNOWN_PATH = "gcloud/#{CREDENTIALS_FILE_NAME}"
|
WELL_KNOWN_PATH = "gcloud/#{CREDENTIALS_FILE_NAME}".freeze
|
||||||
WELL_KNOWN_ERROR = 'Unable to read the default credential file'
|
WELL_KNOWN_ERROR = 'Unable to read the default credential file'.freeze
|
||||||
|
|
||||||
SYSTEM_DEFAULT_ERROR = 'Unable to read the system default credential file'
|
SYSTEM_DEFAULT_ERROR =
|
||||||
|
'Unable to read the system default credential file'.freeze
|
||||||
|
|
||||||
# make_creds proxies the construction of a credentials instance
|
# make_creds proxies the construction of a credentials instance
|
||||||
#
|
#
|
||||||
|
@ -71,7 +72,7 @@ module Google
|
||||||
def from_env(scope = nil)
|
def from_env(scope = nil)
|
||||||
if ENV.key?(ENV_VAR)
|
if ENV.key?(ENV_VAR)
|
||||||
path = ENV[ENV_VAR]
|
path = ENV[ENV_VAR]
|
||||||
fail "file #{path} does not exist" unless File.exist?(path)
|
raise "file #{path} does not exist" unless File.exist?(path)
|
||||||
File.open(path) do |f|
|
File.open(path) do |f|
|
||||||
return make_creds(json_key_io: f, scope: scope)
|
return make_creds(json_key_io: f, scope: scope)
|
||||||
end
|
end
|
||||||
|
|
|
@ -37,16 +37,16 @@ module Google
|
||||||
module Auth
|
module Auth
|
||||||
# Authenticates requests using IAM credentials.
|
# Authenticates requests using IAM credentials.
|
||||||
class IAMCredentials
|
class IAMCredentials
|
||||||
SELECTOR_KEY = 'x-goog-iam-authority-selector'
|
SELECTOR_KEY = 'x-goog-iam-authority-selector'.freeze
|
||||||
TOKEN_KEY = 'x-goog-iam-authorization-token'
|
TOKEN_KEY = 'x-goog-iam-authorization-token'.freeze
|
||||||
|
|
||||||
# Initializes an IAMCredentials.
|
# Initializes an IAMCredentials.
|
||||||
#
|
#
|
||||||
# @param selector the IAM selector.
|
# @param selector the IAM selector.
|
||||||
# @param token the IAM token.
|
# @param token the IAM token.
|
||||||
def initialize(selector, token)
|
def initialize(selector, token)
|
||||||
fail TypeError unless selector.is_a? String
|
raise TypeError unless selector.is_a? String
|
||||||
fail TypeError unless token.is_a? String
|
raise TypeError unless token.is_a? String
|
||||||
@selector = selector
|
@selector = selector
|
||||||
@token = token
|
@token = token
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,7 +39,7 @@ module Google
|
||||||
'email' => 'https://www.googleapis.com/auth/userinfo.email',
|
'email' => 'https://www.googleapis.com/auth/userinfo.email',
|
||||||
'profile' => 'https://www.googleapis.com/auth/userinfo.profile',
|
'profile' => 'https://www.googleapis.com/auth/userinfo.profile',
|
||||||
'openid' => 'https://www.googleapis.com/auth/plus.me'
|
'openid' => 'https://www.googleapis.com/auth/plus.me'
|
||||||
}
|
}.freeze
|
||||||
|
|
||||||
def self.normalize(scope)
|
def self.normalize(scope)
|
||||||
list = as_array(scope)
|
list = as_array(scope)
|
||||||
|
@ -53,7 +53,7 @@ module Google
|
||||||
when String
|
when String
|
||||||
scope.split(' ')
|
scope.split(' ')
|
||||||
else
|
else
|
||||||
fail 'Invalid scope value. Must be string or array'
|
raise 'Invalid scope value. Must be string or array'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -46,7 +46,7 @@ module Google
|
||||||
#
|
#
|
||||||
# cf [Application Default Credentials](http://goo.gl/mkAHpZ)
|
# cf [Application Default Credentials](http://goo.gl/mkAHpZ)
|
||||||
class ServiceAccountCredentials < Signet::OAuth2::Client
|
class ServiceAccountCredentials < Signet::OAuth2::Client
|
||||||
TOKEN_CRED_URI = 'https://www.googleapis.com/oauth2/v3/token'
|
TOKEN_CRED_URI = 'https://www.googleapis.com/oauth2/v3/token'.freeze
|
||||||
extend CredentialsLoader
|
extend CredentialsLoader
|
||||||
|
|
||||||
# Creates a ServiceAccountCredentials.
|
# Creates a ServiceAccountCredentials.
|
||||||
|
@ -73,8 +73,8 @@ module Google
|
||||||
# JSON key.
|
# JSON key.
|
||||||
def self.read_json_key(json_key_io)
|
def self.read_json_key(json_key_io)
|
||||||
json_key = MultiJson.load(json_key_io.read)
|
json_key = MultiJson.load(json_key_io.read)
|
||||||
fail 'missing client_email' unless json_key.key?('client_email')
|
raise 'missing client_email' unless json_key.key?('client_email')
|
||||||
fail 'missing private_key' unless json_key.key?('private_key')
|
raise 'missing private_key' unless json_key.key?('private_key')
|
||||||
[json_key['private_key'], json_key['client_email']]
|
[json_key['private_key'], json_key['client_email']]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -119,8 +119,8 @@ module Google
|
||||||
class ServiceAccountJwtHeaderCredentials
|
class ServiceAccountJwtHeaderCredentials
|
||||||
JWT_AUD_URI_KEY = :jwt_aud_uri
|
JWT_AUD_URI_KEY = :jwt_aud_uri
|
||||||
AUTH_METADATA_KEY = Signet::OAuth2::AUTH_METADATA_KEY
|
AUTH_METADATA_KEY = Signet::OAuth2::AUTH_METADATA_KEY
|
||||||
TOKEN_CRED_URI = 'https://www.googleapis.com/oauth2/v3/token'
|
TOKEN_CRED_URI = 'https://www.googleapis.com/oauth2/v3/token'.freeze
|
||||||
SIGNING_ALGORITHM = 'RS256'
|
SIGNING_ALGORITHM = 'RS256'.freeze
|
||||||
EXPIRY = 60
|
EXPIRY = 60
|
||||||
extend CredentialsLoader
|
extend CredentialsLoader
|
||||||
|
|
||||||
|
@ -139,8 +139,8 @@ module Google
|
||||||
# JSON key.
|
# JSON key.
|
||||||
def self.read_json_key(json_key_io)
|
def self.read_json_key(json_key_io)
|
||||||
json_key = MultiJson.load(json_key_io.read)
|
json_key = MultiJson.load(json_key_io.read)
|
||||||
fail 'missing client_email' unless json_key.key?('client_email')
|
raise 'missing client_email' unless json_key.key?('client_email')
|
||||||
fail 'missing private_key' unless json_key.key?('private_key')
|
raise 'missing private_key' unless json_key.key?('private_key')
|
||||||
[json_key['private_key'], json_key['client_email']]
|
[json_key['private_key'], json_key['client_email']]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ module Signet
|
||||||
@refresh_listeners << block
|
@refresh_listeners << block
|
||||||
end
|
end
|
||||||
|
|
||||||
alias_method :orig_fetch_access_token!, :fetch_access_token!
|
alias 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
|
||||||
|
|
|
@ -37,7 +37,7 @@ module Google
|
||||||
# are stored as JSON using the supplied key, prefixed with
|
# are stored as JSON using the supplied key, prefixed with
|
||||||
# `g-user-token:`
|
# `g-user-token:`
|
||||||
class RedisTokenStore < Google::Auth::TokenStore
|
class RedisTokenStore < Google::Auth::TokenStore
|
||||||
DEFAULT_KEY_PREFIX = 'g-user-token:'
|
DEFAULT_KEY_PREFIX = 'g-user-token:'.freeze
|
||||||
|
|
||||||
# Create a new store with the supplied redis client.
|
# Create a new store with the supplied redis client.
|
||||||
#
|
#
|
||||||
|
@ -51,12 +51,12 @@ module Google
|
||||||
def initialize(options = {})
|
def initialize(options = {})
|
||||||
redis = options.delete(:redis)
|
redis = options.delete(:redis)
|
||||||
prefix = options.delete(:prefix)
|
prefix = options.delete(:prefix)
|
||||||
case redis
|
@redis = case redis
|
||||||
when Redis
|
when Redis
|
||||||
@redis = redis
|
redis
|
||||||
else
|
else
|
||||||
@redis = Redis.new(options)
|
Redis.new(options)
|
||||||
end
|
end
|
||||||
@prefix = prefix || DEFAULT_KEY_PREFIX
|
@prefix = prefix || DEFAULT_KEY_PREFIX
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ module Google
|
||||||
# @return [String]
|
# @return [String]
|
||||||
# The loaded token data.
|
# The loaded token data.
|
||||||
def load(_id)
|
def load(_id)
|
||||||
fail 'Not implemented'
|
raise 'Not implemented'
|
||||||
end
|
end
|
||||||
|
|
||||||
# Put the token data into storage for the given ID.
|
# Put the token data into storage for the given ID.
|
||||||
|
@ -54,7 +54,7 @@ module Google
|
||||||
# @param [String] token
|
# @param [String] token
|
||||||
# The token data to store.
|
# The token data to store.
|
||||||
def store(_id, _token)
|
def store(_id, _token)
|
||||||
fail 'Not implemented'
|
raise 'Not implemented'
|
||||||
end
|
end
|
||||||
|
|
||||||
# Remove the token data from storage for the given ID.
|
# Remove the token data from storage for the given ID.
|
||||||
|
@ -62,7 +62,7 @@ module Google
|
||||||
# @param [String] id
|
# @param [String] id
|
||||||
# ID of the token data to delete
|
# ID of the token data to delete
|
||||||
def delete(_id)
|
def delete(_id)
|
||||||
fail 'Not implemented'
|
raise 'Not implemented'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -32,6 +32,7 @@ require 'multi_json'
|
||||||
require 'googleauth/signet'
|
require 'googleauth/signet'
|
||||||
require 'googleauth/user_refresh'
|
require 'googleauth/user_refresh'
|
||||||
|
|
||||||
|
# rubocop:disable ClassLength
|
||||||
module Google
|
module Google
|
||||||
module Auth
|
module Auth
|
||||||
# Handles an interactive 3-Legged-OAuth2 (3LO) user consent authorization.
|
# Handles an interactive 3-Legged-OAuth2 (3LO) user consent authorization.
|
||||||
|
@ -53,13 +54,13 @@ module Google
|
||||||
# ...
|
# ...
|
||||||
class UserAuthorizer
|
class UserAuthorizer
|
||||||
MISMATCHED_CLIENT_ID_ERROR =
|
MISMATCHED_CLIENT_ID_ERROR =
|
||||||
'Token client ID of %s does not match configured client id %s'
|
'Token client ID of %s does not match configured client id %s'.freeze
|
||||||
NIL_CLIENT_ID_ERROR = 'Client id can not be nil.'
|
NIL_CLIENT_ID_ERROR = 'Client id can not be nil.'.freeze
|
||||||
NIL_SCOPE_ERROR = 'Scope can not be nil.'
|
NIL_SCOPE_ERROR = 'Scope can not be nil.'.freeze
|
||||||
NIL_USER_ID_ERROR = 'User ID can not be nil.'
|
NIL_USER_ID_ERROR = 'User ID can not be nil.'.freeze
|
||||||
NIL_TOKEN_STORE_ERROR = 'Can not call method if token store is nil'
|
NIL_TOKEN_STORE_ERROR = 'Can not call method if token store is nil'.freeze
|
||||||
MISSING_ABSOLUTE_URL_ERROR =
|
MISSING_ABSOLUTE_URL_ERROR =
|
||||||
'Absolute base url required for relative callback url "%s"'
|
'Absolute base url required for relative callback url "%s"'.freeze
|
||||||
|
|
||||||
# Initialize the authorizer
|
# Initialize the authorizer
|
||||||
#
|
#
|
||||||
|
@ -73,8 +74,8 @@ module Google
|
||||||
# URL (either absolute or relative) of the auth callback.
|
# URL (either absolute or relative) of the auth callback.
|
||||||
# Defaults to '/oauth2callback'
|
# Defaults to '/oauth2callback'
|
||||||
def initialize(client_id, scope, token_store, callback_uri = nil)
|
def initialize(client_id, scope, token_store, callback_uri = nil)
|
||||||
fail NIL_CLIENT_ID_ERROR if client_id.nil?
|
raise NIL_CLIENT_ID_ERROR if client_id.nil?
|
||||||
fail NIL_SCOPE_ERROR if scope.nil?
|
raise NIL_SCOPE_ERROR if scope.nil?
|
||||||
|
|
||||||
@client_id = client_id
|
@client_id = client_id
|
||||||
@scope = Array(scope)
|
@scope = Array(scope)
|
||||||
|
@ -102,7 +103,8 @@ module Google
|
||||||
credentials = UserRefreshCredentials.new(
|
credentials = UserRefreshCredentials.new(
|
||||||
client_id: @client_id.id,
|
client_id: @client_id.id,
|
||||||
client_secret: @client_id.secret,
|
client_secret: @client_id.secret,
|
||||||
scope: scope)
|
scope: scope
|
||||||
|
)
|
||||||
redirect_uri = redirect_uri_for(options[:base_url])
|
redirect_uri = redirect_uri_for(options[:base_url])
|
||||||
url = credentials.authorization_uri(access_type: 'offline',
|
url = credentials.authorization_uri(access_type: 'offline',
|
||||||
redirect_uri: redirect_uri,
|
redirect_uri: redirect_uri,
|
||||||
|
@ -123,8 +125,8 @@ module Google
|
||||||
# @return [Google::Auth::UserRefreshCredentials]
|
# @return [Google::Auth::UserRefreshCredentials]
|
||||||
# Stored credentials, nil if none present
|
# Stored credentials, nil if none present
|
||||||
def get_credentials(user_id, scope = nil)
|
def get_credentials(user_id, scope = nil)
|
||||||
fail NIL_USER_ID_ERROR if user_id.nil?
|
raise NIL_USER_ID_ERROR if user_id.nil?
|
||||||
fail NIL_TOKEN_STORE_ERROR if @token_store.nil?
|
raise NIL_TOKEN_STORE_ERROR if @token_store.nil?
|
||||||
|
|
||||||
scope ||= @scope
|
scope ||= @scope
|
||||||
saved_token = @token_store.load(user_id)
|
saved_token = @token_store.load(user_id)
|
||||||
|
@ -132,8 +134,8 @@ module Google
|
||||||
data = MultiJson.load(saved_token)
|
data = MultiJson.load(saved_token)
|
||||||
|
|
||||||
if data.fetch('client_id', @client_id.id) != @client_id.id
|
if data.fetch('client_id', @client_id.id) != @client_id.id
|
||||||
fail sprintf(MISMATCHED_CLIENT_ID_ERROR,
|
raise sprintf(MISMATCHED_CLIENT_ID_ERROR,
|
||||||
data['client_id'], @client_id.id)
|
data['client_id'], @client_id.id)
|
||||||
end
|
end
|
||||||
|
|
||||||
credentials = UserRefreshCredentials.new(
|
credentials = UserRefreshCredentials.new(
|
||||||
|
@ -142,10 +144,10 @@ module Google
|
||||||
scope: data['scope'] || @scope,
|
scope: data['scope'] || @scope,
|
||||||
access_token: data['access_token'],
|
access_token: data['access_token'],
|
||||||
refresh_token: data['refresh_token'],
|
refresh_token: data['refresh_token'],
|
||||||
expires_at: data.fetch('expiration_time_millis', 0) / 1000)
|
expires_at: data.fetch('expiration_time_millis', 0) / 1000
|
||||||
|
)
|
||||||
if credentials.includes_scope?(scope)
|
if credentials.includes_scope?(scope)
|
||||||
monitor_credentials(user_id, credentials)
|
return monitor_credentials(user_id, credentials)
|
||||||
return credentials
|
|
||||||
end
|
end
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
@ -174,7 +176,8 @@ module Google
|
||||||
client_id: @client_id.id,
|
client_id: @client_id.id,
|
||||||
client_secret: @client_id.secret,
|
client_secret: @client_id.secret,
|
||||||
redirect_uri: redirect_uri_for(base_url),
|
redirect_uri: redirect_uri_for(base_url),
|
||||||
scope: scope)
|
scope: scope
|
||||||
|
)
|
||||||
credentials.code = code
|
credentials.code = code
|
||||||
credentials.fetch_access_token!({})
|
credentials.fetch_access_token!({})
|
||||||
monitor_credentials(user_id, credentials)
|
monitor_credentials(user_id, credentials)
|
||||||
|
@ -234,7 +237,8 @@ module Google
|
||||||
access_token: credentials.access_token,
|
access_token: credentials.access_token,
|
||||||
refresh_token: credentials.refresh_token,
|
refresh_token: credentials.refresh_token,
|
||||||
scope: credentials.scope,
|
scope: credentials.scope,
|
||||||
expiration_time_millis: (credentials.expires_at.to_i) * 1000)
|
expiration_time_millis: credentials.expires_at.to_i * 1000
|
||||||
|
)
|
||||||
@token_store.store(user_id, json)
|
@token_store.store(user_id, json)
|
||||||
credentials
|
credentials
|
||||||
end
|
end
|
||||||
|
@ -263,11 +267,13 @@ module Google
|
||||||
# Redirect URI
|
# Redirect URI
|
||||||
def redirect_uri_for(base_url)
|
def redirect_uri_for(base_url)
|
||||||
return @callback_uri unless URI(@callback_uri).scheme.nil?
|
return @callback_uri unless URI(@callback_uri).scheme.nil?
|
||||||
fail sprintf(
|
raise sprintf(
|
||||||
MISSING_ABSOLUTE_URL_ERROR,
|
MISSING_ABSOLUTE_URL_ERROR,
|
||||||
@callback_uri) if base_url.nil? || URI(base_url).scheme.nil?
|
@callback_uri
|
||||||
|
) if base_url.nil? || URI(base_url).scheme.nil?
|
||||||
URI.join(base_url, @callback_uri).to_s
|
URI.join(base_url, @callback_uri).to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
# rubocop:enable ClassLength
|
||||||
|
|
|
@ -46,9 +46,9 @@ module Google
|
||||||
#
|
#
|
||||||
# cf [Application Default Credentials](http://goo.gl/mkAHpZ)
|
# cf [Application Default Credentials](http://goo.gl/mkAHpZ)
|
||||||
class UserRefreshCredentials < Signet::OAuth2::Client
|
class UserRefreshCredentials < Signet::OAuth2::Client
|
||||||
TOKEN_CRED_URI = 'https://www.googleapis.com/oauth2/v3/token'
|
TOKEN_CRED_URI = 'https://www.googleapis.com/oauth2/v3/token'.freeze
|
||||||
AUTHORIZATION_URI = 'https://accounts.google.com/o/oauth2/auth'
|
AUTHORIZATION_URI = 'https://accounts.google.com/o/oauth2/auth'.freeze
|
||||||
REVOKE_TOKEN_URI = 'https://accounts.google.com/o/oauth2/revoke'
|
REVOKE_TOKEN_URI = 'https://accounts.google.com/o/oauth2/revoke'.freeze
|
||||||
extend CredentialsLoader
|
extend CredentialsLoader
|
||||||
|
|
||||||
# Create a UserRefreshCredentials.
|
# Create a UserRefreshCredentials.
|
||||||
|
@ -77,7 +77,7 @@ module Google
|
||||||
json_key = MultiJson.load(json_key_io.read)
|
json_key = MultiJson.load(json_key_io.read)
|
||||||
wanted = %w(client_id client_secret refresh_token)
|
wanted = %w(client_id client_secret refresh_token)
|
||||||
wanted.each do |key|
|
wanted.each do |key|
|
||||||
fail "the json is missing the #{key} field" unless json_key.key?(key)
|
raise "the json is missing the #{key} field" unless json_key.key?(key)
|
||||||
end
|
end
|
||||||
json_key
|
json_key
|
||||||
end
|
end
|
||||||
|
@ -99,8 +99,8 @@ module Google
|
||||||
self.refresh_token = nil
|
self.refresh_token = nil
|
||||||
self.expires_at = 0
|
self.expires_at = 0
|
||||||
else
|
else
|
||||||
fail(Signet::AuthorizationError,
|
raise(Signet::AuthorizationError,
|
||||||
"Unexpected error code #{resp.status}")
|
"Unexpected error code #{resp.status}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -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.5.1'
|
VERSION = '0.5.2'.freeze
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -66,20 +66,21 @@ module Google
|
||||||
# @see {Google::Auth::ControllerHelpers}
|
# @see {Google::Auth::ControllerHelpers}
|
||||||
# @note Requires sessions are enabled
|
# @note Requires sessions are enabled
|
||||||
class WebUserAuthorizer < Google::Auth::UserAuthorizer
|
class WebUserAuthorizer < Google::Auth::UserAuthorizer
|
||||||
STATE_PARAM = 'state'
|
STATE_PARAM = 'state'.freeze
|
||||||
AUTH_CODE_KEY = 'code'
|
AUTH_CODE_KEY = 'code'.freeze
|
||||||
ERROR_CODE_KEY = 'error'
|
ERROR_CODE_KEY = 'error'.freeze
|
||||||
SESSION_ID_KEY = 'session_id'
|
SESSION_ID_KEY = 'session_id'.freeze
|
||||||
CALLBACK_STATE_KEY = 'g-auth-callback'
|
CALLBACK_STATE_KEY = 'g-auth-callback'.freeze
|
||||||
CURRENT_URI_KEY = 'current_uri'
|
CURRENT_URI_KEY = 'current_uri'.freeze
|
||||||
XSRF_KEY = 'g-xsrf-token'
|
XSRF_KEY = 'g-xsrf-token'.freeze
|
||||||
SCOPE_KEY = 'scope'
|
SCOPE_KEY = 'scope'.freeze
|
||||||
|
|
||||||
NIL_REQUEST_ERROR = 'Request is required.'
|
NIL_REQUEST_ERROR = 'Request is required.'.freeze
|
||||||
NIL_SESSION_ERROR = 'Sessions must be enabled'
|
NIL_SESSION_ERROR = 'Sessions must be enabled'.freeze
|
||||||
MISSING_AUTH_CODE_ERROR = 'Missing authorization code in request'
|
MISSING_AUTH_CODE_ERROR = 'Missing authorization code in request'.freeze
|
||||||
AUTHORIZATION_ERROR = 'Authorization error: %s'
|
AUTHORIZATION_ERROR = 'Authorization error: %s'.freeze
|
||||||
INVALID_STATE_TOKEN_ERROR = 'State token does not match expected value'
|
INVALID_STATE_TOKEN_ERROR =
|
||||||
|
'State token does not match expected value'.freeze
|
||||||
|
|
||||||
class << self
|
class << self
|
||||||
attr_accessor :default
|
attr_accessor :default
|
||||||
|
@ -128,13 +129,15 @@ module Google
|
||||||
# credentials & next URL to redirect to
|
# credentials & next URL to redirect to
|
||||||
def handle_auth_callback(user_id, request)
|
def handle_auth_callback(user_id, request)
|
||||||
callback_state, redirect_uri = WebUserAuthorizer.extract_callback_state(
|
callback_state, redirect_uri = WebUserAuthorizer.extract_callback_state(
|
||||||
request)
|
request
|
||||||
|
)
|
||||||
WebUserAuthorizer.validate_callback_state(callback_state, request)
|
WebUserAuthorizer.validate_callback_state(callback_state, request)
|
||||||
credentials = get_and_store_credentials_from_code(
|
credentials = get_and_store_credentials_from_code(
|
||||||
user_id: user_id,
|
user_id: user_id,
|
||||||
code: callback_state[AUTH_CODE_KEY],
|
code: callback_state[AUTH_CODE_KEY],
|
||||||
scope: callback_state[SCOPE_KEY],
|
scope: callback_state[SCOPE_KEY],
|
||||||
base_url: request.url)
|
base_url: request.url
|
||||||
|
)
|
||||||
[credentials, redirect_uri]
|
[credentials, redirect_uri]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -156,14 +159,15 @@ module Google
|
||||||
def get_authorization_url(options = {})
|
def get_authorization_url(options = {})
|
||||||
options = options.dup
|
options = options.dup
|
||||||
request = options[:request]
|
request = options[:request]
|
||||||
fail NIL_REQUEST_ERROR if request.nil?
|
raise NIL_REQUEST_ERROR if request.nil?
|
||||||
fail NIL_SESSION_ERROR if request.session.nil?
|
raise NIL_SESSION_ERROR if request.session.nil?
|
||||||
|
|
||||||
redirect_to = options[:redirect_to] || request.url
|
redirect_to = options[:redirect_to] || request.url
|
||||||
request.session[XSRF_KEY] = SecureRandom.base64
|
request.session[XSRF_KEY] = SecureRandom.base64
|
||||||
options[:state] = MultiJson.dump(
|
options[:state] = MultiJson.dump(
|
||||||
SESSION_ID_KEY => request.session[XSRF_KEY],
|
SESSION_ID_KEY => request.session[XSRF_KEY],
|
||||||
CURRENT_URI_KEY => redirect_to)
|
CURRENT_URI_KEY => redirect_to
|
||||||
|
)
|
||||||
options[:base_url] = request.url
|
options[:base_url] = request.url
|
||||||
super(options)
|
super(options)
|
||||||
end
|
end
|
||||||
|
@ -193,7 +197,8 @@ module Google
|
||||||
user_id: user_id,
|
user_id: user_id,
|
||||||
code: callback_state[AUTH_CODE_KEY],
|
code: callback_state[AUTH_CODE_KEY],
|
||||||
scope: callback_state[SCOPE_KEY],
|
scope: callback_state[SCOPE_KEY],
|
||||||
base_url: request.url)
|
base_url: request.url
|
||||||
|
)
|
||||||
else
|
else
|
||||||
super(user_id, scope)
|
super(user_id, scope)
|
||||||
end
|
end
|
||||||
|
@ -204,7 +209,7 @@ module Google
|
||||||
redirect_uri = state[CURRENT_URI_KEY]
|
redirect_uri = state[CURRENT_URI_KEY]
|
||||||
callback_state = {
|
callback_state = {
|
||||||
AUTH_CODE_KEY => request[AUTH_CODE_KEY],
|
AUTH_CODE_KEY => request[AUTH_CODE_KEY],
|
||||||
ERROR_CODE_KEY => request[ERROR_CODE_KEY],
|
ERROR_CODE_KEY => request[ERROR_CODE_KEY],
|
||||||
SESSION_ID_KEY => state[SESSION_ID_KEY],
|
SESSION_ID_KEY => state[SESSION_ID_KEY],
|
||||||
SCOPE_KEY => request[SCOPE_KEY]
|
SCOPE_KEY => request[SCOPE_KEY]
|
||||||
}
|
}
|
||||||
|
@ -223,12 +228,12 @@ module Google
|
||||||
# Current request
|
# Current request
|
||||||
def self.validate_callback_state(state, request)
|
def self.validate_callback_state(state, request)
|
||||||
if state[AUTH_CODE_KEY].nil?
|
if state[AUTH_CODE_KEY].nil?
|
||||||
fail Signet::AuthorizationError, MISSING_AUTH_CODE_ERROR
|
raise Signet::AuthorizationError, MISSING_AUTH_CODE_ERROR
|
||||||
elsif state[ERROR_CODE_KEY]
|
elsif state[ERROR_CODE_KEY]
|
||||||
fail Signet::AuthorizationError,
|
raise Signet::AuthorizationError,
|
||||||
sprintf(AUTHORIZATION_ERROR, state[ERROR_CODE_KEY])
|
sprintf(AUTHORIZATION_ERROR, state[ERROR_CODE_KEY])
|
||||||
elsif request.session[XSRF_KEY] != state[SESSION_ID_KEY]
|
elsif request.session[XSRF_KEY] != state[SESSION_ID_KEY]
|
||||||
fail Signet::AuthorizationError, INVALID_STATE_TOKEN_ERROR
|
raise Signet::AuthorizationError, INVALID_STATE_TOKEN_ERROR
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -254,7 +259,7 @@ module Google
|
||||||
#
|
#
|
||||||
# @see {Google::Auth::WebUserAuthorizer}
|
# @see {Google::Auth::WebUserAuthorizer}
|
||||||
class CallbackApp
|
class CallbackApp
|
||||||
LOCATION_HEADER = 'Location'
|
LOCATION_HEADER = 'Location'.freeze
|
||||||
REDIR_STATUS = 302
|
REDIR_STATUS = 302
|
||||||
ERROR_STATUS = 500
|
ERROR_STATUS = 500
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,8 @@ shared_examples 'apply/apply! are OK' do
|
||||||
@client.on_refresh(&b)
|
@client.on_refresh(&b)
|
||||||
@client.fetch_access_token!
|
@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'
|
||||||
|
))
|
||||||
expect(stub).to have_been_requested
|
expect(stub).to have_been_requested
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -104,7 +104,8 @@ describe Google::Auth::ClientId do
|
||||||
|
|
||||||
it 'should raise error' do
|
it 'should raise error' do
|
||||||
expect { Google::Auth::ClientId.from_hash(config) }.to raise_error(
|
expect { Google::Auth::ClientId.from_hash(config) }.to raise_error(
|
||||||
/Expected top level property/)
|
/Expected top level property/
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -119,7 +120,8 @@ describe Google::Auth::ClientId do
|
||||||
|
|
||||||
it 'should raise error' do
|
it 'should raise error' do
|
||||||
expect { Google::Auth::ClientId.from_hash(config) }.to raise_error(
|
expect { Google::Auth::ClientId.from_hash(config) }.to raise_error(
|
||||||
/Client id can not be nil/)
|
/Client id can not be nil/
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -134,7 +136,8 @@ describe Google::Auth::ClientId do
|
||||||
|
|
||||||
it 'should raise error' do
|
it 'should raise error' do
|
||||||
expect { Google::Auth::ClientId.from_hash(config) }.to raise_error(
|
expect { Google::Auth::ClientId.from_hash(config) }.to raise_error(
|
||||||
/Client secret can not be nil/)
|
/Client secret can not be nil/
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -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 = 'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token'
|
MD_URI = 'http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token'.freeze
|
||||||
GCECredentials = Google::Auth::GCECredentials
|
GCECredentials = Google::Auth::GCECredentials
|
||||||
|
|
||||||
before(:example) do
|
before(:example) do
|
||||||
|
@ -64,8 +64,8 @@ describe Google::Auth::GCECredentials do
|
||||||
stub = stub_request(:get, MD_URI)
|
stub = stub_request(:get, MD_URI)
|
||||||
.to_return(status: 404,
|
.to_return(status: 404,
|
||||||
headers: { 'Metadata-Flavor' => 'Google' })
|
headers: { 'Metadata-Flavor' => 'Google' })
|
||||||
blk = proc { @client.fetch_access_token! }
|
expect { @client.fetch_access_token! }
|
||||||
expect(&blk).to raise_error Signet::AuthorizationError
|
.to raise_error Signet::AuthorizationError
|
||||||
expect(stub).to have_been_requested
|
expect(stub).to have_been_requested
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -73,8 +73,8 @@ describe Google::Auth::GCECredentials do
|
||||||
stub = stub_request(:get, MD_URI)
|
stub = stub_request(:get, MD_URI)
|
||||||
.to_return(status: 503,
|
.to_return(status: 503,
|
||||||
headers: { 'Metadata-Flavor' => 'Google' })
|
headers: { 'Metadata-Flavor' => 'Google' })
|
||||||
blk = proc { @client.fetch_access_token! }
|
expect { @client.fetch_access_token! }
|
||||||
expect(&blk).to raise_error Signet::AuthorizationError
|
.to raise_error Signet::AuthorizationError
|
||||||
expect(stub).to have_been_requested
|
expect(stub).to have_been_requested
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -45,7 +45,8 @@ describe '#get_application_default' do
|
||||||
@var_name = ENV_VAR
|
@var_name = ENV_VAR
|
||||||
@credential_vars = [
|
@credential_vars = [
|
||||||
ENV_VAR, PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR, CLIENT_ID_VAR,
|
ENV_VAR, PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR, CLIENT_ID_VAR,
|
||||||
CLIENT_SECRET_VAR, REFRESH_TOKEN_VAR, ACCOUNT_TYPE_VAR]
|
CLIENT_SECRET_VAR, REFRESH_TOKEN_VAR, ACCOUNT_TYPE_VAR
|
||||||
|
]
|
||||||
@original_env_vals = {}
|
@original_env_vals = {}
|
||||||
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
||||||
@home = ENV['HOME']
|
@home = ENV['HOME']
|
||||||
|
@ -74,10 +75,9 @@ describe '#get_application_default' do
|
||||||
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
|
||||||
blk = proc do
|
expect do
|
||||||
Google::Auth.get_application_default(@scope, options)
|
Google::Auth.get_application_default(@scope, options)
|
||||||
end
|
end.to raise_error RuntimeError
|
||||||
expect(&blk).to raise_error RuntimeError
|
|
||||||
end
|
end
|
||||||
expect(stub).to have_been_requested
|
expect(stub).to have_been_requested
|
||||||
end
|
end
|
||||||
|
@ -215,10 +215,9 @@ 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
|
||||||
blk = proc do
|
expect do
|
||||||
Google::Auth.get_application_default(@scope, options)
|
Google::Auth.get_application_default(@scope, options)
|
||||||
end
|
end.to raise_error RuntimeError
|
||||||
expect(&blk).to raise_error RuntimeError
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -229,20 +228,18 @@ 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
|
||||||
blk = proc do
|
expect do
|
||||||
Google::Auth.get_application_default(@scope, options)
|
Google::Auth.get_application_default(@scope, options)
|
||||||
end
|
end.to raise_error RuntimeError
|
||||||
expect(&blk).to raise_error RuntimeError
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'fails if env vars are set' do
|
it 'fails if env vars are set' 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
|
expect do
|
||||||
Google::Auth.get_application_default(@scope, options)
|
Google::Auth.get_application_default(@scope, options)
|
||||||
end
|
end.to raise_error RuntimeError
|
||||||
expect(&blk).to raise_error RuntimeError
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -39,13 +39,15 @@ describe Google::Auth::ScopeUtil do
|
||||||
|
|
||||||
it 'normalizes the email scope' do
|
it 'normalizes the email scope' do
|
||||||
expect(normalized).to include(
|
expect(normalized).to include(
|
||||||
'https://www.googleapis.com/auth/userinfo.email')
|
'https://www.googleapis.com/auth/userinfo.email'
|
||||||
|
)
|
||||||
expect(normalized).to_not include 'email'
|
expect(normalized).to_not include 'email'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'normalizes the profile scope' do
|
it 'normalizes the profile scope' do
|
||||||
expect(normalized).to include(
|
expect(normalized).to include(
|
||||||
'https://www.googleapis.com/auth/userinfo.profile')
|
'https://www.googleapis.com/auth/userinfo.profile'
|
||||||
|
)
|
||||||
expect(normalized).to_not include 'profile'
|
expect(normalized).to_not include 'profile'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,8 @@ describe Google::Auth::ServiceAccountCredentials do
|
||||||
end
|
end
|
||||||
stub_request(:post, 'https://www.googleapis.com/oauth2/v3/token')
|
stub_request(:post, 'https://www.googleapis.com/oauth2/v3/token')
|
||||||
.with(body: hash_including(
|
.with(body: hash_including(
|
||||||
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer'),
|
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer'
|
||||||
|
),
|
||||||
&blk)
|
&blk)
|
||||||
.to_return(body: body,
|
.to_return(body: body,
|
||||||
status: 200,
|
status: 200,
|
||||||
|
@ -164,7 +165,8 @@ describe Google::Auth::ServiceAccountCredentials do
|
||||||
before(:example) do
|
before(:example) do
|
||||||
@var_name = ENV_VAR
|
@var_name = ENV_VAR
|
||||||
@credential_vars = [
|
@credential_vars = [
|
||||||
ENV_VAR, PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR, ACCOUNT_TYPE_VAR]
|
ENV_VAR, PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR, ACCOUNT_TYPE_VAR
|
||||||
|
]
|
||||||
@original_env_vals = {}
|
@original_env_vals = {}
|
||||||
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
||||||
ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
|
ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
|
||||||
|
@ -294,7 +296,8 @@ describe Google::Auth::ServiceAccountJwtHeaderCredentials do
|
||||||
before(:example) do
|
before(:example) do
|
||||||
@var_name = ENV_VAR
|
@var_name = ENV_VAR
|
||||||
@credential_vars = [
|
@credential_vars = [
|
||||||
ENV_VAR, PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR, ACCOUNT_TYPE_VAR]
|
ENV_VAR, PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR, ACCOUNT_TYPE_VAR
|
||||||
|
]
|
||||||
@original_env_vals = {}
|
@original_env_vals = {}
|
||||||
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
||||||
ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
|
ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
|
||||||
|
|
|
@ -45,7 +45,8 @@ describe Signet::OAuth2::Client do
|
||||||
scope: 'https://www.googleapis.com/auth/userinfo.profile',
|
scope: 'https://www.googleapis.com/auth/userinfo.profile',
|
||||||
issuer: 'app@example.com',
|
issuer: 'app@example.com',
|
||||||
audience: 'https://accounts.google.com/o/oauth2/token',
|
audience: 'https://accounts.google.com/o/oauth2/token',
|
||||||
signing_key: @key)
|
signing_key: @key
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def make_auth_stubs(opts)
|
def make_auth_stubs(opts)
|
||||||
|
@ -60,8 +61,8 @@ describe Signet::OAuth2::Client do
|
||||||
end
|
end
|
||||||
stub_request(:post, 'https://accounts.google.com/o/oauth2/token')
|
stub_request(:post, 'https://accounts.google.com/o/oauth2/token')
|
||||||
.with(body: hash_including(
|
.with(body: hash_including(
|
||||||
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer'),
|
'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer'
|
||||||
&blk)
|
), &blk)
|
||||||
.to_return(body: body,
|
.to_return(body: body,
|
||||||
status: 200,
|
status: 200,
|
||||||
headers: { 'Content-Type' => 'application/json' })
|
headers: { 'Content-Type' => 'application/json' })
|
||||||
|
|
|
@ -82,7 +82,8 @@ describe Google::Auth::UserAuthorizer do
|
||||||
|
|
||||||
it 'should include the callback uri' do
|
it 'should include the callback uri' do
|
||||||
expect(URI(uri).query).to match(
|
expect(URI(uri).query).to match(
|
||||||
%r{redirect_uri=https://www.example.com/oauth/callback})
|
%r{redirect_uri=https://www.example.com/oauth/callback}
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should include the scope' do
|
it 'should include the scope' do
|
||||||
|
@ -139,7 +140,8 @@ describe Google::Auth::UserAuthorizer do
|
||||||
MultiJson.dump(
|
MultiJson.dump(
|
||||||
access_token: 'accesstoken',
|
access_token: 'accesstoken',
|
||||||
refresh_token: 'refreshtoken',
|
refresh_token: 'refreshtoken',
|
||||||
expiration_time_millis: 1_441_234_742_000)
|
expiration_time_millis: 1_441_234_742_000
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with a valid user id' do
|
context 'with a valid user id' do
|
||||||
|
@ -150,7 +152,8 @@ describe Google::Auth::UserAuthorizer do
|
||||||
|
|
||||||
it 'should return an instance of UserRefreshCredentials' do
|
it 'should return an instance of UserRefreshCredentials' do
|
||||||
expect(credentials).to be_instance_of(
|
expect(credentials).to be_instance_of(
|
||||||
Google::Auth::UserRefreshCredentials)
|
Google::Auth::UserRefreshCredentials
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return credentials with a valid refresh token' do
|
it 'should return credentials with a valid refresh token' do
|
||||||
|
@ -226,7 +229,8 @@ describe Google::Auth::UserAuthorizer do
|
||||||
it 'should persist the expiry as milliseconds' do
|
it 'should persist the expiry as milliseconds' do
|
||||||
expected_expiry = expiry * 1000
|
expected_expiry = expiry * 1000
|
||||||
expect(MultiJson.load(token_json)['expiration_time_millis']).to eql(
|
expect(MultiJson.load(token_json)['expiration_time_millis']).to eql(
|
||||||
expected_expiry)
|
expected_expiry
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -240,12 +244,14 @@ describe Google::Auth::UserAuthorizer do
|
||||||
before(:example) do
|
before(:example) do
|
||||||
stub_request(:post, 'https://www.googleapis.com/oauth2/v3/token')
|
stub_request(:post, 'https://www.googleapis.com/oauth2/v3/token')
|
||||||
.to_return(body: token_json, status: 200, headers: {
|
.to_return(body: token_json, status: 200, headers: {
|
||||||
'Content-Type' => 'application/json' })
|
'Content-Type' => 'application/json'
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should exchange a code for credentials' do
|
it 'should exchange a code for credentials' do
|
||||||
credentials = authorizer.get_credentials_from_code(
|
credentials = authorizer.get_credentials_from_code(
|
||||||
user_id: 'user1', code: 'code')
|
user_id: 'user1', code: 'code'
|
||||||
|
)
|
||||||
expect(credentials.access_token).to eq '1/abc123'
|
expect(credentials.access_token).to eq '1/abc123'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -256,7 +262,8 @@ describe Google::Auth::UserAuthorizer do
|
||||||
|
|
||||||
it 'should store credentials when requested' do
|
it 'should store credentials when requested' do
|
||||||
authorizer.get_and_store_credentials_from_code(
|
authorizer.get_and_store_credentials_from_code(
|
||||||
user_id: 'user1', code: 'code')
|
user_id: 'user1', code: 'code'
|
||||||
|
)
|
||||||
expect(token_store.load('user1')).to_not be_nil
|
expect(token_store.load('user1')).to_not be_nil
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -286,20 +293,23 @@ describe Google::Auth::UserAuthorizer do
|
||||||
MultiJson.dump(
|
MultiJson.dump(
|
||||||
access_token: 'accesstoken',
|
access_token: 'accesstoken',
|
||||||
refresh_token: 'refreshtoken',
|
refresh_token: 'refreshtoken',
|
||||||
expiration_time_millis: 1_441_234_742_000)
|
expiration_time_millis: 1_441_234_742_000
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
before(:example) do
|
before(:example) do
|
||||||
token_store.store('user1', token_json)
|
token_store.store('user1', token_json)
|
||||||
stub_request(
|
stub_request(
|
||||||
:get, 'https://accounts.google.com/o/oauth2/revoke?token=refreshtoken')
|
:get, 'https://accounts.google.com/o/oauth2/revoke?token=refreshtoken'
|
||||||
|
)
|
||||||
.to_return(status: 200)
|
.to_return(status: 200)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should revoke the grant' do
|
it 'should revoke the grant' do
|
||||||
authorizer.revoke_authorization('user1')
|
authorizer.revoke_authorization('user1')
|
||||||
expect(a_request(
|
expect(a_request(
|
||||||
:get, 'https://accounts.google.com/o/oauth2/revoke?token=refreshtoken'))
|
:get, 'https://accounts.google.com/o/oauth2/revoke?token=refreshtoken'
|
||||||
|
))
|
||||||
.to have_been_made
|
.to have_been_made
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -87,7 +87,8 @@ describe Google::Auth::UserRefreshCredentials do
|
||||||
@var_name = ENV_VAR
|
@var_name = ENV_VAR
|
||||||
@credential_vars = [
|
@credential_vars = [
|
||||||
ENV_VAR, CLIENT_ID_VAR, CLIENT_SECRET_VAR, REFRESH_TOKEN_VAR,
|
ENV_VAR, CLIENT_ID_VAR, CLIENT_SECRET_VAR, REFRESH_TOKEN_VAR,
|
||||||
ACCOUNT_TYPE_VAR]
|
ACCOUNT_TYPE_VAR
|
||||||
|
]
|
||||||
@original_env_vals = {}
|
@original_env_vals = {}
|
||||||
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
||||||
@scope = 'https://www.googleapis.com/auth/userinfo.profile'
|
@scope = 'https://www.googleapis.com/auth/userinfo.profile'
|
||||||
|
@ -288,7 +289,8 @@ describe Google::Auth::UserRefreshCredentials do
|
||||||
it 'raises an authorization error' do
|
it 'raises an authorization error' do
|
||||||
stub
|
stub
|
||||||
expect { @client.revoke! }.to raise_error(
|
expect { @client.revoke! }.to raise_error(
|
||||||
Signet::AuthorizationError)
|
Signet::AuthorizationError
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -52,13 +52,15 @@ describe Google::Auth::WebUserAuthorizer do
|
||||||
let(:env) do
|
let(:env) do
|
||||||
Rack::MockRequest.env_for(
|
Rack::MockRequest.env_for(
|
||||||
'http://example.com:8080/test',
|
'http://example.com:8080/test',
|
||||||
'REMOTE_ADDR' => '10.10.10.10')
|
'REMOTE_ADDR' => '10.10.10.10'
|
||||||
|
)
|
||||||
end
|
end
|
||||||
let(:request) { Rack::Request.new(env) }
|
let(:request) { Rack::Request.new(env) }
|
||||||
it 'should include current url in state' do
|
it 'should include current url in state' do
|
||||||
url = authorizer.get_authorization_url(request: request)
|
url = authorizer.get_authorization_url(request: request)
|
||||||
expect(url).to match(
|
expect(url).to match(
|
||||||
%r{%22current_uri%22:%22http://example.com:8080/test%22})
|
%r{%22current_uri%22:%22http://example.com:8080/test%22}
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should include request forgery token in state' do
|
it 'should include request forgery token in state' do
|
||||||
|
@ -76,20 +78,23 @@ describe Google::Auth::WebUserAuthorizer do
|
||||||
it 'should resolve callback against base URL' do
|
it 'should resolve callback against base URL' do
|
||||||
url = authorizer.get_authorization_url(request: request)
|
url = authorizer.get_authorization_url(request: request)
|
||||||
expect(url).to match(
|
expect(url).to match(
|
||||||
%r{redirect_uri=http://example.com:8080/oauth2callback})
|
%r{redirect_uri=http://example.com:8080/oauth2callback}
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should allow overriding the current URL' do
|
it 'should allow overriding the current URL' do
|
||||||
url = authorizer.get_authorization_url(
|
url = authorizer.get_authorization_url(
|
||||||
request: request,
|
request: request,
|
||||||
redirect_to: '/foo')
|
redirect_to: '/foo'
|
||||||
|
)
|
||||||
expect(url).to match %r{%22current_uri%22:%22/foo%22}
|
expect(url).to match %r{%22current_uri%22:%22/foo%22}
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should pass through login hint' do
|
it 'should pass through login hint' do
|
||||||
url = authorizer.get_authorization_url(
|
url = authorizer.get_authorization_url(
|
||||||
request: request,
|
request: request,
|
||||||
login_hint: 'user@example.com')
|
login_hint: 'user@example.com'
|
||||||
|
)
|
||||||
expect(url).to match(/login_hint=user@example.com/)
|
expect(url).to match(/login_hint=user@example.com/)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -113,7 +118,8 @@ describe Google::Auth::WebUserAuthorizer do
|
||||||
'http://example.com:8080/oauth2callback?code=authcode&'\
|
'http://example.com:8080/oauth2callback?code=authcode&'\
|
||||||
'state=%7B%22current_uri%22%3A%22%2Ffoo%22%2C%22'\
|
'state=%7B%22current_uri%22%3A%22%2Ffoo%22%2C%22'\
|
||||||
'session_id%22%3A%22abc%22%7D',
|
'session_id%22%3A%22abc%22%7D',
|
||||||
'REMOTE_ADDR' => '10.10.10.10')
|
'REMOTE_ADDR' => '10.10.10.10'
|
||||||
|
)
|
||||||
end
|
end
|
||||||
let(:request) { Rack::Request.new(env) }
|
let(:request) { Rack::Request.new(env) }
|
||||||
|
|
||||||
|
@ -123,7 +129,8 @@ describe Google::Auth::WebUserAuthorizer do
|
||||||
|
|
||||||
it 'should return credentials when valid code present' do
|
it 'should return credentials when valid code present' do
|
||||||
expect(credentials).to be_instance_of(
|
expect(credentials).to be_instance_of(
|
||||||
Google::Auth::UserRefreshCredentials)
|
Google::Auth::UserRefreshCredentials
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'should return next URL to redirect to' do
|
it 'should return next URL to redirect to' do
|
||||||
|
|
Loading…
Reference in New Issue