googleauth 1.6.0 → 1.8.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/CHANGELOG.md +18 -0
- data/README.md +1 -1
- data/lib/googleauth/application_default.rb +2 -2
- data/lib/googleauth/client_id.rb +25 -7
- data/lib/googleauth/compute_engine.rb +23 -15
- data/lib/googleauth/credentials_loader.rb +5 -4
- data/lib/googleauth/external_account/external_account_utils.rb +11 -0
- data/lib/googleauth/external_account/pluggable_credentials.rb +156 -0
- data/lib/googleauth/external_account.rb +4 -0
- data/lib/googleauth/id_tokens.rb +2 -2
- data/lib/googleauth/scope_util.rb +35 -2
- data/lib/googleauth/user_authorizer.rb +12 -5
- data/lib/googleauth/version.rb +1 -1
- metadata +4 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 888e57705b33e87158d060b7b1569e54e00000428de35f979e7ffc9456cbb7b3
|
4
|
+
data.tar.gz: ac341b6c481df125091c1465b56642173591f5698baff6f4806b05216eca8802
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e9d2fd50c39bf83e86f9f31bbddb897d28ce908be1214849926c45ce7ad2fa0d8f48d70a01acc84c9fa49ddf1a3a3c0c5a87b9bdf1d3ae1b9430b739e709c67
|
7
|
+
data.tar.gz: f92483b4971ecc9d48a0b3656a76c694974c6b60153d6ea5ff0f1dd6c544da51b924aedbfa71956db2c1dada98a6cdaa632bb6f38c663e384acc8ebb3af8d1d2
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,23 @@
|
|
1
1
|
# Release History
|
2
2
|
|
3
|
+
### 1.8.0 (2023-09-07)
|
4
|
+
|
5
|
+
#### Features
|
6
|
+
|
7
|
+
* Pass additional parameters to auhtorization url ([#447](https://github.com/googleapis/google-auth-library-ruby/issues/447))
|
8
|
+
#### Documentation
|
9
|
+
|
10
|
+
* improve ADC related error and warning messages ([#449](https://github.com/googleapis/google-auth-library-ruby/issues/449))
|
11
|
+
|
12
|
+
### 1.7.0 (2023-07-14)
|
13
|
+
|
14
|
+
#### Features
|
15
|
+
|
16
|
+
* Adding support for pluggable auth credentials ([#437](https://github.com/googleapis/google-auth-library-ruby/issues/437))
|
17
|
+
#### Documentation
|
18
|
+
|
19
|
+
* fixed iss argument and description in comments of IDTokens ([#438](https://github.com/googleapis/google-auth-library-ruby/issues/438))
|
20
|
+
|
3
21
|
### 1.6.0 (2023-06-20)
|
4
22
|
|
5
23
|
#### Features
|
data/README.md
CHANGED
@@ -243,6 +243,6 @@ hesitate to
|
|
243
243
|
[ask questions](http://stackoverflow.com/questions/tagged/google-auth-library-ruby)
|
244
244
|
about the client or APIs on [StackOverflow](http://stackoverflow.com).
|
245
245
|
|
246
|
-
[application default credentials]: https://
|
246
|
+
[application default credentials]: https://cloud.google.com/docs/authentication/provide-credentials-adc
|
247
247
|
[contributing]: https://github.com/googleapis/google-auth-library-ruby/tree/main/.github/CONTRIBUTING.md
|
248
248
|
[license]: https://github.com/googleapis/google-auth-library-ruby/tree/main/LICENSE
|
@@ -21,7 +21,7 @@ module Google
|
|
21
21
|
module Auth
|
22
22
|
NOT_FOUND_ERROR = <<~ERROR_MESSAGE.freeze
|
23
23
|
Could not load the default credentials. Browse to
|
24
|
-
https://
|
24
|
+
https://cloud.google.com/docs/authentication/provide-credentials-adc
|
25
25
|
for more information
|
26
26
|
ERROR_MESSAGE
|
27
27
|
|
@@ -57,7 +57,7 @@ module Google
|
|
57
57
|
return creds unless creds.nil?
|
58
58
|
unless GCECredentials.on_gce? options
|
59
59
|
# Clear cache of the result of GCECredentials.on_gce?
|
60
|
-
GCECredentials.
|
60
|
+
GCECredentials.reset_cache
|
61
61
|
raise NOT_FOUND_ERROR
|
62
62
|
end
|
63
63
|
GCECredentials.new options.merge(scope: scope)
|
data/lib/googleauth/client_id.rb
CHANGED
@@ -17,37 +17,52 @@ require "googleauth/credentials_loader"
|
|
17
17
|
|
18
18
|
module Google
|
19
19
|
module Auth
|
20
|
-
|
21
|
-
# flows.
|
20
|
+
##
|
21
|
+
# Representation of an application's identity for user authorization flows.
|
22
|
+
#
|
22
23
|
class ClientId
|
24
|
+
# Toplevel JSON key for the an installed app configuration.
|
25
|
+
# Must include client_id and client_secret subkeys if present.
|
23
26
|
INSTALLED_APP = "installed".freeze
|
27
|
+
# Toplevel JSON key for the a webapp configuration.
|
28
|
+
# Must include client_id and client_secret subkeys if present.
|
24
29
|
WEB_APP = "web".freeze
|
30
|
+
# JSON key for the client ID within an app configuration.
|
25
31
|
CLIENT_ID = "client_id".freeze
|
32
|
+
# JSON key for the client secret within an app configuration.
|
26
33
|
CLIENT_SECRET = "client_secret".freeze
|
34
|
+
# An error message raised when none of the expected toplevel properties
|
35
|
+
# can be found.
|
27
36
|
MISSING_TOP_LEVEL_ELEMENT_ERROR =
|
28
37
|
"Expected top level property 'installed' or 'web' to be present.".freeze
|
29
38
|
|
39
|
+
##
|
30
40
|
# Text identifier of the client ID
|
31
41
|
# @return [String]
|
42
|
+
#
|
32
43
|
attr_reader :id
|
33
44
|
|
45
|
+
##
|
34
46
|
# Secret associated with the client ID
|
35
47
|
# @return [String]
|
48
|
+
#
|
36
49
|
attr_reader :secret
|
37
50
|
|
38
51
|
class << self
|
39
52
|
attr_accessor :default
|
40
53
|
end
|
41
54
|
|
42
|
-
|
55
|
+
##
|
56
|
+
# Initialize the Client ID. Both id and secret must be non-nil.
|
43
57
|
#
|
44
58
|
# @param [String] id
|
45
59
|
# Text identifier of the client ID
|
46
60
|
# @param [String] secret
|
47
61
|
# Secret associated with the client ID
|
48
|
-
# @note
|
49
|
-
#
|
62
|
+
# @note Direct instantiation is discouraged to avoid embedding IDs
|
63
|
+
# and secrets in source. See {#from_file} to load from
|
50
64
|
# `client_secrets.json` files.
|
65
|
+
#
|
51
66
|
def initialize id, secret
|
52
67
|
CredentialsLoader.warn_if_cloud_sdk_credentials id
|
53
68
|
raise "Client id can not be nil" if id.nil?
|
@@ -56,12 +71,14 @@ module Google
|
|
56
71
|
@secret = secret
|
57
72
|
end
|
58
73
|
|
74
|
+
##
|
59
75
|
# Constructs a Client ID from a JSON file downloaded from the
|
60
76
|
# Google Developers Console.
|
61
77
|
#
|
62
78
|
# @param [String, File] file
|
63
79
|
# Path of file to read from
|
64
80
|
# @return [Google::Auth::ClientID]
|
81
|
+
#
|
65
82
|
def self.from_file file
|
66
83
|
raise "File can not be nil." if file.nil?
|
67
84
|
File.open file.to_s do |f|
|
@@ -71,13 +88,14 @@ module Google
|
|
71
88
|
end
|
72
89
|
end
|
73
90
|
|
91
|
+
##
|
74
92
|
# Constructs a Client ID from a previously loaded JSON file. The hash
|
75
|
-
# structure should
|
76
|
-
# match the expected JSON format.
|
93
|
+
# structure should match the expected JSON format.
|
77
94
|
#
|
78
95
|
# @param [hash] config
|
79
96
|
# Parsed contents of the JSON file
|
80
97
|
# @return [Google::Auth::ClientID]
|
98
|
+
#
|
81
99
|
def self.from_hash config
|
82
100
|
raise "Hash can not be nil." if config.nil?
|
83
101
|
raw_detail = config[INSTALLED_APP] || config[WEB_APP]
|
@@ -14,7 +14,6 @@
|
|
14
14
|
|
15
15
|
require "faraday"
|
16
16
|
require "googleauth/signet"
|
17
|
-
require "memoist"
|
18
17
|
|
19
18
|
module Google
|
20
19
|
# Module Auth provides classes that provide Google-specific authorization
|
@@ -47,9 +46,9 @@ module Google
|
|
47
46
|
# @private Unused and deprecated
|
48
47
|
COMPUTE_CHECK_URI = "http://169.254.169.254".freeze
|
49
48
|
|
50
|
-
|
51
|
-
extend Memoist
|
49
|
+
@on_gce_cache = {}
|
52
50
|
|
51
|
+
class << self
|
53
52
|
def metadata_host
|
54
53
|
ENV.fetch "GCE_METADATA_HOST", DEFAULT_METADATA_HOST
|
55
54
|
end
|
@@ -68,21 +67,30 @@ module Google
|
|
68
67
|
|
69
68
|
# Detect if this appear to be a GCE instance, by checking if metadata
|
70
69
|
# is available.
|
71
|
-
def on_gce? options = {}
|
72
|
-
#
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
70
|
+
def on_gce? options = {}, reload = false # rubocop:disable Style/OptionalBooleanParameter
|
71
|
+
# We can follow OptionalBooleanParameter here because it's a public interface, we can't change it.
|
72
|
+
@on_gce_cache.delete options if reload
|
73
|
+
@on_gce_cache.fetch options do
|
74
|
+
@on_gce_cache[options] = begin
|
75
|
+
# TODO: This should use google-cloud-env instead.
|
76
|
+
c = options[:connection] || Faraday.default_connection
|
77
|
+
headers = { "Metadata-Flavor" => "Google" }
|
78
|
+
resp = c.get compute_check_uri, nil, headers do |req|
|
79
|
+
req.options.timeout = 1.0
|
80
|
+
req.options.open_timeout = 0.1
|
81
|
+
end
|
82
|
+
return false unless resp.status == 200
|
83
|
+
resp.headers["Metadata-Flavor"] == "Google"
|
84
|
+
rescue Faraday::TimeoutError, Faraday::ConnectionFailed
|
85
|
+
false
|
86
|
+
end
|
78
87
|
end
|
79
|
-
return false unless resp.status == 200
|
80
|
-
resp.headers["Metadata-Flavor"] == "Google"
|
81
|
-
rescue Faraday::TimeoutError, Faraday::ConnectionFailed
|
82
|
-
false
|
83
88
|
end
|
84
89
|
|
85
|
-
|
90
|
+
def reset_cache
|
91
|
+
@on_gce_cache.clear
|
92
|
+
end
|
93
|
+
alias unmemoize_all reset_cache
|
86
94
|
end
|
87
95
|
|
88
96
|
# Overrides the super class method to change how access tokens are
|
@@ -50,10 +50,11 @@ module Google
|
|
50
50
|
"s.googleusercontent.com".freeze
|
51
51
|
|
52
52
|
CLOUD_SDK_CREDENTIALS_WARNING =
|
53
|
-
"
|
54
|
-
"
|
55
|
-
|
56
|
-
"
|
53
|
+
"You are authenticating using user credentials." \
|
54
|
+
"For production, we recommend using service account credentials." \
|
55
|
+
"To learn more about service account credentials, see" \
|
56
|
+
"http://cloud.google.com/docs/authentication/external/set-up-adc-on-cloud " \
|
57
|
+
"To suppress this message, set the " \
|
57
58
|
"GOOGLE_AUTH_SUPPRESS_CREDENTIALS_WARNINGS environment variable.".freeze
|
58
59
|
|
59
60
|
# make_creds proxies the construction of a credentials instance
|
@@ -86,6 +86,17 @@ module Google
|
|
86
86
|
raise "Invalid time value #{time}"
|
87
87
|
end
|
88
88
|
end
|
89
|
+
|
90
|
+
def service_account_email
|
91
|
+
return nil if @service_account_impersonation_url.nil?
|
92
|
+
start_idx = @service_account_impersonation_url.rindex "/"
|
93
|
+
end_idx = @service_account_impersonation_url.index ":generateAccessToken"
|
94
|
+
if start_idx != -1 && end_idx != -1 && start_idx < end_idx
|
95
|
+
start_idx += 1
|
96
|
+
return @service_account_impersonation_url[start_idx..end_idx]
|
97
|
+
end
|
98
|
+
nil
|
99
|
+
end
|
89
100
|
end
|
90
101
|
end
|
91
102
|
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
# Copyright 2023 Google, Inc.
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require "open3"
|
16
|
+
require "time"
|
17
|
+
require "googleauth/external_account/base_credentials"
|
18
|
+
require "googleauth/external_account/external_account_utils"
|
19
|
+
|
20
|
+
module Google
|
21
|
+
# Module Auth provides classes that provide Google-specific authorization used to access Google APIs.
|
22
|
+
module Auth
|
23
|
+
module ExternalAccount
|
24
|
+
# This module handles the retrieval of credentials from Google Cloud by utilizing the any 3PI
|
25
|
+
# provider then exchanging the credentials for a short-lived Google Cloud access token.
|
26
|
+
class PluggableAuthCredentials
|
27
|
+
# constant for pluggable auth enablement in environment variable.
|
28
|
+
ENABLE_PLUGGABLE_ENV = "GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES".freeze
|
29
|
+
EXECUTABLE_SUPPORTED_MAX_VERSION = 1
|
30
|
+
EXECUTABLE_TIMEOUT_MILLIS_DEFAULT = 30 * 1000
|
31
|
+
EXECUTABLE_TIMEOUT_MILLIS_LOWER_BOUND = 5 * 1000
|
32
|
+
EXECUTABLE_TIMEOUT_MILLIS_UPPER_BOUND = 120 * 1000
|
33
|
+
ID_TOKEN_TYPE = ["urn:ietf:params:oauth:token-type:jwt", "urn:ietf:params:oauth:token-type:id_token"].freeze
|
34
|
+
|
35
|
+
include Google::Auth::ExternalAccount::BaseCredentials
|
36
|
+
include Google::Auth::ExternalAccount::ExternalAccountUtils
|
37
|
+
extend CredentialsLoader
|
38
|
+
|
39
|
+
# Will always be nil, but method still gets used.
|
40
|
+
attr_reader :client_id
|
41
|
+
|
42
|
+
# Initialize from options map.
|
43
|
+
#
|
44
|
+
# @param [string] audience
|
45
|
+
# @param [hash{symbol => value}] credential_source
|
46
|
+
# credential_source is a hash that contains either source file or url.
|
47
|
+
# credential_source_format is either text or json. To define how we parse the credential response.
|
48
|
+
#
|
49
|
+
def initialize options = {}
|
50
|
+
base_setup options
|
51
|
+
|
52
|
+
@audience = options[:audience]
|
53
|
+
@credential_source = options[:credential_source] || {}
|
54
|
+
@credential_source_executable = @credential_source[:executable]
|
55
|
+
raise "Missing excutable source. An 'executable' must be provided" if @credential_source_executable.nil?
|
56
|
+
@credential_source_executable_command = @credential_source_executable[:command]
|
57
|
+
if @credential_source_executable_command.nil?
|
58
|
+
raise "Missing command field. Executable command must be provided."
|
59
|
+
end
|
60
|
+
@credential_source_executable_timeout_millis = @credential_source_executable[:timeout_millis] ||
|
61
|
+
EXECUTABLE_TIMEOUT_MILLIS_DEFAULT
|
62
|
+
if @credential_source_executable_timeout_millis < EXECUTABLE_TIMEOUT_MILLIS_LOWER_BOUND ||
|
63
|
+
@credential_source_executable_timeout_millis > EXECUTABLE_TIMEOUT_MILLIS_UPPER_BOUND
|
64
|
+
raise "Timeout must be between 5 and 120 seconds."
|
65
|
+
end
|
66
|
+
@credential_source_executable_output_file = @credential_source_executable[:output_file]
|
67
|
+
end
|
68
|
+
|
69
|
+
def retrieve_subject_token!
|
70
|
+
unless ENV[ENABLE_PLUGGABLE_ENV] == "1"
|
71
|
+
raise "Executables need to be explicitly allowed (set GOOGLE_EXTERNAL_ACCOUNT_ALLOW_EXECUTABLES to '1') " \
|
72
|
+
"to run."
|
73
|
+
end
|
74
|
+
# check output file first
|
75
|
+
subject_token = load_subject_token_from_output_file
|
76
|
+
return subject_token unless subject_token.nil?
|
77
|
+
# environment variable injection
|
78
|
+
env = inject_environment_variables
|
79
|
+
output = subprocess_with_timeout env, @credential_source_executable_command,
|
80
|
+
@credential_source_executable_timeout_millis
|
81
|
+
response = MultiJson.load output, symbolize_keys: true
|
82
|
+
parse_subject_token response
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
|
87
|
+
def load_subject_token_from_output_file
|
88
|
+
return nil if @credential_source_executable_output_file.nil?
|
89
|
+
return nil unless File.exist? @credential_source_executable_output_file
|
90
|
+
begin
|
91
|
+
content = File.read @credential_source_executable_output_file, encoding: "utf-8"
|
92
|
+
response = MultiJson.load content, symbolize_keys: true
|
93
|
+
rescue StandardError
|
94
|
+
return nil
|
95
|
+
end
|
96
|
+
begin
|
97
|
+
subject_token = parse_subject_token response
|
98
|
+
rescue StandardError => e
|
99
|
+
return nil if e.message.match(/The token returned by the executable is expired/)
|
100
|
+
raise e
|
101
|
+
end
|
102
|
+
subject_token
|
103
|
+
end
|
104
|
+
|
105
|
+
def parse_subject_token response
|
106
|
+
validate_response_schema response
|
107
|
+
unless response[:success]
|
108
|
+
if response[:code].nil? || response[:message].nil?
|
109
|
+
raise "Error code and message fields are required in the response."
|
110
|
+
end
|
111
|
+
raise "Executable returned unsuccessful response: code: #{response[:code]}, message: #{response[:message]}."
|
112
|
+
end
|
113
|
+
if response[:expiration_time] && response[:expiration_time] < Time.now.to_i
|
114
|
+
raise "The token returned by the executable is expired."
|
115
|
+
end
|
116
|
+
raise "The executable response is missing the token_type field." if response[:token_type].nil?
|
117
|
+
return response[:id_token] if ID_TOKEN_TYPE.include? response[:token_type]
|
118
|
+
return response[:saml_response] if response[:token_type] == "urn:ietf:params:oauth:token-type:saml2"
|
119
|
+
raise "Executable returned unsupported token type."
|
120
|
+
end
|
121
|
+
|
122
|
+
def validate_response_schema response
|
123
|
+
raise "The executable response is missing the version field." if response[:version].nil?
|
124
|
+
if response[:version] > EXECUTABLE_SUPPORTED_MAX_VERSION
|
125
|
+
raise "Executable returned unsupported version #{response[:version]}."
|
126
|
+
end
|
127
|
+
raise "The executable response is missing the success field." if response[:success].nil?
|
128
|
+
end
|
129
|
+
|
130
|
+
def inject_environment_variables
|
131
|
+
env = ENV.to_h
|
132
|
+
env["GOOGLE_EXTERNAL_ACCOUNT_AUDIENCE"] = @audience
|
133
|
+
env["GOOGLE_EXTERNAL_ACCOUNT_TOKEN_TYPE"] = @subject_token_type
|
134
|
+
env["GOOGLE_EXTERNAL_ACCOUNT_INTERACTIVE"] = "0" # only non-interactive mode we support.
|
135
|
+
unless @service_account_impersonation_url.nil?
|
136
|
+
env["GOOGLE_EXTERNAL_ACCOUNT_IMPERSONATED_EMAIL"] = service_account_email
|
137
|
+
end
|
138
|
+
unless @credential_source_executable_output_file.nil?
|
139
|
+
env["GOOGLE_EXTERNAL_ACCOUNT_OUTPUT_FILE"] = @credential_source_executable_output_file
|
140
|
+
end
|
141
|
+
env
|
142
|
+
end
|
143
|
+
|
144
|
+
def subprocess_with_timeout environment_vars, command, timeout_seconds
|
145
|
+
Timeout.timeout timeout_seconds do
|
146
|
+
output, error, status = Open3.capture3 environment_vars, command
|
147
|
+
unless status.success?
|
148
|
+
raise "Executable exited with non-zero return code #{status.exitstatus}. Error: #{output}, #{error}"
|
149
|
+
end
|
150
|
+
output
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
@@ -17,6 +17,7 @@ require "uri"
|
|
17
17
|
require "googleauth/credentials_loader"
|
18
18
|
require "googleauth/external_account/aws_credentials"
|
19
19
|
require "googleauth/external_account/identity_pool_credentials"
|
20
|
+
require "googleauth/external_account/pluggable_credentials"
|
20
21
|
|
21
22
|
module Google
|
22
23
|
# Module Auth provides classes that provide Google-specific authorization
|
@@ -80,6 +81,9 @@ module Google
|
|
80
81
|
unless user_creds[:credential_source][:file].nil? && user_creds[:credential_source][:url].nil?
|
81
82
|
return Google::Auth::ExternalAccount::IdentityPoolCredentials.new user_creds
|
82
83
|
end
|
84
|
+
unless user_creds[:credential_source][:executable].nil?
|
85
|
+
return Google::Auth::ExternalAccount::PluggableAuthCredentials.new user_creds
|
86
|
+
end
|
83
87
|
raise INVALID_EXTERNAL_ACCOUNT_TYPE
|
84
88
|
end
|
85
89
|
end
|
data/lib/googleauth/id_tokens.rb
CHANGED
@@ -153,7 +153,7 @@ module Google
|
|
153
153
|
# one of the provided values, or the verification will fail with
|
154
154
|
# {Google::Auth::IDToken::AuthorizedPartyMismatchError}. If `nil`
|
155
155
|
# (the default), no azp checking is performed.
|
156
|
-
# @param
|
156
|
+
# @param iss [String,Array<String>,nil] The expected issuer. At least
|
157
157
|
# one `iss` field in the token must match at least one of the
|
158
158
|
# provided issuers, or the verification will fail with
|
159
159
|
# {Google::Auth::IDToken::IssuerMismatchError}. If `nil`, no issuer
|
@@ -191,7 +191,7 @@ module Google
|
|
191
191
|
# one of the provided values, or the verification will fail with
|
192
192
|
# {Google::Auth::IDToken::AuthorizedPartyMismatchError}. If `nil`
|
193
193
|
# (the default), no azp checking is performed.
|
194
|
-
# @param
|
194
|
+
# @param iss [String,Array<String>,nil] The expected issuer. At least
|
195
195
|
# one `iss` field in the token must match at least one of the
|
196
196
|
# provided issuers, or the verification will fail with
|
197
197
|
# {Google::Auth::IDToken::IssuerMismatchError}. If `nil`, no issuer
|
@@ -18,27 +18,60 @@ require "multi_json"
|
|
18
18
|
|
19
19
|
module Google
|
20
20
|
module Auth
|
21
|
-
|
21
|
+
##
|
22
|
+
# Small utility for normalizing scopes into canonical form.
|
23
|
+
#
|
24
|
+
# The canonical form of scopes is as an array of strings, each in the form
|
25
|
+
# of a full URL. This utility converts space-delimited scope strings into
|
26
|
+
# this form, and handles a small number of common aliases.
|
27
|
+
#
|
28
|
+
# This is used by UserRefreshCredentials to verify that a credential grants
|
29
|
+
# a requested scope.
|
30
|
+
#
|
22
31
|
module ScopeUtil
|
32
|
+
##
|
33
|
+
# Aliases understood by this utility
|
34
|
+
#
|
23
35
|
ALIASES = {
|
24
36
|
"email" => "https://www.googleapis.com/auth/userinfo.email",
|
25
37
|
"profile" => "https://www.googleapis.com/auth/userinfo.profile",
|
26
38
|
"openid" => "https://www.googleapis.com/auth/plus.me"
|
27
39
|
}.freeze
|
28
40
|
|
41
|
+
##
|
42
|
+
# Normalize the input, which may be an array of scopes or a whitespace-
|
43
|
+
# delimited scope string. The output is always an array, even if a single
|
44
|
+
# scope is input.
|
45
|
+
#
|
46
|
+
# @param scope [String,Array<String>] Input scope(s)
|
47
|
+
# @return [Array<String>] An array of scopes in canonical form.
|
48
|
+
#
|
29
49
|
def self.normalize scope
|
30
50
|
list = as_array scope
|
31
51
|
list.map { |item| ALIASES[item] || item }
|
32
52
|
end
|
33
53
|
|
54
|
+
##
|
55
|
+
# Ensure the input is an array. If a single string is passed in, splits
|
56
|
+
# it via whitespace. Does not interpret aliases.
|
57
|
+
#
|
58
|
+
# @param scope [String,Array<String>] Input scope(s)
|
59
|
+
# @return [Array<String>] Always an array of strings
|
60
|
+
# @raise ArgumentError If the input is not a string or array of strings
|
61
|
+
#
|
34
62
|
def self.as_array scope
|
35
63
|
case scope
|
36
64
|
when Array
|
65
|
+
scope.each do |item|
|
66
|
+
unless item.is_a? String
|
67
|
+
raise ArgumentError, "Invalid scope value: #{item.inspect}. Must be string or array"
|
68
|
+
end
|
69
|
+
end
|
37
70
|
scope
|
38
71
|
when String
|
39
72
|
scope.split
|
40
73
|
else
|
41
|
-
raise "Invalid scope value. Must be string or array"
|
74
|
+
raise ArgumentError, "Invalid scope value: #{scope.inspect}. Must be string or array"
|
42
75
|
end
|
43
76
|
end
|
44
77
|
end
|
@@ -80,6 +80,8 @@ module Google
|
|
80
80
|
# @param [String, Array<String>] scope
|
81
81
|
# Authorization scope to request. Overrides the instance scopes if not
|
82
82
|
# nil.
|
83
|
+
# @param [Hash] additional_parameters
|
84
|
+
# Additional query parameters to be added to the authorization URL.
|
83
85
|
# @return [String]
|
84
86
|
# Authorization url
|
85
87
|
def get_authorization_url options = {}
|
@@ -87,7 +89,8 @@ module Google
|
|
87
89
|
credentials = UserRefreshCredentials.new(
|
88
90
|
client_id: @client_id.id,
|
89
91
|
client_secret: @client_id.secret,
|
90
|
-
scope: scope
|
92
|
+
scope: scope,
|
93
|
+
additional_parameters: options[:additional_parameters]
|
91
94
|
)
|
92
95
|
redirect_uri = redirect_uri_for options[:base_url]
|
93
96
|
url = credentials.authorization_uri(access_type: "offline",
|
@@ -144,6 +147,9 @@ module Google
|
|
144
147
|
# Absolute URL to resolve the configured callback uri against.
|
145
148
|
# Required if the configured
|
146
149
|
# callback uri is a relative.
|
150
|
+
# @param [Hash] additional_parameters
|
151
|
+
# Additional parameters to be added to the post body of token
|
152
|
+
# endpoint request.
|
147
153
|
# @return [Google::Auth::UserRefreshCredentials]
|
148
154
|
# Credentials if exchange is successful
|
149
155
|
def get_credentials_from_code options = {}
|
@@ -152,10 +158,11 @@ module Google
|
|
152
158
|
scope = options[:scope] || @scope
|
153
159
|
base_url = options[:base_url]
|
154
160
|
credentials = UserRefreshCredentials.new(
|
155
|
-
client_id:
|
156
|
-
client_secret:
|
157
|
-
redirect_uri:
|
158
|
-
scope:
|
161
|
+
client_id: @client_id.id,
|
162
|
+
client_secret: @client_id.secret,
|
163
|
+
redirect_uri: redirect_uri_for(base_url),
|
164
|
+
scope: scope,
|
165
|
+
additional_parameters: options[:additional_parameters]
|
159
166
|
)
|
160
167
|
credentials.code = code
|
161
168
|
credentials.fetch_access_token!({})
|
data/lib/googleauth/version.rb
CHANGED
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: 1.
|
4
|
+
version: 1.8.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: 2023-
|
11
|
+
date: 2023-09-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
@@ -50,20 +50,6 @@ dependencies:
|
|
50
50
|
- - "<"
|
51
51
|
- !ruby/object:Gem::Version
|
52
52
|
version: '3.0'
|
53
|
-
- !ruby/object:Gem::Dependency
|
54
|
-
name: memoist
|
55
|
-
requirement: !ruby/object:Gem::Requirement
|
56
|
-
requirements:
|
57
|
-
- - "~>"
|
58
|
-
- !ruby/object:Gem::Version
|
59
|
-
version: '0.16'
|
60
|
-
type: :runtime
|
61
|
-
prerelease: false
|
62
|
-
version_requirements: !ruby/object:Gem::Requirement
|
63
|
-
requirements:
|
64
|
-
- - "~>"
|
65
|
-
- !ruby/object:Gem::Version
|
66
|
-
version: '0.16'
|
67
53
|
- !ruby/object:Gem::Dependency
|
68
54
|
name: multi_json
|
69
55
|
requirement: !ruby/object:Gem::Requirement
|
@@ -145,6 +131,7 @@ files:
|
|
145
131
|
- lib/googleauth/external_account/base_credentials.rb
|
146
132
|
- lib/googleauth/external_account/external_account_utils.rb
|
147
133
|
- lib/googleauth/external_account/identity_pool_credentials.rb
|
134
|
+
- lib/googleauth/external_account/pluggable_credentials.rb
|
148
135
|
- lib/googleauth/helpers/connection.rb
|
149
136
|
- lib/googleauth/iam.rb
|
150
137
|
- lib/googleauth/id_tokens.rb
|
@@ -185,7 +172,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
185
172
|
- !ruby/object:Gem::Version
|
186
173
|
version: '0'
|
187
174
|
requirements: []
|
188
|
-
rubygems_version: 3.4.
|
175
|
+
rubygems_version: 3.4.19
|
189
176
|
signing_key:
|
190
177
|
specification_version: 4
|
191
178
|
summary: Google Auth Library for Ruby
|