1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
|
# Copyright 2023 Google, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.require "time"
require "googleauth/base_client"
require "googleauth/errors"
require "googleauth/helpers/connection"
require "googleauth/oauth2/sts_client"
module Google
# Module Auth provides classes that provide Google-specific authorization
# used to access Google APIs.
module Auth
module ExternalAccount
# Authenticates requests using External Account credentials, such
# as those provided by the AWS provider or OIDC provider like Azure, etc.
module ExternalAccountUtils
# Cloud resource manager URL used to retrieve project information.
CLOUD_RESOURCE_MANAGER = "https://cloudresourcemanager.googleapis.com/v1/projects/".freeze
##
# Retrieves the project ID corresponding to the workload identity or workforce pool.
# For workforce pool credentials, it returns the project ID corresponding to the workforce_pool_user_project.
# When not determinable, None is returned.
#
# The resource may not have permission (resourcemanager.projects.get) to
# call this API or the required scopes may not be selected:
# https://cloud.google.com/resource-manager/reference/rest/v1/projects/get#authorization-scopes
#
# @return [String, nil] The project ID corresponding to the workload identity
# pool or workforce pool if determinable
#
def project_id
return @project_id unless @project_id.nil?
project_number = self.project_number || @workforce_pool_user_project
# if we missing either project number or scope, we won't retrieve project_id
return nil if project_number.nil? || @scope.nil?
url = "#{CLOUD_RESOURCE_MANAGER}#{project_number}"
response = connection.get url do |req|
req.headers["Authorization"] = "Bearer #{@access_token}"
req.headers["Content-Type"] = "application/json"
end
if response.status == 200
response_data = MultiJson.load response.body, symbolize_names: true
@project_id = response_data[:projectId]
end
@project_id
end
##
# Retrieve the project number corresponding to workload identity pool
# STS audience pattern:
# `//iam.googleapis.com/projects/$PROJECT_NUMBER/locations/...`
#
# @return [String, nil] The project number extracted from the audience string,
# or nil if it cannot be determined
#
def project_number
segments = @audience.split "/"
idx = segments.index "projects"
return nil if idx.nil? || idx + 1 == segments.size
segments[idx + 1]
end
# Normalizes a timestamp value to a Time object
#
# @param time [Time, String, nil] The timestamp to normalize
# @return [Time, nil] The normalized timestamp or nil if input is nil
# @raise [Google::Auth::CredentialsError] If the time value is not nil, Time, or String
def normalize_timestamp time
case time
when NilClass
nil
when Time
time
when String
Time.parse time
else
raise CredentialsError, "Invalid time value #{time}"
end
end
# Extracts the service account email from the impersonation URL
#
# @return [String, nil] The service account email extracted from the
# service_account_impersonation_url, or nil if it cannot be determined
def service_account_email
return nil if @service_account_impersonation_url.nil?
start_idx = @service_account_impersonation_url.rindex "/"
end_idx = @service_account_impersonation_url.index ":generateAccessToken"
if start_idx != -1 && end_idx != -1 && start_idx < end_idx
start_idx += 1
return @service_account_impersonation_url[start_idx..end_idx]
end
nil
end
end
end
end
end
|