googleauth 0.5.3 → 0.6.0
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/.travis.yml +1 -1
- data/CONTRIBUTING.md +5 -4
- data/Gemfile +1 -1
- data/README.md +3 -3
- data/googleauth.gemspec +1 -1
- data/lib/googleauth.rb +3 -93
- data/lib/googleauth/application_default.rb +67 -0
- data/lib/googleauth/credentials.rb +177 -0
- data/lib/googleauth/default_credentials.rb +91 -0
- data/lib/googleauth/user_authorizer.rb +1 -1
- data/lib/googleauth/version.rb +1 -1
- data/spec/googleauth/credentials_spec.rb +108 -0
- data/spec/googleauth/service_account_spec.rb +3 -2
- data/spec/googleauth/signet_spec.rb +2 -1
- data/spec/googleauth/user_refresh_spec.rb +1 -1
- metadata +16 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cec38ca5e660e992fb100c34682b8c0091424cd0
|
4
|
+
data.tar.gz: 791afd4f7ed5f55b7a2e506f8fa7f9f9e4754135
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0814d5fd8fc3a00d296dd9c9ad9b72dff84aec4e009d35930589435053307bf00b3296b1c30fab74a451cfdde3165df5b8b1d5c949d9476ed81d6e1ca838d02e
|
7
|
+
data.tar.gz: 9b83bbe09b924617fdad6f7d3853e17991c63db0ddf3c3be0283fce9e03cd16c881941cee7a09e549e38af1e0e604e7ac520cd13000d45d845e94446a1bb511b
|
data/.travis.yml
CHANGED
data/CONTRIBUTING.md
CHANGED
@@ -9,11 +9,12 @@ Please fill out either the individual or corporate Contributor License Agreement
|
|
9
9
|
(CLA).
|
10
10
|
|
11
11
|
* If you are an individual writing original source code and you're sure you
|
12
|
-
own the intellectual property, then you'll need to sign an [individual CLA]
|
13
|
-
(http://code.google.com/legal/individual-cla-v1.0.html).
|
12
|
+
own the intellectual property, then you'll need to sign an [individual CLA].
|
14
13
|
* If you work for a company that wants to allow you to contribute your work,
|
15
|
-
then you'll need to sign a [corporate CLA]
|
16
|
-
|
14
|
+
then you'll need to sign a [corporate CLA].
|
15
|
+
|
16
|
+
[individual CLA]: http://code.google.com/legal/individual-cla-v1.0.html
|
17
|
+
[corporate CLA]: http://code.google.com/legal/corporate-cla-v1.0.html
|
17
18
|
|
18
19
|
Follow either of the two links above to access the appropriate CLA and
|
19
20
|
instructions for how to sign and return it. Once we receive it, we'll be able to
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -8,9 +8,9 @@
|
|
8
8
|
</dl>
|
9
9
|
|
10
10
|
[](http://badge.fury.io/rb/googleauth)
|
11
|
-
[](http://travis-ci.org/google/google-auth-library-ruby)
|
12
|
+
[](https://coveralls.io/r/google/google-auth-library-ruby)
|
13
|
+
[](https://gemnasium.com/google/google-auth-library-ruby)
|
14
14
|
|
15
15
|
## Description
|
16
16
|
|
data/googleauth.gemspec
CHANGED
@@ -28,7 +28,7 @@ Gem::Specification.new do |s|
|
|
28
28
|
|
29
29
|
s.add_dependency 'faraday', '~> 0.12'
|
30
30
|
s.add_dependency 'logging', '~> 2.0'
|
31
|
-
s.add_dependency 'jwt', '
|
31
|
+
s.add_dependency 'jwt', '>= 1.4', '< 3.0'
|
32
32
|
s.add_dependency 'memoist', '~> 0.12'
|
33
33
|
s.add_dependency 'multi_json', '~> 1.11'
|
34
34
|
s.add_dependency 'os', '~> 0.9'
|
data/lib/googleauth.rb
CHANGED
@@ -27,99 +27,9 @@
|
|
27
27
|
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
28
28
|
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
29
|
|
30
|
-
require '
|
31
|
-
require 'stringio'
|
32
|
-
|
33
|
-
require 'googleauth/credentials_loader'
|
34
|
-
require 'googleauth/compute_engine'
|
35
|
-
require 'googleauth/service_account'
|
36
|
-
require 'googleauth/user_refresh'
|
30
|
+
require 'googleauth/application_default'
|
37
31
|
require 'googleauth/client_id'
|
32
|
+
require 'googleauth/credentials'
|
33
|
+
require 'googleauth/default_credentials'
|
38
34
|
require 'googleauth/user_authorizer'
|
39
35
|
require 'googleauth/web_user_authorizer'
|
40
|
-
|
41
|
-
module Google
|
42
|
-
# Module Auth provides classes that provide Google-specific authorization
|
43
|
-
# used to access Google APIs.
|
44
|
-
module Auth
|
45
|
-
NOT_FOUND_ERROR = <<END.freeze
|
46
|
-
Could not load the default credentials. Browse to
|
47
|
-
https://developers.google.com/accounts/docs/application-default-credentials
|
48
|
-
for more information
|
49
|
-
END
|
50
|
-
|
51
|
-
# DefaultCredentials is used to preload the credentials file, to determine
|
52
|
-
# which type of credentials should be loaded.
|
53
|
-
class DefaultCredentials
|
54
|
-
extend CredentialsLoader
|
55
|
-
|
56
|
-
# override CredentialsLoader#make_creds to use the class determined by
|
57
|
-
# loading the json.
|
58
|
-
def self.make_creds(options = {})
|
59
|
-
json_key_io, scope = options.values_at(:json_key_io, :scope)
|
60
|
-
if json_key_io
|
61
|
-
json_key, clz = determine_creds_class(json_key_io)
|
62
|
-
clz.make_creds(json_key_io: StringIO.new(MultiJson.dump(json_key)),
|
63
|
-
scope: scope)
|
64
|
-
else
|
65
|
-
clz = read_creds
|
66
|
-
clz.make_creds(scope: scope)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def self.read_creds
|
71
|
-
env_var = CredentialsLoader::ACCOUNT_TYPE_VAR
|
72
|
-
type = ENV[env_var]
|
73
|
-
raise "#{env_var} is undefined in env" unless type
|
74
|
-
case type
|
75
|
-
when 'service_account'
|
76
|
-
ServiceAccountCredentials
|
77
|
-
when 'authorized_user'
|
78
|
-
UserRefreshCredentials
|
79
|
-
else
|
80
|
-
raise "credentials type '#{type}' is not supported"
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
# Reads the input json and determines which creds class to use.
|
85
|
-
def self.determine_creds_class(json_key_io)
|
86
|
-
json_key = MultiJson.load(json_key_io.read)
|
87
|
-
key = 'type'
|
88
|
-
raise "the json is missing the '#{key}' field" unless json_key.key?(key)
|
89
|
-
type = json_key[key]
|
90
|
-
case type
|
91
|
-
when 'service_account'
|
92
|
-
[json_key, ServiceAccountCredentials]
|
93
|
-
when 'authorized_user'
|
94
|
-
[json_key, UserRefreshCredentials]
|
95
|
-
else
|
96
|
-
raise "credentials type '#{type}' is not supported"
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
# Obtains the default credentials implementation to use in this
|
102
|
-
# environment.
|
103
|
-
#
|
104
|
-
# Use this to obtain the Application Default Credentials for accessing
|
105
|
-
# Google APIs. Application Default Credentials are described in detail
|
106
|
-
# at http://goo.gl/IUuyuX.
|
107
|
-
#
|
108
|
-
# If supplied, scope is used to create the credentials instance, when it can
|
109
|
-
# be applied. E.g, on google compute engine and for user credentials the
|
110
|
-
# scope is ignored.
|
111
|
-
#
|
112
|
-
# @param scope [string|array|nil] the scope(s) to access
|
113
|
-
# @param options [hash] allows override of the connection being used
|
114
|
-
def get_application_default(scope = nil, options = {})
|
115
|
-
creds = DefaultCredentials.from_env(scope) ||
|
116
|
-
DefaultCredentials.from_well_known_path(scope) ||
|
117
|
-
DefaultCredentials.from_system_default_path(scope)
|
118
|
-
return creds unless creds.nil?
|
119
|
-
raise NOT_FOUND_ERROR unless GCECredentials.on_gce?(options)
|
120
|
-
GCECredentials.new
|
121
|
-
end
|
122
|
-
|
123
|
-
module_function :get_application_default
|
124
|
-
end
|
125
|
-
end
|
@@ -0,0 +1,67 @@
|
|
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/compute_engine'
|
31
|
+
require 'googleauth/default_credentials'
|
32
|
+
|
33
|
+
module Google
|
34
|
+
# Module Auth provides classes that provide Google-specific authorization
|
35
|
+
# used to access Google APIs.
|
36
|
+
module Auth
|
37
|
+
NOT_FOUND_ERROR = <<ERROR_MESSAGE.freeze
|
38
|
+
Could not load the default credentials. Browse to
|
39
|
+
https://developers.google.com/accounts/docs/application-default-credentials
|
40
|
+
for more information
|
41
|
+
ERROR_MESSAGE
|
42
|
+
|
43
|
+
# Obtains the default credentials implementation to use in this
|
44
|
+
# environment.
|
45
|
+
#
|
46
|
+
# Use this to obtain the Application Default Credentials for accessing
|
47
|
+
# Google APIs. Application Default Credentials are described in detail
|
48
|
+
# at http://goo.gl/IUuyuX.
|
49
|
+
#
|
50
|
+
# If supplied, scope is used to create the credentials instance, when it can
|
51
|
+
# be applied. E.g, on google compute engine and for user credentials the
|
52
|
+
# scope is ignored.
|
53
|
+
#
|
54
|
+
# @param scope [string|array|nil] the scope(s) to access
|
55
|
+
# @param options [hash] allows override of the connection being used
|
56
|
+
def get_application_default(scope = nil, options = {})
|
57
|
+
creds = DefaultCredentials.from_env(scope) ||
|
58
|
+
DefaultCredentials.from_well_known_path(scope) ||
|
59
|
+
DefaultCredentials.from_system_default_path(scope)
|
60
|
+
return creds unless creds.nil?
|
61
|
+
raise NOT_FOUND_ERROR unless GCECredentials.on_gce?(options)
|
62
|
+
GCECredentials.new
|
63
|
+
end
|
64
|
+
|
65
|
+
module_function :get_application_default
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
# Copyright 2017, 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 'forwardable'
|
31
|
+
require 'json'
|
32
|
+
require 'signet/oauth_2/client'
|
33
|
+
|
34
|
+
require 'googleauth/default_credentials'
|
35
|
+
|
36
|
+
module Google
|
37
|
+
module Auth
|
38
|
+
# This class is intended to be inherited by API-specific classes
|
39
|
+
# which overrides the SCOPE constant.
|
40
|
+
class Credentials
|
41
|
+
TOKEN_CREDENTIAL_URI = 'https://accounts.google.com/o/oauth2/token'.freeze
|
42
|
+
AUDIENCE = 'https://accounts.google.com/o/oauth2/token'.freeze
|
43
|
+
SCOPE = [].freeze
|
44
|
+
PATH_ENV_VARS = [].freeze
|
45
|
+
JSON_ENV_VARS = [].freeze
|
46
|
+
DEFAULT_PATHS = [].freeze
|
47
|
+
|
48
|
+
attr_accessor :client
|
49
|
+
|
50
|
+
# Delegate client methods to the client object.
|
51
|
+
extend Forwardable
|
52
|
+
def_delegators :@client,
|
53
|
+
:token_credential_uri, :audience,
|
54
|
+
:scope, :issuer, :signing_key, :updater_proc
|
55
|
+
|
56
|
+
def initialize(keyfile, options = {})
|
57
|
+
scope = options[:scope]
|
58
|
+
verify_keyfile_provided! keyfile
|
59
|
+
if keyfile.is_a? Signet::OAuth2::Client
|
60
|
+
@client = keyfile
|
61
|
+
elsif keyfile.is_a? Hash
|
62
|
+
hash = stringify_hash_keys keyfile
|
63
|
+
hash['scope'] ||= scope
|
64
|
+
@client = init_client hash
|
65
|
+
else
|
66
|
+
verify_keyfile_exists! keyfile
|
67
|
+
json = JSON.parse ::File.read(keyfile)
|
68
|
+
json['scope'] ||= scope
|
69
|
+
@client = init_client json
|
70
|
+
end
|
71
|
+
@client.fetch_access_token!
|
72
|
+
end
|
73
|
+
|
74
|
+
# Returns the default credentials checking, in this order, the path env
|
75
|
+
# evironment variables, json environment variables, default paths. If the
|
76
|
+
# previously stated locations do not contain keyfile information,
|
77
|
+
# this method defaults to use the application default.
|
78
|
+
def self.default(options = {})
|
79
|
+
scope = options[:scope]
|
80
|
+
# First try to find keyfile file from environment variables.
|
81
|
+
client = from_path_vars(scope)
|
82
|
+
|
83
|
+
# Second try to find keyfile json from environment variables.
|
84
|
+
client ||= from_json_vars(scope)
|
85
|
+
|
86
|
+
# Third try to find keyfile file from known file paths.
|
87
|
+
client ||= from_default_vars(scope)
|
88
|
+
|
89
|
+
# Finally get instantiated client from Google::Auth
|
90
|
+
client ||= from_application_default(scope)
|
91
|
+
client
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.from_path_vars(scope)
|
95
|
+
self::PATH_ENV_VARS
|
96
|
+
.map { |v| ENV[v] }
|
97
|
+
.compact
|
98
|
+
.select { |p| ::File.file? p }
|
99
|
+
.each do |file|
|
100
|
+
return new file, scope: scope
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def self.from_json_vars(scope)
|
105
|
+
json = lambda do |v|
|
106
|
+
unless ENV[v].nil?
|
107
|
+
begin
|
108
|
+
JSON.parse ENV[v]
|
109
|
+
rescue
|
110
|
+
nil
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
self::JSON_ENV_VARS.map(&json).compact.each do |hash|
|
115
|
+
return new hash, scope: scope
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.from_default_paths(scope)
|
120
|
+
self::DEFAULT_PATHS
|
121
|
+
.select { |p| ::File.file? p }
|
122
|
+
.each do |file|
|
123
|
+
return new file, scope: scope
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.from_application_default(scope)
|
128
|
+
scope ||= self::SCOPE
|
129
|
+
client = Google::Auth.get_application_default scope
|
130
|
+
new client
|
131
|
+
end
|
132
|
+
private_class_method :from_path_vars,
|
133
|
+
:from_json_vars,
|
134
|
+
:from_default_paths,
|
135
|
+
:from_application_default
|
136
|
+
|
137
|
+
protected
|
138
|
+
|
139
|
+
# Verify that the keyfile argument is provided.
|
140
|
+
def verify_keyfile_provided!(keyfile)
|
141
|
+
return unless keyfile.nil?
|
142
|
+
raise 'The keyfile passed to Google::Auth::Credentials.new was nil.'
|
143
|
+
end
|
144
|
+
|
145
|
+
# Verify that the keyfile argument is a file.
|
146
|
+
def verify_keyfile_exists!(keyfile)
|
147
|
+
exists = ::File.file? keyfile
|
148
|
+
raise "The keyfile '#{keyfile}' is not a valid file." unless exists
|
149
|
+
end
|
150
|
+
|
151
|
+
# Initializes the Signet client.
|
152
|
+
def init_client(keyfile)
|
153
|
+
client_opts = client_options keyfile
|
154
|
+
Signet::OAuth2::Client.new client_opts
|
155
|
+
end
|
156
|
+
|
157
|
+
# returns a new Hash with string keys instead of symbol keys.
|
158
|
+
def stringify_hash_keys(hash)
|
159
|
+
Hash[hash.map { |k, v| [k.to_s, v] }]
|
160
|
+
end
|
161
|
+
|
162
|
+
def client_options(options)
|
163
|
+
# Keyfile options have higher priority over constructor defaults
|
164
|
+
options['token_credential_uri'] ||= self.class::TOKEN_CREDENTIAL_URI
|
165
|
+
options['audience'] ||= self.class::AUDIENCE
|
166
|
+
options['scope'] ||= self.class::SCOPE
|
167
|
+
|
168
|
+
# client options for initializing signet client
|
169
|
+
{ token_credential_uri: options['token_credential_uri'],
|
170
|
+
audience: options['audience'],
|
171
|
+
scope: Array(options['scope']),
|
172
|
+
issuer: options['client_email'],
|
173
|
+
signing_key: OpenSSL::PKey::RSA.new(options['private_key']) }
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,91 @@
|
|
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 'multi_json'
|
31
|
+
require 'stringio'
|
32
|
+
|
33
|
+
require 'googleauth/credentials_loader'
|
34
|
+
require 'googleauth/service_account'
|
35
|
+
require 'googleauth/user_refresh'
|
36
|
+
|
37
|
+
module Google
|
38
|
+
# Module Auth provides classes that provide Google-specific authorization
|
39
|
+
# used to access Google APIs.
|
40
|
+
module Auth
|
41
|
+
# DefaultCredentials is used to preload the credentials file, to determine
|
42
|
+
# which type of credentials should be loaded.
|
43
|
+
class DefaultCredentials
|
44
|
+
extend CredentialsLoader
|
45
|
+
|
46
|
+
# override CredentialsLoader#make_creds to use the class determined by
|
47
|
+
# loading the json.
|
48
|
+
def self.make_creds(options = {})
|
49
|
+
json_key_io, scope = options.values_at(:json_key_io, :scope)
|
50
|
+
if json_key_io
|
51
|
+
json_key, clz = determine_creds_class(json_key_io)
|
52
|
+
clz.make_creds(json_key_io: StringIO.new(MultiJson.dump(json_key)),
|
53
|
+
scope: scope)
|
54
|
+
else
|
55
|
+
clz = read_creds
|
56
|
+
clz.make_creds(scope: scope)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.read_creds
|
61
|
+
env_var = CredentialsLoader::ACCOUNT_TYPE_VAR
|
62
|
+
type = ENV[env_var]
|
63
|
+
raise "#{env_var} is undefined in env" unless type
|
64
|
+
case type
|
65
|
+
when 'service_account'
|
66
|
+
ServiceAccountCredentials
|
67
|
+
when 'authorized_user'
|
68
|
+
UserRefreshCredentials
|
69
|
+
else
|
70
|
+
raise "credentials type '#{type}' is not supported"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Reads the input json and determines which creds class to use.
|
75
|
+
def self.determine_creds_class(json_key_io)
|
76
|
+
json_key = MultiJson.load(json_key_io.read)
|
77
|
+
key = 'type'
|
78
|
+
raise "the json is missing the '#{key}' field" unless json_key.key?(key)
|
79
|
+
type = json_key[key]
|
80
|
+
case type
|
81
|
+
when 'service_account'
|
82
|
+
[json_key, ServiceAccountCredentials]
|
83
|
+
when 'authorized_user'
|
84
|
+
[json_key, UserRefreshCredentials]
|
85
|
+
else
|
86
|
+
raise "credentials type '#{type}' is not supported"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -276,7 +276,7 @@ module Google
|
|
276
276
|
def redirect_uri_for(base_url)
|
277
277
|
return @callback_uri unless URI(@callback_uri).scheme.nil?
|
278
278
|
if base_url.nil? || URI(base_url).scheme.nil?
|
279
|
-
raise sprintf(
|
279
|
+
raise sprintf(MISSING_ABSOLUTE_URL_ERROR, @callback_uri)
|
280
280
|
end
|
281
281
|
URI.join(base_url, @callback_uri).to_s
|
282
282
|
end
|
data/lib/googleauth/version.rb
CHANGED
@@ -0,0 +1,108 @@
|
|
1
|
+
# Copyright 2017, 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'
|
31
|
+
|
32
|
+
# This test is testing the private class Google::Auth::Credentials. We want to
|
33
|
+
# make sure that the passed in scope propogates to the Signet object. This means
|
34
|
+
# testing the private API, which is generally frowned on.
|
35
|
+
describe Google::Auth::Credentials, :private do
|
36
|
+
let(:default_keyfile_hash) do
|
37
|
+
{
|
38
|
+
'private_key_id' => 'testabc1234567890xyz',
|
39
|
+
'private_key' => "-----BEGIN RSA PRIVATE KEY-----\nMIIBOwIBAAJBAOyi0Hy1l4Ym2m2o71Q0TF4O9E81isZEsX0bb+Bqz1SXEaSxLiXM\nUZE8wu0eEXivXuZg6QVCW/5l+f2+9UPrdNUCAwEAAQJAJkqubA/Chj3RSL92guy3\nktzeodarLyw8gF8pOmpuRGSiEo/OLTeRUMKKD1/kX4f9sxf3qDhB4e7dulXR1co/\nIQIhAPx8kMW4XTTL6lJYd2K5GrH8uBMp8qL5ya3/XHrBgw3dAiEA7+3Iw3ULTn2I\n1J34WlJ2D5fbzMzB4FAHUNEV7Ys3f1kCIQDtUahCMChrl7+H5t9QS+xrn77lRGhs\nB50pjvy95WXpgQIhAI2joW6JzTfz8fAapb+kiJ/h9Vcs1ZN3iyoRlNFb61JZAiA8\nNy5NyNrMVwtB/lfJf1dAK/p/Bwd8LZLtgM6PapRfgw==\n-----END RSA PRIVATE KEY-----\n",
|
40
|
+
'client_email' => 'credz-testabc1234567890xyz@developer.gserviceaccount.com',
|
41
|
+
'client_id' => 'credz-testabc1234567890xyz.apps.googleusercontent.com',
|
42
|
+
'type' => 'service_account'
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'uses a default scope' do
|
47
|
+
mocked_signet = double('Signet::OAuth2::Client')
|
48
|
+
allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
|
49
|
+
allow(Signet::OAuth2::Client).to receive(:new) do |options|
|
50
|
+
expect(options[:token_credential_uri]).to eq('https://accounts.google.com/o/oauth2/token')
|
51
|
+
expect(options[:audience]).to eq('https://accounts.google.com/o/oauth2/token')
|
52
|
+
expect(options[:scope]).to eq([])
|
53
|
+
expect(options[:issuer]).to eq(default_keyfile_hash['client_email'])
|
54
|
+
expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
|
55
|
+
|
56
|
+
mocked_signet
|
57
|
+
end
|
58
|
+
|
59
|
+
Google::Auth::Credentials.new default_keyfile_hash
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'uses a custom scope' do
|
63
|
+
mocked_signet = double('Signet::OAuth2::Client')
|
64
|
+
allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
|
65
|
+
allow(Signet::OAuth2::Client).to receive(:new) do |options|
|
66
|
+
expect(options[:token_credential_uri]).to eq('https://accounts.google.com/o/oauth2/token')
|
67
|
+
expect(options[:audience]).to eq('https://accounts.google.com/o/oauth2/token')
|
68
|
+
expect(options[:scope]).to eq(['http://example.com/scope'])
|
69
|
+
expect(options[:issuer]).to eq(default_keyfile_hash['client_email'])
|
70
|
+
expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
|
71
|
+
|
72
|
+
mocked_signet
|
73
|
+
end
|
74
|
+
|
75
|
+
Google::Auth::Credentials.new default_keyfile_hash, scope: 'http://example.com/scope'
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'can be subclassed to pass in other env paths' do
|
79
|
+
TEST_PATH_ENV_VAR = 'TEST_PATH'.freeze
|
80
|
+
TEST_PATH_ENV_VAL = '/unknown/path/to/file.txt'.freeze
|
81
|
+
TEST_JSON_ENV_VAR = 'TEST_JSON_VARS'.freeze
|
82
|
+
|
83
|
+
ENV[TEST_PATH_ENV_VAR] = TEST_PATH_ENV_VAL
|
84
|
+
ENV[TEST_JSON_ENV_VAR] = JSON.generate(default_keyfile_hash)
|
85
|
+
|
86
|
+
class TestCredentials < Google::Auth::Credentials
|
87
|
+
SCOPE = 'http://example.com/scope'.freeze
|
88
|
+
PATH_ENV_VARS = [TEST_PATH_ENV_VAR].freeze
|
89
|
+
JSON_ENV_VARS = [TEST_JSON_ENV_VAR].freeze
|
90
|
+
end
|
91
|
+
|
92
|
+
allow(::File).to receive(:file?).with(TEST_PATH_ENV_VAL) { false }
|
93
|
+
|
94
|
+
mocked_signet = double('Signet::OAuth2::Client')
|
95
|
+
allow(mocked_signet).to receive(:fetch_access_token!).and_return(true)
|
96
|
+
allow(Signet::OAuth2::Client).to receive(:new) do |options|
|
97
|
+
expect(options[:token_credential_uri]).to eq('https://accounts.google.com/o/oauth2/token')
|
98
|
+
expect(options[:audience]).to eq('https://accounts.google.com/o/oauth2/token')
|
99
|
+
expect(options[:scope]).to eq(['http://example.com/scope'])
|
100
|
+
expect(options[:issuer]).to eq(default_keyfile_hash['client_email'])
|
101
|
+
expect(options[:signing_key]).to be_a_kind_of(OpenSSL::PKey::RSA)
|
102
|
+
|
103
|
+
mocked_signet
|
104
|
+
end
|
105
|
+
|
106
|
+
TestCredentials.default
|
107
|
+
end
|
108
|
+
end
|
@@ -54,7 +54,7 @@ shared_examples 'jwt header auth' do
|
|
54
54
|
expect(hdr).to_not be_nil
|
55
55
|
expect(hdr.start_with?(auth_prefix)).to be true
|
56
56
|
authorization = hdr[auth_prefix.length..-1]
|
57
|
-
payload, = JWT.decode(authorization, @key.public_key)
|
57
|
+
payload, = JWT.decode(authorization, @key.public_key, true, algorithm: 'RS256')
|
58
58
|
expect(payload['aud']).to eq(test_uri)
|
59
59
|
expect(payload['iss']).to eq(client_email)
|
60
60
|
end
|
@@ -135,7 +135,8 @@ describe Google::Auth::ServiceAccountCredentials do
|
|
135
135
|
blk = proc do |request|
|
136
136
|
params = Addressable::URI.form_unencode(request.body)
|
137
137
|
_claim, _header = JWT.decode(params.assoc('assertion').last,
|
138
|
-
@key.public_key
|
138
|
+
@key.public_key, true,
|
139
|
+
algorithm: 'RS256')
|
139
140
|
end
|
140
141
|
stub_request(:post, 'https://www.googleapis.com/oauth2/v4/token')
|
141
142
|
.with(body: hash_including(
|
@@ -57,7 +57,8 @@ describe Signet::OAuth2::Client do
|
|
57
57
|
blk = proc do |request|
|
58
58
|
params = Addressable::URI.form_unencode(request.body)
|
59
59
|
_claim, _header = JWT.decode(params.assoc('assertion').last,
|
60
|
-
@key.public_key
|
60
|
+
@key.public_key, true,
|
61
|
+
algorithm: 'RS256')
|
61
62
|
end
|
62
63
|
stub_request(:post, 'https://accounts.google.com/o/oauth2/token')
|
63
64
|
.with(body: hash_including(
|
@@ -294,7 +294,7 @@ describe Google::Auth::UserRefreshCredentials do
|
|
294
294
|
end
|
295
295
|
end
|
296
296
|
|
297
|
-
describe 'when erros
|
297
|
+
describe 'when erros occurred with request' do
|
298
298
|
it 'should fail with Signet::AuthorizationError if request times out' do
|
299
299
|
allow_any_instance_of(Faraday::Connection).to receive(:get)
|
300
300
|
.and_raise(Faraday::TimeoutError)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: googleauth
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tim Emiola
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -42,16 +42,22 @@ dependencies:
|
|
42
42
|
name: jwt
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '1.4'
|
48
|
+
- - "<"
|
49
|
+
- !ruby/object:Gem::Version
|
50
|
+
version: '3.0'
|
48
51
|
type: :runtime
|
49
52
|
prerelease: false
|
50
53
|
version_requirements: !ruby/object:Gem::Requirement
|
51
54
|
requirements:
|
52
|
-
- - "
|
55
|
+
- - ">="
|
53
56
|
- !ruby/object:Gem::Version
|
54
57
|
version: '1.4'
|
58
|
+
- - "<"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '3.0'
|
55
61
|
- !ruby/object:Gem::Dependency
|
56
62
|
name: memoist
|
57
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -129,9 +135,12 @@ files:
|
|
129
135
|
- Rakefile
|
130
136
|
- googleauth.gemspec
|
131
137
|
- lib/googleauth.rb
|
138
|
+
- lib/googleauth/application_default.rb
|
132
139
|
- lib/googleauth/client_id.rb
|
133
140
|
- lib/googleauth/compute_engine.rb
|
141
|
+
- lib/googleauth/credentials.rb
|
134
142
|
- lib/googleauth/credentials_loader.rb
|
143
|
+
- lib/googleauth/default_credentials.rb
|
135
144
|
- lib/googleauth/iam.rb
|
136
145
|
- lib/googleauth/scope_util.rb
|
137
146
|
- lib/googleauth/service_account.rb
|
@@ -146,6 +155,7 @@ files:
|
|
146
155
|
- spec/googleauth/apply_auth_examples.rb
|
147
156
|
- spec/googleauth/client_id_spec.rb
|
148
157
|
- spec/googleauth/compute_engine_spec.rb
|
158
|
+
- spec/googleauth/credentials_spec.rb
|
149
159
|
- spec/googleauth/get_application_default_spec.rb
|
150
160
|
- spec/googleauth/iam_spec.rb
|
151
161
|
- spec/googleauth/scope_util_spec.rb
|
@@ -178,7 +188,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
178
188
|
version: '0'
|
179
189
|
requirements: []
|
180
190
|
rubyforge_project:
|
181
|
-
rubygems_version: 2.
|
191
|
+
rubygems_version: 2.4.8
|
182
192
|
signing_key:
|
183
193
|
specification_version: 4
|
184
194
|
summary: Google Auth Library for Ruby
|
@@ -186,6 +196,7 @@ test_files:
|
|
186
196
|
- spec/googleauth/apply_auth_examples.rb
|
187
197
|
- spec/googleauth/client_id_spec.rb
|
188
198
|
- spec/googleauth/compute_engine_spec.rb
|
199
|
+
- spec/googleauth/credentials_spec.rb
|
189
200
|
- spec/googleauth/get_application_default_spec.rb
|
190
201
|
- spec/googleauth/iam_spec.rb
|
191
202
|
- spec/googleauth/scope_util_spec.rb
|