googleauth 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +2 -2
- data/.travis.yml +18 -2
- data/CHANGELOG.md +26 -1
- data/googleauth.gemspec +2 -1
- data/lib/googleauth.rb +29 -6
- data/lib/googleauth/credentials_loader.rb +53 -8
- data/lib/googleauth/iam.rb +75 -0
- data/lib/googleauth/service_account.rb +19 -6
- data/lib/googleauth/user_refresh.rb +9 -2
- data/lib/googleauth/version.rb +1 -1
- data/spec/googleauth/get_application_default_spec.rb +66 -21
- data/spec/googleauth/iam_spec.rb +80 -0
- data/spec/googleauth/service_account_spec.rb +77 -24
- data/spec/googleauth/user_refresh_spec.rb +76 -16
- metadata +45 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: adef96ddcbbab3bf0cdf0bcb5e2772bbf3de2f04
|
4
|
+
data.tar.gz: ab58fe380898294110ec76ac571a22ef411efe6b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ad82896ca3cac5f605ece8cf51c512bc4625c782045452fee044064ae4d751e33e29101f6c9caef569f08816b1b1066626000a3b541c30dc02033a70cbebe7c
|
7
|
+
data.tar.gz: cd31e77291d39c9cf44c6ffa39a3e939274a5ca9834d6ee558f2e5ec4d5b575d6c8d29655cbaa4b25dc8e5ca89330a5f87d61dd1eea302398ac388c27f56aa46
|
data/.rubocop_todo.yml
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# This configuration was generated by `rubocop --auto-gen-config`
|
2
|
-
# on 2015-
|
2
|
+
# on 2015-05-18 09:38:28 -0700 using RuboCop version 0.31.0.
|
3
3
|
# The point is for the user to remove these configuration records
|
4
4
|
# one by one as the offenses are removed from the code base.
|
5
5
|
# Note that changes in the inspected code, or installation of new
|
@@ -9,7 +9,7 @@
|
|
9
9
|
Metrics/AbcSize:
|
10
10
|
Max: 24
|
11
11
|
|
12
|
-
# Offense count:
|
12
|
+
# Offense count: 10
|
13
13
|
# Configuration parameters: CountComments.
|
14
14
|
Metrics/MethodLength:
|
15
15
|
Max: 13
|
data/.travis.yml
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
sudo: false
|
1
2
|
language: ruby
|
2
3
|
rvm:
|
3
4
|
- 2.2
|
@@ -7,9 +8,24 @@ rvm:
|
|
7
8
|
- rbx-2
|
8
9
|
- jruby
|
9
10
|
script: "bundle exec rake"
|
11
|
+
addons:
|
12
|
+
apt:
|
13
|
+
packages:
|
14
|
+
- idn
|
15
|
+
- build-essential # this and below attempt allow rubinius to be setup ok
|
16
|
+
- bison
|
17
|
+
- ruby-dev
|
18
|
+
- rake zlib1g-dev
|
19
|
+
- libyaml-dev
|
20
|
+
- libssl-dev
|
21
|
+
- libreadline-dev
|
22
|
+
- libncurses5-dev
|
23
|
+
- llvm
|
24
|
+
- llvm-dev
|
25
|
+
- libeditline-dev
|
26
|
+
- libedit-dev
|
10
27
|
before_install:
|
11
|
-
-
|
12
|
-
- sudo apt-get install idn
|
28
|
+
- gem update bundler
|
13
29
|
notifications:
|
14
30
|
email:
|
15
31
|
recipients:
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
## 0.4.2 (05/08/2015)
|
2
|
+
|
3
|
+
### Changes
|
4
|
+
|
5
|
+
* Updated UserRefreshCredentials hash to use string keys ([@haabator][])
|
6
|
+
[#36](https://github.com/google/google-auth-library-ruby/issues/36)
|
7
|
+
|
8
|
+
* Add support for a system default credentials file. ([@mr-salty][])
|
9
|
+
[#33](https://github.com/google/google-auth-library-ruby/issues/33)
|
10
|
+
|
11
|
+
* Fix bug when loading credentials from ENV ([@dwilkie][])
|
12
|
+
[#31](https://github.com/google/google-auth-library-ruby/issues/31)
|
13
|
+
|
14
|
+
* Relax the constraint of dependent version of multi_json ([@igrep][])
|
15
|
+
[#30](https://github.com/google/google-auth-library-ruby/issues/30)
|
16
|
+
|
17
|
+
### Changes
|
18
|
+
|
19
|
+
* Enables passing credentials via environment variables. ([@haabaato][])
|
20
|
+
[#27](https://github.com/google/google-auth-library-ruby/issues/27)
|
21
|
+
|
1
22
|
## 0.4.1 (25/04/2015)
|
2
23
|
|
3
24
|
### Changes
|
@@ -18,5 +39,9 @@
|
|
18
39
|
* makes the scope parameter's optional in all APIs. ([@tbetbetbe][])
|
19
40
|
* changes the scope parameter's position in various constructors. ([@tbetbetbe][])
|
20
41
|
|
21
|
-
[@
|
42
|
+
[@dwilkie]: https://github.com/dwilkie
|
43
|
+
[@haabaato]: https://github.com/haabaato
|
44
|
+
[@igrep]: https://github.com/igrep
|
22
45
|
[@joneslee85]: https://github.com/joneslee85
|
46
|
+
[@mr-salty]: https://github.com/mr-salty
|
47
|
+
[@tbetbetbe]: https://github.com/tbetbetbe
|
data/googleauth.gemspec
CHANGED
@@ -29,12 +29,13 @@ Gem::Specification.new do |s|
|
|
29
29
|
s.add_dependency 'logging', '~> 2.0'
|
30
30
|
s.add_dependency 'jwt', '~> 1.4'
|
31
31
|
s.add_dependency 'memoist', '~> 0.12'
|
32
|
-
s.add_dependency 'multi_json', '1.11'
|
32
|
+
s.add_dependency 'multi_json', '~> 1.11'
|
33
33
|
s.add_dependency 'signet', '~> 0.6'
|
34
34
|
|
35
35
|
s.add_development_dependency 'bundler', '~> 1.9'
|
36
36
|
s.add_development_dependency 'simplecov', '~> 0.9'
|
37
37
|
s.add_development_dependency 'coveralls', '~> 0.7'
|
38
|
+
s.add_development_dependency 'fakefs', '~> 0.6'
|
38
39
|
s.add_development_dependency 'rake', '~> 10.0'
|
39
40
|
s.add_development_dependency 'rubocop', '~> 0.30'
|
40
41
|
s.add_development_dependency 'rspec', '~> 3.0'
|
data/lib/googleauth.rb
CHANGED
@@ -52,16 +52,38 @@ END
|
|
52
52
|
|
53
53
|
# override CredentialsLoader#make_creds to use the class determined by
|
54
54
|
# loading the json.
|
55
|
-
def self.make_creds(
|
56
|
-
|
57
|
-
|
55
|
+
def self.make_creds(options = {})
|
56
|
+
json_key_io, scope = options.values_at(:json_key_io, :scope)
|
57
|
+
if json_key_io
|
58
|
+
json_key, clz = determine_creds_class(json_key_io)
|
59
|
+
clz.new(json_key_io: StringIO.new(MultiJson.dump(json_key)),
|
60
|
+
scope: scope)
|
61
|
+
else
|
62
|
+
clz = read_creds
|
63
|
+
clz.new(scope: scope)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def self.read_creds
|
68
|
+
env_var = CredentialsLoader::ACCOUNT_TYPE_VAR
|
69
|
+
type = ENV[env_var]
|
70
|
+
fail "#{ACCOUNT_TYPE_VAR} is undefined in env" unless type
|
71
|
+
case type
|
72
|
+
when 'service_account'
|
73
|
+
ServiceAccountCredentials
|
74
|
+
when 'authorized_user'
|
75
|
+
UserRefreshCredentials
|
76
|
+
else
|
77
|
+
fail "credentials type '#{type}' is not supported"
|
78
|
+
end
|
58
79
|
end
|
59
80
|
|
60
81
|
# Reads the input json and determines which creds class to use.
|
61
82
|
def self.determine_creds_class(json_key_io)
|
62
83
|
json_key = MultiJson.load(json_key_io.read)
|
63
|
-
|
64
|
-
|
84
|
+
key = 'type'
|
85
|
+
fail "the json is missing the '#{key}' field" unless json_key.key?(key)
|
86
|
+
type = json_key[key]
|
65
87
|
case type
|
66
88
|
when 'service_account'
|
67
89
|
[json_key, ServiceAccountCredentials]
|
@@ -88,7 +110,8 @@ END
|
|
88
110
|
# @param options [hash] allows override of the connection being used
|
89
111
|
def get_application_default(scope = nil, options = {})
|
90
112
|
creds = DefaultCredentials.from_env(scope) ||
|
91
|
-
DefaultCredentials.from_well_known_path(scope)
|
113
|
+
DefaultCredentials.from_well_known_path(scope) ||
|
114
|
+
DefaultCredentials.from_system_default_path(scope)
|
92
115
|
return creds unless creds.nil?
|
93
116
|
fail NOT_FOUND_ERROR unless GCECredentials.on_gce?(options)
|
94
117
|
GCECredentials.new
|
@@ -39,11 +39,22 @@ module Google
|
|
39
39
|
module CredentialsLoader
|
40
40
|
extend Memoist
|
41
41
|
ENV_VAR = 'GOOGLE_APPLICATION_CREDENTIALS'
|
42
|
+
|
43
|
+
PRIVATE_KEY_VAR = 'GOOGLE_PRIVATE_KEY'
|
44
|
+
CLIENT_EMAIL_VAR = 'GOOGLE_CLIENT_EMAIL'
|
45
|
+
CLIENT_ID_VAR = 'GOOGLE_CLIENT_ID'
|
46
|
+
CLIENT_SECRET_VAR = 'GOOGLE_CLIENT_SECRET'
|
47
|
+
REFRESH_TOKEN_VAR = 'GOOGLE_REFRESH_TOKEN'
|
48
|
+
ACCOUNT_TYPE_VAR = 'GOOGLE_ACCOUNT_TYPE'
|
49
|
+
|
50
|
+
CREDENTIALS_FILE_NAME = 'application_default_credentials.json'
|
42
51
|
NOT_FOUND_ERROR =
|
43
52
|
"Unable to read the credential file specified by #{ENV_VAR}"
|
44
|
-
WELL_KNOWN_PATH =
|
53
|
+
WELL_KNOWN_PATH = "gcloud/#{CREDENTIALS_FILE_NAME}"
|
45
54
|
WELL_KNOWN_ERROR = 'Unable to read the default credential file'
|
46
55
|
|
56
|
+
SYSTEM_DEFAULT_ERROR = 'Unable to read the system default credential file'
|
57
|
+
|
47
58
|
# determines if the current OS is windows
|
48
59
|
def windows?
|
49
60
|
RbConfig::CONFIG['host_os'] =~ /Windows|mswin/
|
@@ -63,11 +74,14 @@ module Google
|
|
63
74
|
#
|
64
75
|
# @param scope [string|array|nil] the scope(s) to access
|
65
76
|
def from_env(scope = nil)
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
77
|
+
if ENV.key?(ENV_VAR)
|
78
|
+
path = ENV[ENV_VAR]
|
79
|
+
fail "file #{path} does not exist" unless File.exist?(path)
|
80
|
+
File.open(path) do |f|
|
81
|
+
return make_creds(json_key_io: f, scope: scope)
|
82
|
+
end
|
83
|
+
elsif service_account_env_vars? || authorized_user_env_vars?
|
84
|
+
return make_creds(scope: scope)
|
71
85
|
end
|
72
86
|
rescue StandardError => e
|
73
87
|
raise "#{NOT_FOUND_ERROR}: #{e}"
|
@@ -77,17 +91,48 @@ module Google
|
|
77
91
|
#
|
78
92
|
# @param scope [string|array|nil] the scope(s) to access
|
79
93
|
def from_well_known_path(scope = nil)
|
80
|
-
home_var
|
94
|
+
home_var = windows? ? 'APPDATA' : 'HOME'
|
95
|
+
base = WELL_KNOWN_PATH
|
81
96
|
root = ENV[home_var].nil? ? '' : ENV[home_var]
|
82
97
|
base = File.join('.config', base) unless windows?
|
83
98
|
path = File.join(root, base)
|
84
99
|
return nil unless File.exist?(path)
|
85
100
|
File.open(path) do |f|
|
86
|
-
return make_creds(f, scope)
|
101
|
+
return make_creds(json_key_io: f, scope: scope)
|
87
102
|
end
|
88
103
|
rescue StandardError => e
|
89
104
|
raise "#{WELL_KNOWN_ERROR}: #{e}"
|
90
105
|
end
|
106
|
+
|
107
|
+
# Creates an instance from the system default path
|
108
|
+
#
|
109
|
+
# @param scope [string|array|nil] the scope(s) to access
|
110
|
+
def from_system_default_path(scope = nil)
|
111
|
+
if windows?
|
112
|
+
return nil unless ENV['ProgramData']
|
113
|
+
prefix = File.join(ENV['ProgramData'], 'Google/Auth')
|
114
|
+
else
|
115
|
+
prefix = '/etc/google/auth/'
|
116
|
+
end
|
117
|
+
path = File.join(prefix, CREDENTIALS_FILE_NAME)
|
118
|
+
return nil unless File.exist?(path)
|
119
|
+
File.open(path) do |f|
|
120
|
+
return make_creds(json_key_io: f, scope: scope)
|
121
|
+
end
|
122
|
+
rescue StandardError => e
|
123
|
+
raise "#{SYSTEM_DEFAULT_ERROR}: #{e}"
|
124
|
+
end
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def service_account_env_vars?
|
129
|
+
([PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR] - ENV.keys).empty?
|
130
|
+
end
|
131
|
+
|
132
|
+
def authorized_user_env_vars?
|
133
|
+
([CLIENT_ID_VAR, CLIENT_SECRET_VAR, REFRESH_TOKEN_VAR] -
|
134
|
+
ENV.keys).empty?
|
135
|
+
end
|
91
136
|
end
|
92
137
|
end
|
93
138
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# Copyright 2015, Google Inc.
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are
|
6
|
+
# met:
|
7
|
+
#
|
8
|
+
# * Redistributions of source code must retain the above copyright
|
9
|
+
# notice, this list of conditions and the following disclaimer.
|
10
|
+
# * Redistributions in binary form must reproduce the above
|
11
|
+
# copyright notice, this list of conditions and the following disclaimer
|
12
|
+
# in the documentation and/or other materials provided with the
|
13
|
+
# distribution.
|
14
|
+
# * Neither the name of Google Inc. nor the names of its
|
15
|
+
# contributors may be used to endorse or promote products derived from
|
16
|
+
# this software without specific prior written permission.
|
17
|
+
#
|
18
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
19
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
20
|
+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
21
|
+
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
22
|
+
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
23
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
24
|
+
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
26
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
27
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
|
30
|
+
require 'googleauth/signet'
|
31
|
+
require 'googleauth/credentials_loader'
|
32
|
+
require 'multi_json'
|
33
|
+
|
34
|
+
module Google
|
35
|
+
# Module Auth provides classes that provide Google-specific authorization
|
36
|
+
# used to access Google APIs.
|
37
|
+
module Auth
|
38
|
+
# Authenticates requests using IAM credentials.
|
39
|
+
class IAMCredentials
|
40
|
+
SELECTOR_KEY = 'x-goog-iam-authority-selector'
|
41
|
+
TOKEN_KEY = 'x-goog-iam-authorization-token'
|
42
|
+
|
43
|
+
# Initializes an IAMCredentials.
|
44
|
+
#
|
45
|
+
# @param selector the IAM selector.
|
46
|
+
# @param token the IAM token.
|
47
|
+
def initialize(selector, token)
|
48
|
+
fail TypeError unless selector.is_a? String
|
49
|
+
fail TypeError unless token.is_a? String
|
50
|
+
@selector = selector
|
51
|
+
@token = token
|
52
|
+
end
|
53
|
+
|
54
|
+
# Adds the credential fields to the hash.
|
55
|
+
def apply!(a_hash)
|
56
|
+
a_hash[SELECTOR_KEY] = @selector
|
57
|
+
a_hash[TOKEN_KEY] = @token
|
58
|
+
a_hash
|
59
|
+
end
|
60
|
+
|
61
|
+
# Returns a clone of a_hash updated with the authoriation header
|
62
|
+
def apply(a_hash)
|
63
|
+
a_copy = a_hash.clone
|
64
|
+
apply!(a_copy)
|
65
|
+
a_copy
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns a reference to the #apply method, suitable for passing as
|
69
|
+
# a closure
|
70
|
+
def updater_proc
|
71
|
+
lambda(&method(:apply))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -62,8 +62,15 @@ module Google
|
|
62
62
|
#
|
63
63
|
# @param json_key_io [IO] an IO from which the JSON key can be read
|
64
64
|
# @param scope [string|array|nil] the scope(s) to access
|
65
|
-
def initialize(
|
66
|
-
|
65
|
+
def initialize(options = {})
|
66
|
+
json_key_io, scope = options.values_at(:json_key_io, :scope)
|
67
|
+
if json_key_io
|
68
|
+
private_key, client_email = self.class.read_json_key(json_key_io)
|
69
|
+
else
|
70
|
+
private_key = ENV[CredentialsLoader::PRIVATE_KEY_VAR]
|
71
|
+
client_email = ENV[CredentialsLoader::CLIENT_EMAIL_VAR]
|
72
|
+
end
|
73
|
+
|
67
74
|
super(token_credential_uri: TOKEN_CRED_URI,
|
68
75
|
audience: TOKEN_CRED_URI,
|
69
76
|
scope: scope,
|
@@ -90,7 +97,7 @@ module Google
|
|
90
97
|
client_email: @issuer
|
91
98
|
}
|
92
99
|
alt_clz = ServiceAccountJwtHeaderCredentials
|
93
|
-
alt = alt_clz.new(StringIO.new(MultiJson.dump(cred_json)))
|
100
|
+
alt = alt_clz.new(json_key_io: StringIO.new(MultiJson.dump(cred_json)))
|
94
101
|
alt.apply!(a_hash)
|
95
102
|
end
|
96
103
|
end
|
@@ -120,7 +127,7 @@ module Google
|
|
120
127
|
# optional scope. Here's the constructor only has one param, so
|
121
128
|
# we modify make_creds to reflect this.
|
122
129
|
def self.make_creds(*args)
|
123
|
-
new(args[0])
|
130
|
+
new(json_key_io: args[0][:json_key_io])
|
124
131
|
end
|
125
132
|
|
126
133
|
# Reads the private key and client email fields from the service account
|
@@ -135,8 +142,14 @@ module Google
|
|
135
142
|
# Initializes a ServiceAccountJwtHeaderCredentials.
|
136
143
|
#
|
137
144
|
# @param json_key_io [IO] an IO from which the JSON key can be read
|
138
|
-
def initialize(
|
139
|
-
|
145
|
+
def initialize(options = {})
|
146
|
+
json_key_io = options[:json_key_io]
|
147
|
+
if json_key_io
|
148
|
+
private_key, client_email = self.class.read_json_key(json_key_io)
|
149
|
+
else
|
150
|
+
private_key = ENV[CredentialsLoader::PRIVATE_KEY_VAR]
|
151
|
+
client_email = ENV[CredentialsLoader::CLIENT_EMAIL_VAR]
|
152
|
+
end
|
140
153
|
@private_key = private_key
|
141
154
|
@issuer = client_email
|
142
155
|
@signing_key = OpenSSL::PKey::RSA.new(private_key)
|
@@ -63,8 +63,15 @@ module Google
|
|
63
63
|
#
|
64
64
|
# @param json_key_io [IO] an IO from which the JSON key can be read
|
65
65
|
# @param scope [string|array|nil] the scope(s) to access
|
66
|
-
def initialize(
|
67
|
-
|
66
|
+
def initialize(options = {})
|
67
|
+
json_key_io, scope = options.values_at(:json_key_io, :scope)
|
68
|
+
user_creds = self.class.read_json_key(json_key_io) if json_key_io
|
69
|
+
user_creds ||= {
|
70
|
+
'client_id' => ENV[CredentialsLoader::CLIENT_ID_VAR],
|
71
|
+
'client_secret' => ENV[CredentialsLoader::CLIENT_SECRET_VAR],
|
72
|
+
'refresh_token' => ENV[CredentialsLoader::REFRESH_TOKEN_VAR]
|
73
|
+
}
|
74
|
+
|
68
75
|
super(token_credential_uri: TOKEN_CRED_URI,
|
69
76
|
client_id: user_creds['client_id'],
|
70
77
|
client_secret: user_creds['client_secret'],
|
data/lib/googleauth/version.rb
CHANGED
@@ -32,20 +32,25 @@ $LOAD_PATH.unshift(spec_dir)
|
|
32
32
|
$LOAD_PATH.uniq!
|
33
33
|
|
34
34
|
require 'faraday'
|
35
|
+
require 'fakefs/safe'
|
35
36
|
require 'googleauth'
|
36
37
|
require 'spec_helper'
|
37
38
|
|
38
39
|
describe '#get_application_default' do
|
39
40
|
before(:example) do
|
40
41
|
@key = OpenSSL::PKey::RSA.new(2048)
|
41
|
-
@var_name =
|
42
|
-
@
|
42
|
+
@var_name = ENV_VAR
|
43
|
+
@credential_vars = [
|
44
|
+
ENV_VAR, PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR, CLIENT_ID_VAR,
|
45
|
+
CLIENT_SECRET_VAR, REFRESH_TOKEN_VAR, ACCOUNT_TYPE_VAR]
|
46
|
+
@original_env_vals = {}
|
47
|
+
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
43
48
|
@home = ENV['HOME']
|
44
49
|
@scope = 'https://www.googleapis.com/auth/userinfo.profile'
|
45
50
|
end
|
46
51
|
|
47
52
|
after(:example) do
|
48
|
-
ENV[
|
53
|
+
@credential_vars.each { |var| ENV[var] = @original_env_vals[var] }
|
49
54
|
ENV['HOME'] = @home unless @home == ENV['HOME']
|
50
55
|
end
|
51
56
|
|
@@ -54,7 +59,8 @@ describe '#get_application_default' do
|
|
54
59
|
Dir.mktmpdir do |dir|
|
55
60
|
key_path = File.join(dir, 'does-not-exist')
|
56
61
|
ENV[@var_name] = key_path
|
57
|
-
expect { Google::Auth.get_application_default(@scope) }
|
62
|
+
expect { Google::Auth.get_application_default(@scope) }
|
63
|
+
.to raise_error RuntimeError
|
58
64
|
end
|
59
65
|
end
|
60
66
|
|
@@ -65,17 +71,17 @@ describe '#get_application_default' do
|
|
65
71
|
{ 'Metadata-Flavor' => 'Google' },
|
66
72
|
'']
|
67
73
|
end
|
68
|
-
end
|
74
|
+
end # GCE not detected
|
69
75
|
Dir.mktmpdir do |dir|
|
70
76
|
ENV.delete(@var_name) unless ENV[@var_name].nil? # no env var
|
71
|
-
ENV['HOME'] = dir
|
77
|
+
ENV['HOME'] = dir # no config present in this tmp dir
|
72
78
|
c = Faraday.new do |b|
|
73
79
|
b.adapter(:test, stubs)
|
74
80
|
end
|
75
81
|
blk = proc do
|
76
82
|
Google::Auth.get_application_default(@scope, connection: c)
|
77
83
|
end
|
78
|
-
expect(&blk).to raise_error
|
84
|
+
expect(&blk).to raise_error RuntimeError
|
79
85
|
end
|
80
86
|
stubs.verify_stubbed_calls
|
81
87
|
end
|
@@ -95,8 +101,7 @@ describe '#get_application_default' do
|
|
95
101
|
it 'succeeds with default file without GOOGLE_APPLICATION_CREDENTIALS' do
|
96
102
|
ENV.delete(@var_name) unless ENV[@var_name].nil?
|
97
103
|
Dir.mktmpdir do |dir|
|
98
|
-
key_path = File.join(dir, '.config',
|
99
|
-
CredentialsLoader::WELL_KNOWN_PATH)
|
104
|
+
key_path = File.join(dir, '.config', WELL_KNOWN_PATH)
|
100
105
|
FileUtils.mkdir_p(File.dirname(key_path))
|
101
106
|
File.write(key_path, cred_json_text)
|
102
107
|
ENV['HOME'] = dir
|
@@ -107,8 +112,7 @@ describe '#get_application_default' do
|
|
107
112
|
it 'succeeds with default file without a scope' do
|
108
113
|
ENV.delete(@var_name) unless ENV[@var_name].nil?
|
109
114
|
Dir.mktmpdir do |dir|
|
110
|
-
key_path = File.join(dir, '.config',
|
111
|
-
CredentialsLoader::WELL_KNOWN_PATH)
|
115
|
+
key_path = File.join(dir, '.config', WELL_KNOWN_PATH)
|
112
116
|
FileUtils.mkdir_p(File.dirname(key_path))
|
113
117
|
File.write(key_path, cred_json_text)
|
114
118
|
ENV['HOME'] = dir
|
@@ -123,10 +127,10 @@ describe '#get_application_default' do
|
|
123
127
|
{ 'Metadata-Flavor' => 'Google' },
|
124
128
|
'']
|
125
129
|
end
|
126
|
-
end
|
130
|
+
end # GCE detected
|
127
131
|
Dir.mktmpdir do |dir|
|
128
132
|
ENV.delete(@var_name) unless ENV[@var_name].nil? # no env var
|
129
|
-
ENV['HOME'] = dir
|
133
|
+
ENV['HOME'] = dir # no config present in this tmp dir
|
130
134
|
c = Faraday.new do |b|
|
131
135
|
b.adapter(:test, stubs)
|
132
136
|
end
|
@@ -137,17 +141,42 @@ describe '#get_application_default' do
|
|
137
141
|
end
|
138
142
|
stubs.verify_stubbed_calls
|
139
143
|
end
|
144
|
+
|
145
|
+
it 'succeeds with system default file' do
|
146
|
+
ENV.delete(@var_name) unless ENV[@var_name].nil?
|
147
|
+
FakeFS do
|
148
|
+
key_path = File.join('/etc/google/auth/', CREDENTIALS_FILE_NAME)
|
149
|
+
FileUtils.mkdir_p(File.dirname(key_path))
|
150
|
+
File.write(key_path, cred_json_text)
|
151
|
+
expect(Google::Auth.get_application_default(@scope)).to_not be_nil
|
152
|
+
File.delete(key_path)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'succeeds if environment vars are valid' do
|
157
|
+
ENV.delete(@var_name) unless ENV[@var_name].nil? # no env var
|
158
|
+
ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
|
159
|
+
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
160
|
+
ENV[CLIENT_ID_VAR] = cred_json[:client_id]
|
161
|
+
ENV[CLIENT_SECRET_VAR] = cred_json[:client_secret]
|
162
|
+
ENV[REFRESH_TOKEN_VAR] = cred_json[:refresh_token]
|
163
|
+
ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
|
164
|
+
expect(Google::Auth.get_application_default(@scope)).to_not be_nil
|
165
|
+
end
|
140
166
|
end
|
141
167
|
|
142
168
|
describe 'when credential type is service account' do
|
143
|
-
|
144
|
-
|
169
|
+
let(:cred_json) do
|
170
|
+
{
|
145
171
|
private_key_id: 'a_private_key_id',
|
146
172
|
private_key: @key.to_pem,
|
147
173
|
client_email: 'app@developer.gserviceaccount.com',
|
148
174
|
client_id: 'app.apps.googleusercontent.com',
|
149
175
|
type: 'service_account'
|
150
176
|
}
|
177
|
+
end
|
178
|
+
|
179
|
+
def cred_json_text
|
151
180
|
MultiJson.dump(cred_json)
|
152
181
|
end
|
153
182
|
|
@@ -156,13 +185,16 @@ describe '#get_application_default' do
|
|
156
185
|
end
|
157
186
|
|
158
187
|
describe 'when credential type is authorized_user' do
|
159
|
-
|
160
|
-
|
188
|
+
let(:cred_json) do
|
189
|
+
{
|
161
190
|
client_secret: 'privatekey',
|
162
191
|
refresh_token: 'refreshtoken',
|
163
192
|
client_id: 'app.apps.googleusercontent.com',
|
164
193
|
type: 'authorized_user'
|
165
194
|
}
|
195
|
+
end
|
196
|
+
|
197
|
+
def cred_json_text
|
166
198
|
MultiJson.dump(cred_json)
|
167
199
|
end
|
168
200
|
|
@@ -171,13 +203,18 @@ describe '#get_application_default' do
|
|
171
203
|
end
|
172
204
|
|
173
205
|
describe 'when credential type is unknown' do
|
174
|
-
|
175
|
-
|
206
|
+
let(:cred_json) do
|
207
|
+
{
|
176
208
|
client_secret: 'privatekey',
|
177
209
|
refresh_token: 'refreshtoken',
|
178
210
|
client_id: 'app.apps.googleusercontent.com',
|
211
|
+
private_key: @key.to_pem,
|
212
|
+
client_email: 'app@developer.gserviceaccount.com',
|
179
213
|
type: 'not_known_type'
|
180
214
|
}
|
215
|
+
end
|
216
|
+
|
217
|
+
def cred_json_text
|
181
218
|
MultiJson.dump(cred_json)
|
182
219
|
end
|
183
220
|
|
@@ -197,8 +234,7 @@ describe '#get_application_default' do
|
|
197
234
|
it 'fails if the well known file contains the creds' do
|
198
235
|
ENV.delete(@var_name) unless ENV[@var_name].nil?
|
199
236
|
Dir.mktmpdir do |dir|
|
200
|
-
key_path = File.join(dir, '.config',
|
201
|
-
CredentialsLoader::WELL_KNOWN_PATH)
|
237
|
+
key_path = File.join(dir, '.config', WELL_KNOWN_PATH)
|
202
238
|
FileUtils.mkdir_p(File.dirname(key_path))
|
203
239
|
File.write(key_path, cred_json_text)
|
204
240
|
ENV['HOME'] = dir
|
@@ -208,5 +244,14 @@ describe '#get_application_default' do
|
|
208
244
|
expect(&blk).to raise_error RuntimeError
|
209
245
|
end
|
210
246
|
end
|
247
|
+
|
248
|
+
it 'fails if env vars are set' do
|
249
|
+
ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
|
250
|
+
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
251
|
+
blk = proc do
|
252
|
+
Google::Auth.get_application_default(@scope)
|
253
|
+
end
|
254
|
+
expect(&blk).to raise_error RuntimeError
|
255
|
+
end
|
211
256
|
end
|
212
257
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# Copyright 2015, Google Inc.
|
2
|
+
# All rights reserved.
|
3
|
+
#
|
4
|
+
# Redistribution and use in source and binary forms, with or without
|
5
|
+
# modification, are permitted provided that the following conditions are
|
6
|
+
# met:
|
7
|
+
#
|
8
|
+
# * Redistributions of source code must retain the above copyright
|
9
|
+
# notice, this list of conditions and the following disclaimer.
|
10
|
+
# * Redistributions in binary form must reproduce the above
|
11
|
+
# copyright notice, this list of conditions and the following disclaimer
|
12
|
+
# in the documentation and/or other materials provided with the
|
13
|
+
# distribution.
|
14
|
+
# * Neither the name of Google Inc. nor the names of its
|
15
|
+
# contributors may be used to endorse or promote products derived from
|
16
|
+
# this software without specific prior written permission.
|
17
|
+
#
|
18
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
19
|
+
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
20
|
+
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
21
|
+
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
22
|
+
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
23
|
+
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
24
|
+
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
25
|
+
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
26
|
+
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
27
|
+
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
|
+
|
30
|
+
spec_dir = File.expand_path(File.join(File.dirname(__FILE__)))
|
31
|
+
$LOAD_PATH.unshift(spec_dir)
|
32
|
+
$LOAD_PATH.uniq!
|
33
|
+
|
34
|
+
require 'googleauth/iam'
|
35
|
+
|
36
|
+
describe Google::Auth::IAMCredentials do
|
37
|
+
IAMCredentials = Google::Auth::IAMCredentials
|
38
|
+
let(:test_selector) { 'the-test-selector' }
|
39
|
+
let(:test_token) { 'the-test-token' }
|
40
|
+
let(:test_creds) { IAMCredentials.new(test_selector, test_token) }
|
41
|
+
|
42
|
+
describe '#apply!' do
|
43
|
+
it 'should update the target hash with the iam values' do
|
44
|
+
md = { foo: 'bar' }
|
45
|
+
test_creds.apply!(md)
|
46
|
+
expect(md[IAMCredentials::SELECTOR_KEY]).to eq test_selector
|
47
|
+
expect(md[IAMCredentials::TOKEN_KEY]).to eq test_token
|
48
|
+
expect(md[:foo]).to eq 'bar'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'updater_proc' do
|
53
|
+
it 'should provide a proc that updates a hash with the iam values' do
|
54
|
+
md = { foo: 'bar' }
|
55
|
+
the_proc = test_creds.updater_proc
|
56
|
+
got = the_proc.call(md)
|
57
|
+
expect(got[IAMCredentials::SELECTOR_KEY]).to eq test_selector
|
58
|
+
expect(got[IAMCredentials::TOKEN_KEY]).to eq test_token
|
59
|
+
expect(got[:foo]).to eq 'bar'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#apply' do
|
64
|
+
it 'should not update the original hash with the iam values' do
|
65
|
+
md = { foo: 'bar' }
|
66
|
+
test_creds.apply(md)
|
67
|
+
expect(md[IAMCredentials::SELECTOR_KEY]).to be_nil
|
68
|
+
expect(md[IAMCredentials::TOKEN_KEY]).to be_nil
|
69
|
+
expect(md[:foo]).to eq 'bar'
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'should return a with the iam values' do
|
73
|
+
md = { foo: 'bar' }
|
74
|
+
got = test_creds.apply(md)
|
75
|
+
expect(got[IAMCredentials::SELECTOR_KEY]).to eq test_selector
|
76
|
+
expect(got[IAMCredentials::TOKEN_KEY]).to eq test_token
|
77
|
+
expect(got[:foo]).to eq 'bar'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -32,6 +32,7 @@ $LOAD_PATH.unshift(spec_dir)
|
|
32
32
|
$LOAD_PATH.uniq!
|
33
33
|
|
34
34
|
require 'apply_auth_examples'
|
35
|
+
require 'fakefs/safe'
|
35
36
|
require 'fileutils'
|
36
37
|
require 'googleauth/service_account'
|
37
38
|
require 'jwt'
|
@@ -53,7 +54,7 @@ shared_examples 'jwt header auth' do
|
|
53
54
|
expect(hdr).to_not be_nil
|
54
55
|
expect(hdr.start_with?(auth_prefix)).to be true
|
55
56
|
authorization = hdr[auth_prefix.length..-1]
|
56
|
-
payload,
|
57
|
+
payload, = JWT.decode(authorization, @key.public_key)
|
57
58
|
expect(payload['aud']).to eq(test_uri)
|
58
59
|
expect(payload['iss']).to eq(client_email)
|
59
60
|
end
|
@@ -108,12 +109,22 @@ end
|
|
108
109
|
describe Google::Auth::ServiceAccountCredentials do
|
109
110
|
ServiceAccountCredentials = Google::Auth::ServiceAccountCredentials
|
110
111
|
let(:client_email) { 'app@developer.gserviceaccount.com' }
|
112
|
+
let(:cred_json) do
|
113
|
+
{
|
114
|
+
private_key_id: 'a_private_key_id',
|
115
|
+
private_key: @key.to_pem,
|
116
|
+
client_email: client_email,
|
117
|
+
client_id: 'app.apps.googleusercontent.com',
|
118
|
+
type: 'service_account'
|
119
|
+
}
|
120
|
+
end
|
111
121
|
|
112
122
|
before(:example) do
|
113
123
|
@key = OpenSSL::PKey::RSA.new(2048)
|
114
124
|
@client = ServiceAccountCredentials.new(
|
115
|
-
StringIO.new(cred_json_text),
|
116
|
-
'https://www.googleapis.com/auth/userinfo.profile'
|
125
|
+
json_key_io: StringIO.new(cred_json_text),
|
126
|
+
scope: 'https://www.googleapis.com/auth/userinfo.profile'
|
127
|
+
)
|
117
128
|
end
|
118
129
|
|
119
130
|
def make_auth_stubs(opts = {})
|
@@ -131,13 +142,6 @@ describe Google::Auth::ServiceAccountCredentials do
|
|
131
142
|
end
|
132
143
|
|
133
144
|
def cred_json_text
|
134
|
-
cred_json = {
|
135
|
-
private_key_id: 'a_private_key_id',
|
136
|
-
private_key: @key.to_pem,
|
137
|
-
client_email: client_email,
|
138
|
-
client_id: 'app.apps.googleusercontent.com',
|
139
|
-
type: 'service_account'
|
140
|
-
}
|
141
145
|
MultiJson.dump(cred_json)
|
142
146
|
end
|
143
147
|
|
@@ -154,13 +158,18 @@ describe Google::Auth::ServiceAccountCredentials do
|
|
154
158
|
describe '#from_env' do
|
155
159
|
before(:example) do
|
156
160
|
@var_name = ENV_VAR
|
157
|
-
@
|
161
|
+
@credential_vars = [
|
162
|
+
ENV_VAR, PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR, ACCOUNT_TYPE_VAR]
|
163
|
+
@original_env_vals = {}
|
164
|
+
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
165
|
+
ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
|
166
|
+
|
158
167
|
@scope = 'https://www.googleapis.com/auth/userinfo.profile'
|
159
168
|
@clz = ServiceAccountCredentials
|
160
169
|
end
|
161
170
|
|
162
171
|
after(:example) do
|
163
|
-
ENV[
|
172
|
+
@credential_vars.each { |var| ENV[var] = @original_env_vals[var] }
|
164
173
|
end
|
165
174
|
|
166
175
|
it 'returns nil if the GOOGLE_APPLICATION_CREDENTIALS is unset' do
|
@@ -174,7 +183,7 @@ describe Google::Auth::ServiceAccountCredentials do
|
|
174
183
|
Dir.mktmpdir do |dir|
|
175
184
|
key_path = File.join(dir, 'does-not-exist')
|
176
185
|
ENV[@var_name] = key_path
|
177
|
-
expect { @clz.from_env(@scope) }.to raise_error
|
186
|
+
expect { @clz.from_env(@scope) }.to raise_error RuntimeError
|
178
187
|
end
|
179
188
|
end
|
180
189
|
|
@@ -187,6 +196,13 @@ describe Google::Auth::ServiceAccountCredentials do
|
|
187
196
|
expect(@clz.from_env(@scope)).to_not be_nil
|
188
197
|
end
|
189
198
|
end
|
199
|
+
|
200
|
+
it 'succeeds when GOOGLE_PRIVATE_KEY and GOOGLE_CLIENT_EMAIL env vars are'\
|
201
|
+
' valid' do
|
202
|
+
ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
|
203
|
+
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
204
|
+
expect(@clz.from_env(@scope)).to_not be_nil
|
205
|
+
end
|
190
206
|
end
|
191
207
|
|
192
208
|
describe '#from_well_known_path' do
|
@@ -216,6 +232,30 @@ describe Google::Auth::ServiceAccountCredentials do
|
|
216
232
|
end
|
217
233
|
end
|
218
234
|
end
|
235
|
+
|
236
|
+
describe '#from_system_default_path' do
|
237
|
+
before(:example) do
|
238
|
+
@scope = 'https://www.googleapis.com/auth/userinfo.profile'
|
239
|
+
@path = File.join('/etc/google/auth/', CREDENTIALS_FILE_NAME)
|
240
|
+
@clz = ServiceAccountCredentials
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'is nil if no file exists' do
|
244
|
+
FakeFS do
|
245
|
+
expect(ServiceAccountCredentials.from_system_default_path(@scope))
|
246
|
+
.to be_nil
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
it 'successfully loads the file when it is present' do
|
251
|
+
FakeFS do
|
252
|
+
FileUtils.mkdir_p(File.dirname(@path))
|
253
|
+
File.write(@path, cred_json_text)
|
254
|
+
expect(@clz.from_system_default_path(@scope)).to_not be_nil
|
255
|
+
File.delete(@path)
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
219
259
|
end
|
220
260
|
|
221
261
|
describe Google::Auth::ServiceAccountJwtHeaderCredentials do
|
@@ -224,20 +264,22 @@ describe Google::Auth::ServiceAccountJwtHeaderCredentials do
|
|
224
264
|
|
225
265
|
let(:client_email) { 'app@developer.gserviceaccount.com' }
|
226
266
|
let(:clz) { Google::Auth::ServiceAccountJwtHeaderCredentials }
|
227
|
-
|
228
|
-
|
229
|
-
@key = OpenSSL::PKey::RSA.new(2048)
|
230
|
-
@client = clz.new(StringIO.new(cred_json_text))
|
231
|
-
end
|
232
|
-
|
233
|
-
def cred_json_text
|
234
|
-
cred_json = {
|
267
|
+
let(:cred_json) do
|
268
|
+
{
|
235
269
|
private_key_id: 'a_private_key_id',
|
236
270
|
private_key: @key.to_pem,
|
237
271
|
client_email: client_email,
|
238
272
|
client_id: 'app.apps.googleusercontent.com',
|
239
273
|
type: 'service_account'
|
240
274
|
}
|
275
|
+
end
|
276
|
+
|
277
|
+
before(:example) do
|
278
|
+
@key = OpenSSL::PKey::RSA.new(2048)
|
279
|
+
@client = clz.new(json_key_io: StringIO.new(cred_json_text))
|
280
|
+
end
|
281
|
+
|
282
|
+
def cred_json_text
|
241
283
|
MultiJson.dump(cred_json)
|
242
284
|
end
|
243
285
|
|
@@ -246,11 +288,15 @@ describe Google::Auth::ServiceAccountJwtHeaderCredentials do
|
|
246
288
|
describe '#from_env' do
|
247
289
|
before(:example) do
|
248
290
|
@var_name = ENV_VAR
|
249
|
-
@
|
291
|
+
@credential_vars = [
|
292
|
+
ENV_VAR, PRIVATE_KEY_VAR, CLIENT_EMAIL_VAR, ACCOUNT_TYPE_VAR]
|
293
|
+
@original_env_vals = {}
|
294
|
+
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
295
|
+
ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
|
250
296
|
end
|
251
297
|
|
252
298
|
after(:example) do
|
253
|
-
ENV[
|
299
|
+
@credential_vars.each { |var| ENV[var] = @original_env_vals[var] }
|
254
300
|
end
|
255
301
|
|
256
302
|
it 'returns nil if the GOOGLE_APPLICATION_CREDENTIALS is unset' do
|
@@ -264,7 +310,7 @@ describe Google::Auth::ServiceAccountJwtHeaderCredentials do
|
|
264
310
|
Dir.mktmpdir do |dir|
|
265
311
|
key_path = File.join(dir, 'does-not-exist')
|
266
312
|
ENV[@var_name] = key_path
|
267
|
-
expect { clz.from_env }.to raise_error
|
313
|
+
expect { clz.from_env }.to raise_error RuntimeError
|
268
314
|
end
|
269
315
|
end
|
270
316
|
|
@@ -277,6 +323,13 @@ describe Google::Auth::ServiceAccountJwtHeaderCredentials do
|
|
277
323
|
expect(clz.from_env).to_not be_nil
|
278
324
|
end
|
279
325
|
end
|
326
|
+
|
327
|
+
it 'succeeds when GOOGLE_PRIVATE_KEY and GOOGLE_CLIENT_EMAIL env vars are'\
|
328
|
+
' valid' do
|
329
|
+
ENV[PRIVATE_KEY_VAR] = cred_json[:private_key]
|
330
|
+
ENV[CLIENT_EMAIL_VAR] = cred_json[:client_email]
|
331
|
+
expect(clz.from_env(@scope)).to_not be_nil
|
332
|
+
end
|
280
333
|
end
|
281
334
|
|
282
335
|
describe '#from_well_known_path' do
|
@@ -32,6 +32,7 @@ $LOAD_PATH.unshift(spec_dir)
|
|
32
32
|
$LOAD_PATH.uniq!
|
33
33
|
|
34
34
|
require 'apply_auth_examples'
|
35
|
+
require 'fakefs/safe'
|
35
36
|
require 'fileutils'
|
36
37
|
require 'googleauth/user_refresh'
|
37
38
|
require 'jwt'
|
@@ -40,15 +41,26 @@ require 'openssl'
|
|
40
41
|
require 'spec_helper'
|
41
42
|
require 'tmpdir'
|
42
43
|
|
44
|
+
include Google::Auth::CredentialsLoader
|
45
|
+
|
43
46
|
describe Google::Auth::UserRefreshCredentials do
|
44
47
|
UserRefreshCredentials = Google::Auth::UserRefreshCredentials
|
45
|
-
|
48
|
+
|
49
|
+
let(:cred_json) do
|
50
|
+
{
|
51
|
+
client_secret: 'privatekey',
|
52
|
+
client_id: 'client123',
|
53
|
+
refresh_token: 'refreshtoken',
|
54
|
+
type: 'authorized_user'
|
55
|
+
}
|
56
|
+
end
|
46
57
|
|
47
58
|
before(:example) do
|
48
59
|
@key = OpenSSL::PKey::RSA.new(2048)
|
49
60
|
@client = UserRefreshCredentials.new(
|
50
|
-
StringIO.new(cred_json_text),
|
51
|
-
'https://www.googleapis.com/auth/userinfo.profile'
|
61
|
+
json_key_io: StringIO.new(cred_json_text),
|
62
|
+
scope: 'https://www.googleapis.com/auth/userinfo.profile'
|
63
|
+
)
|
52
64
|
end
|
53
65
|
|
54
66
|
def make_auth_stubs(opts = {})
|
@@ -64,12 +76,6 @@ describe Google::Auth::UserRefreshCredentials do
|
|
64
76
|
end
|
65
77
|
|
66
78
|
def cred_json_text(missing = nil)
|
67
|
-
cred_json = {
|
68
|
-
client_secret: 'privatekey',
|
69
|
-
client_id: 'client123',
|
70
|
-
refresh_token: 'refreshtoken',
|
71
|
-
type: 'authorized_user'
|
72
|
-
}
|
73
79
|
cred_json.delete(missing.to_sym) unless missing.nil?
|
74
80
|
MultiJson.dump(cred_json)
|
75
81
|
end
|
@@ -78,14 +84,18 @@ describe Google::Auth::UserRefreshCredentials do
|
|
78
84
|
|
79
85
|
describe '#from_env' do
|
80
86
|
before(:example) do
|
81
|
-
@var_name =
|
82
|
-
@
|
87
|
+
@var_name = ENV_VAR
|
88
|
+
@credential_vars = [
|
89
|
+
ENV_VAR, CLIENT_ID_VAR, CLIENT_SECRET_VAR, REFRESH_TOKEN_VAR,
|
90
|
+
ACCOUNT_TYPE_VAR]
|
91
|
+
@original_env_vals = {}
|
92
|
+
@credential_vars.each { |var| @original_env_vals[var] = ENV[var] }
|
83
93
|
@scope = 'https://www.googleapis.com/auth/userinfo.profile'
|
84
94
|
@clz = UserRefreshCredentials
|
85
95
|
end
|
86
96
|
|
87
97
|
after(:example) do
|
88
|
-
ENV[
|
98
|
+
@credential_vars.each { |var| ENV[var] = @original_env_vals[var] }
|
89
99
|
end
|
90
100
|
|
91
101
|
it 'returns nil if the GOOGLE_APPLICATION_CREDENTIALS is unset' do
|
@@ -99,7 +109,7 @@ describe Google::Auth::UserRefreshCredentials do
|
|
99
109
|
Dir.mktmpdir do |dir|
|
100
110
|
key_path = File.join(dir, 'does-not-exist')
|
101
111
|
ENV[@var_name] = key_path
|
102
|
-
expect { @clz.from_env(@scope) }.to raise_error
|
112
|
+
expect { @clz.from_env(@scope) }.to raise_error RuntimeError
|
103
113
|
end
|
104
114
|
end
|
105
115
|
|
@@ -111,7 +121,7 @@ describe Google::Auth::UserRefreshCredentials do
|
|
111
121
|
FileUtils.mkdir_p(File.dirname(key_path))
|
112
122
|
File.write(key_path, cred_json_text(missing))
|
113
123
|
ENV[@var_name] = key_path
|
114
|
-
expect { @clz.from_env(@scope) }.to raise_error
|
124
|
+
expect { @clz.from_env(@scope) }.to raise_error RuntimeError
|
115
125
|
end
|
116
126
|
end
|
117
127
|
end
|
@@ -125,13 +135,25 @@ describe Google::Auth::UserRefreshCredentials do
|
|
125
135
|
expect(@clz.from_env(@scope)).to_not be_nil
|
126
136
|
end
|
127
137
|
end
|
138
|
+
|
139
|
+
it 'succeeds when GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET, and '\
|
140
|
+
'GOOGLE_REFRESH_TOKEN env vars are valid' do
|
141
|
+
ENV[CLIENT_ID_VAR] = cred_json[:client_id]
|
142
|
+
ENV[CLIENT_SECRET_VAR] = cred_json[:client_secret]
|
143
|
+
ENV[REFRESH_TOKEN_VAR] = cred_json[:refresh_token]
|
144
|
+
ENV[ACCOUNT_TYPE_VAR] = cred_json[:type]
|
145
|
+
expect(@clz.from_env(@scope)).to_not be_nil
|
146
|
+
expect(subject.client_id).to eq(cred_json[:client_id])
|
147
|
+
expect(subject.client_secret).to eq(cred_json[:client_secret])
|
148
|
+
expect(subject.refresh_token).to eq(cred_json[:refresh_token])
|
149
|
+
end
|
128
150
|
end
|
129
151
|
|
130
152
|
describe '#from_well_known_path' do
|
131
153
|
before(:example) do
|
132
154
|
@home = ENV['HOME']
|
133
155
|
@scope = 'https://www.googleapis.com/auth/userinfo.profile'
|
134
|
-
@known_path =
|
156
|
+
@known_path = WELL_KNOWN_PATH
|
135
157
|
@clz = UserRefreshCredentials
|
136
158
|
end
|
137
159
|
|
@@ -152,7 +174,8 @@ describe Google::Auth::UserRefreshCredentials do
|
|
152
174
|
FileUtils.mkdir_p(File.dirname(key_path))
|
153
175
|
File.write(key_path, cred_json_text(missing))
|
154
176
|
ENV['HOME'] = dir
|
155
|
-
expect { @clz.
|
177
|
+
expect { @clz.from_well_known_path(@scope) }
|
178
|
+
.to raise_error RuntimeError
|
156
179
|
end
|
157
180
|
end
|
158
181
|
end
|
@@ -167,4 +190,41 @@ describe Google::Auth::UserRefreshCredentials do
|
|
167
190
|
end
|
168
191
|
end
|
169
192
|
end
|
193
|
+
|
194
|
+
describe '#from_system_default_path' do
|
195
|
+
before(:example) do
|
196
|
+
@scope = 'https://www.googleapis.com/auth/userinfo.profile'
|
197
|
+
@path = File.join('/etc/google/auth/', CREDENTIALS_FILE_NAME)
|
198
|
+
@clz = UserRefreshCredentials
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'is nil if no file exists' do
|
202
|
+
FakeFS do
|
203
|
+
expect(UserRefreshCredentials.from_system_default_path(@scope))
|
204
|
+
.to be_nil
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'fails if the file is invalid' do
|
209
|
+
needed = %w(client_id client_secret refresh_token)
|
210
|
+
needed.each do |missing|
|
211
|
+
FakeFS do
|
212
|
+
FileUtils.mkdir_p(File.dirname(@path))
|
213
|
+
File.write(@path, cred_json_text(missing))
|
214
|
+
expect { @clz.from_system_default_path(@scope) }
|
215
|
+
.to raise_error RuntimeError
|
216
|
+
File.delete(@path)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'successfully loads the file when it is present' do
|
222
|
+
FakeFS do
|
223
|
+
FileUtils.mkdir_p(File.dirname(@path))
|
224
|
+
File.write(@path, cred_json_text)
|
225
|
+
expect(@clz.from_system_default_path(@scope)).to_not be_nil
|
226
|
+
File.delete(@path)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
170
230
|
end
|
metadata
CHANGED
@@ -1,178 +1,192 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: googleauth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Emiola
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-08-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
+
type: :runtime
|
14
15
|
name: faraday
|
16
|
+
prerelease: false
|
15
17
|
requirement: !ruby/object:Gem::Requirement
|
16
18
|
requirements:
|
17
19
|
- - "~>"
|
18
20
|
- !ruby/object:Gem::Version
|
19
21
|
version: '0.9'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0.9'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
+
type: :runtime
|
28
29
|
name: logging
|
30
|
+
prerelease: false
|
29
31
|
requirement: !ruby/object:Gem::Requirement
|
30
32
|
requirements:
|
31
33
|
- - "~>"
|
32
34
|
- !ruby/object:Gem::Version
|
33
35
|
version: '2.0'
|
34
|
-
type: :runtime
|
35
|
-
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '2.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
+
type: :runtime
|
42
43
|
name: jwt
|
44
|
+
prerelease: false
|
43
45
|
requirement: !ruby/object:Gem::Requirement
|
44
46
|
requirements:
|
45
47
|
- - "~>"
|
46
48
|
- !ruby/object:Gem::Version
|
47
49
|
version: '1.4'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.4'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
+
type: :runtime
|
56
57
|
name: memoist
|
58
|
+
prerelease: false
|
57
59
|
requirement: !ruby/object:Gem::Requirement
|
58
60
|
requirements:
|
59
61
|
- - "~>"
|
60
62
|
- !ruby/object:Gem::Version
|
61
63
|
version: '0.12'
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0.12'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
+
type: :runtime
|
70
71
|
name: multi_json
|
72
|
+
prerelease: false
|
71
73
|
requirement: !ruby/object:Gem::Requirement
|
72
74
|
requirements:
|
73
|
-
- -
|
75
|
+
- - "~>"
|
74
76
|
- !ruby/object:Gem::Version
|
75
77
|
version: '1.11'
|
76
|
-
type: :runtime
|
77
|
-
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '1.11'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
+
type: :runtime
|
84
85
|
name: signet
|
86
|
+
prerelease: false
|
85
87
|
requirement: !ruby/object:Gem::Requirement
|
86
88
|
requirements:
|
87
89
|
- - "~>"
|
88
90
|
- !ruby/object:Gem::Version
|
89
91
|
version: '0.6'
|
90
|
-
type: :runtime
|
91
|
-
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0.6'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
+
type: :development
|
98
99
|
name: bundler
|
100
|
+
prerelease: false
|
99
101
|
requirement: !ruby/object:Gem::Requirement
|
100
102
|
requirements:
|
101
103
|
- - "~>"
|
102
104
|
- !ruby/object:Gem::Version
|
103
105
|
version: '1.9'
|
104
|
-
type: :development
|
105
|
-
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '1.9'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
+
type: :development
|
112
113
|
name: simplecov
|
114
|
+
prerelease: false
|
113
115
|
requirement: !ruby/object:Gem::Requirement
|
114
116
|
requirements:
|
115
117
|
- - "~>"
|
116
118
|
- !ruby/object:Gem::Version
|
117
119
|
version: '0.9'
|
118
|
-
type: :development
|
119
|
-
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0.9'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
+
type: :development
|
126
127
|
name: coveralls
|
128
|
+
prerelease: false
|
127
129
|
requirement: !ruby/object:Gem::Requirement
|
128
130
|
requirements:
|
129
131
|
- - "~>"
|
130
132
|
- !ruby/object:Gem::Version
|
131
133
|
version: '0.7'
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0.7'
|
139
|
+
- !ruby/object:Gem::Dependency
|
132
140
|
type: :development
|
141
|
+
name: fakefs
|
133
142
|
prerelease: false
|
143
|
+
requirement: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - "~>"
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0.6'
|
134
148
|
version_requirements: !ruby/object:Gem::Requirement
|
135
149
|
requirements:
|
136
150
|
- - "~>"
|
137
151
|
- !ruby/object:Gem::Version
|
138
|
-
version: '0.
|
152
|
+
version: '0.6'
|
139
153
|
- !ruby/object:Gem::Dependency
|
154
|
+
type: :development
|
140
155
|
name: rake
|
156
|
+
prerelease: false
|
141
157
|
requirement: !ruby/object:Gem::Requirement
|
142
158
|
requirements:
|
143
159
|
- - "~>"
|
144
160
|
- !ruby/object:Gem::Version
|
145
161
|
version: '10.0'
|
146
|
-
type: :development
|
147
|
-
prerelease: false
|
148
162
|
version_requirements: !ruby/object:Gem::Requirement
|
149
163
|
requirements:
|
150
164
|
- - "~>"
|
151
165
|
- !ruby/object:Gem::Version
|
152
166
|
version: '10.0'
|
153
167
|
- !ruby/object:Gem::Dependency
|
168
|
+
type: :development
|
154
169
|
name: rubocop
|
170
|
+
prerelease: false
|
155
171
|
requirement: !ruby/object:Gem::Requirement
|
156
172
|
requirements:
|
157
173
|
- - "~>"
|
158
174
|
- !ruby/object:Gem::Version
|
159
175
|
version: '0.30'
|
160
|
-
type: :development
|
161
|
-
prerelease: false
|
162
176
|
version_requirements: !ruby/object:Gem::Requirement
|
163
177
|
requirements:
|
164
178
|
- - "~>"
|
165
179
|
- !ruby/object:Gem::Version
|
166
180
|
version: '0.30'
|
167
181
|
- !ruby/object:Gem::Dependency
|
182
|
+
type: :development
|
168
183
|
name: rspec
|
184
|
+
prerelease: false
|
169
185
|
requirement: !ruby/object:Gem::Requirement
|
170
186
|
requirements:
|
171
187
|
- - "~>"
|
172
188
|
- !ruby/object:Gem::Version
|
173
189
|
version: '3.0'
|
174
|
-
type: :development
|
175
|
-
prerelease: false
|
176
190
|
version_requirements: !ruby/object:Gem::Requirement
|
177
191
|
requirements:
|
178
192
|
- - "~>"
|
@@ -202,6 +216,7 @@ files:
|
|
202
216
|
- lib/googleauth.rb
|
203
217
|
- lib/googleauth/compute_engine.rb
|
204
218
|
- lib/googleauth/credentials_loader.rb
|
219
|
+
- lib/googleauth/iam.rb
|
205
220
|
- lib/googleauth/service_account.rb
|
206
221
|
- lib/googleauth/signet.rb
|
207
222
|
- lib/googleauth/user_refresh.rb
|
@@ -209,6 +224,7 @@ files:
|
|
209
224
|
- spec/googleauth/apply_auth_examples.rb
|
210
225
|
- spec/googleauth/compute_engine_spec.rb
|
211
226
|
- spec/googleauth/get_application_default_spec.rb
|
227
|
+
- spec/googleauth/iam_spec.rb
|
212
228
|
- spec/googleauth/service_account_spec.rb
|
213
229
|
- spec/googleauth/signet_spec.rb
|
214
230
|
- spec/googleauth/user_refresh_spec.rb
|
@@ -233,7 +249,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
233
249
|
version: '0'
|
234
250
|
requirements: []
|
235
251
|
rubyforge_project:
|
236
|
-
rubygems_version: 2.4.
|
252
|
+
rubygems_version: 2.4.8
|
237
253
|
signing_key:
|
238
254
|
specification_version: 4
|
239
255
|
summary: Google Auth Library for Ruby
|
@@ -241,6 +257,7 @@ test_files:
|
|
241
257
|
- spec/googleauth/apply_auth_examples.rb
|
242
258
|
- spec/googleauth/compute_engine_spec.rb
|
243
259
|
- spec/googleauth/get_application_default_spec.rb
|
260
|
+
- spec/googleauth/iam_spec.rb
|
244
261
|
- spec/googleauth/service_account_spec.rb
|
245
262
|
- spec/googleauth/signet_spec.rb
|
246
263
|
- spec/googleauth/user_refresh_spec.rb
|