googleauth-extras 0.2.0 → 0.3.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/.rubocop.yml +7 -1
- data/CHANGELOG.md +10 -0
- data/googleauth-extras.gemspec +1 -1
- data/lib/google/auth/extras/identity_credential_refresh_patch.rb +17 -0
- data/lib/google/auth/extras/impersonated_credential.rb +94 -22
- data/lib/google/auth/extras/version.rb +1 -1
- data/lib/google/auth/extras.rb +47 -5
- metadata +12 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 56aa20519132423c5f99a9c67fb011bdf44d575ccb60d7109abd0f2f6db17a09
|
4
|
+
data.tar.gz: 6d63aaa0d4dce0256ee828233640f951af9a203a9bf56dc46640ad2994fbe05a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a8c1978e55c6d63353823bf771c49c6c94266963774c2db5b9eef32d23f625f5762b08f30e773f71ef897bf53f07840f9e039a5dada27bc6bf7427b17667e3c1
|
7
|
+
data.tar.gz: 78b376acc7c4bfd48b0be54127761a4ef40ec02c28029e0de2d90526116a41f43d8cfe7029b5e877480c582fc9bb46b401f3aa2b8520bc8ce8668a866e523065
|
data/.rubocop.yml
CHANGED
@@ -19,12 +19,18 @@ Layout/LineLength:
|
|
19
19
|
Metrics/AbcSize:
|
20
20
|
Enabled: false
|
21
21
|
|
22
|
+
Metrics/CyclomaticComplexity:
|
23
|
+
Enabled: false
|
24
|
+
|
22
25
|
Metrics/MethodLength:
|
23
|
-
Max:
|
26
|
+
Max: 30
|
24
27
|
|
25
28
|
Metrics/ParameterLists:
|
26
29
|
Enabled: false
|
27
30
|
|
31
|
+
Metrics/PerceivedComplexity:
|
32
|
+
Enabled: false
|
33
|
+
|
28
34
|
RSpec/ContextWording:
|
29
35
|
Enabled: false
|
30
36
|
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,15 @@
|
|
1
1
|
# Release History
|
2
2
|
|
3
|
+
0.3.0
|
4
|
+
-----
|
5
|
+
|
6
|
+
- Support impersonation with ID tokens. ([#9](https://github.com/persona-id/googleauth-extras/pull/9))
|
7
|
+
|
8
|
+
0.2.1
|
9
|
+
-----
|
10
|
+
|
11
|
+
- Support signet 0.18.0. ([#7](https://github.com/persona-id/googleauth-extras/pull/7))
|
12
|
+
|
3
13
|
0.2.0
|
4
14
|
-----
|
5
15
|
|
data/googleauth-extras.gemspec
CHANGED
@@ -34,5 +34,5 @@ Gem::Specification.new do |spec|
|
|
34
34
|
spec.add_runtime_dependency 'faraday', '>= 1.0', '< 3.0'
|
35
35
|
spec.add_runtime_dependency 'google-apis-iamcredentials_v1'
|
36
36
|
spec.add_runtime_dependency 'googleauth', '~> 1.3'
|
37
|
-
spec.add_runtime_dependency 'signet', '
|
37
|
+
spec.add_runtime_dependency 'signet', '>= 0.17.0', '< 0.19.0'
|
38
38
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Google
|
4
|
+
module Auth
|
5
|
+
module Extras
|
6
|
+
# This module fixes an issue with ID tokens not automatically refreshing
|
7
|
+
# because their expiration is encoded in the JWT.
|
8
|
+
module IdentityCredentialRefreshPatch
|
9
|
+
def update_token!(*)
|
10
|
+
super.tap do
|
11
|
+
self.expires_at = decoded_id_token['exp'] if id_token
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -5,10 +5,15 @@ module Google
|
|
5
5
|
module Extras
|
6
6
|
# This credential impersonates a service account.
|
7
7
|
class ImpersonatedCredential < Signet::OAuth2::Client
|
8
|
-
|
8
|
+
include IdentityCredentialRefreshPatch
|
9
9
|
|
10
10
|
# A credential that impersonates a service account.
|
11
11
|
#
|
12
|
+
# The `email_address` of the service account to impersonate may be the exact
|
13
|
+
# same as the one represented in `base_credentials` for any desired situation
|
14
|
+
# but a handy usage is for going from and access token to an ID token (aka
|
15
|
+
# using `target_audience`).
|
16
|
+
#
|
12
17
|
# @param base_credentials [Hash, String, Signet::OAuth2::Client]
|
13
18
|
# Credentials to use to impersonate the provided email address.
|
14
19
|
#
|
@@ -19,22 +24,48 @@ module Google
|
|
19
24
|
# @param email_address [String]
|
20
25
|
# Email of the service account to impersonate.
|
21
26
|
#
|
27
|
+
# @param include_email [Boolean]
|
28
|
+
# Include the service account email in the token. If set to true, the token will
|
29
|
+
# contain email and email_verified claims.
|
30
|
+
# Only supported when using a target_audience.
|
31
|
+
#
|
22
32
|
# @param lifetime [String]
|
23
33
|
# The desired lifetime (in seconds) of the token before needing to be refreshed.
|
24
34
|
# Defaults to 1h, adjust as needed given a refresh is automatically performed
|
25
35
|
# when the token less than 60s of remaining life and refresh requires an
|
26
36
|
# additional API call.
|
37
|
+
# Only supported when not using a target_audience.
|
27
38
|
#
|
28
39
|
# @param scope [String, Array<String>]
|
29
40
|
# The OAuth 2 scopes to request. Can either be formatted as a comma seperated string or array.
|
41
|
+
# Only supported when not using a target_audience.
|
42
|
+
#
|
43
|
+
# @param target_audience [String]
|
44
|
+
# The audience for the token, such as the API or account that this token grants access to.
|
30
45
|
#
|
31
46
|
# @see https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/generateAccessToken
|
47
|
+
# @see https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/generateIdToken
|
32
48
|
# @see https://cloud.google.com/iam/docs/create-short-lived-credentials-delegated#sa-credentials-permissions
|
49
|
+
# @see https://developers.google.com/identity/protocols/oauth2/scopes
|
33
50
|
#
|
34
|
-
def initialize(
|
35
|
-
|
51
|
+
def initialize(
|
52
|
+
email_address:,
|
53
|
+
base_credentials: nil,
|
54
|
+
delegate_email_addresses: nil,
|
55
|
+
include_email: nil,
|
56
|
+
lifetime: nil,
|
57
|
+
scope: nil,
|
58
|
+
target_audience: nil
|
59
|
+
)
|
60
|
+
super(client_id: target_audience, scope: scope, target_audience: target_audience)
|
36
61
|
|
37
|
-
|
62
|
+
if self.target_audience.nil? || self.target_audience.empty?
|
63
|
+
raise(ArgumentError, 'Must provide scope or target_audience') if self.scope.nil? || self.scope.empty?
|
64
|
+
elsif self.scope.nil? || self.scope.empty?
|
65
|
+
# no-op
|
66
|
+
else
|
67
|
+
raise ArgumentError, 'Must provide scope or target_audience, not both'
|
68
|
+
end
|
38
69
|
|
39
70
|
@iam_credentials_service = Google::Apis::IamcredentialsV1::IAMCredentialsService.new.tap do |ics|
|
40
71
|
ics.authorization = base_credentials if base_credentials
|
@@ -44,36 +75,77 @@ module Google
|
|
44
75
|
transform_email_to_name(email)
|
45
76
|
end
|
46
77
|
|
47
|
-
|
78
|
+
# This is true when target_audience is passed
|
79
|
+
if token_type == :id_token
|
80
|
+
@impersonate_include_email = include_email
|
81
|
+
elsif !include_email.nil?
|
82
|
+
raise ArgumentError, 'Can only provide include_email when using target_audience'
|
83
|
+
end
|
84
|
+
|
85
|
+
# This is true when scope is passed
|
86
|
+
if token_type == :access_token
|
87
|
+
@impersonate_lifetime = lifetime
|
88
|
+
elsif !lifetime.nil?
|
89
|
+
raise ArgumentError, 'Cannot provide lifetime when using target_audience'
|
90
|
+
end
|
48
91
|
|
49
92
|
@impersonate_name = transform_email_to_name(email_address)
|
50
93
|
end
|
51
94
|
|
52
95
|
def fetch_access_token(*)
|
53
|
-
|
54
|
-
|
55
|
-
|
96
|
+
token_request = if token_type == :id_token
|
97
|
+
Google::Apis::IamcredentialsV1::GenerateIdTokenRequest.new(
|
98
|
+
audience: target_audience,
|
99
|
+
)
|
100
|
+
else
|
101
|
+
Google::Apis::IamcredentialsV1::GenerateAccessTokenRequest.new(
|
102
|
+
scope: scope,
|
103
|
+
)
|
104
|
+
end
|
56
105
|
|
57
106
|
# The Google SDK doesn't like nil repeated values, but be careful with others as well.
|
58
|
-
|
59
|
-
|
107
|
+
token_request.delegates = @impersonate_delegates unless @impersonate_delegates.empty?
|
108
|
+
if token_type == :id_token
|
109
|
+
token_request.include_email = @impersonate_include_email unless @impersonate_include_email.nil?
|
110
|
+
else
|
111
|
+
token_request.lifetime = @impersonate_lifetime unless @impersonate_lifetime.nil?
|
112
|
+
end
|
113
|
+
|
114
|
+
if token_type == :id_token
|
115
|
+
id_token_response = @iam_credentials_service.generate_service_account_id_token(@impersonate_name, token_request)
|
60
116
|
|
61
|
-
|
117
|
+
{
|
118
|
+
id_token: id_token_response.token,
|
119
|
+
}
|
120
|
+
else
|
121
|
+
access_token_response = @iam_credentials_service.generate_service_account_access_token(@impersonate_name, token_request)
|
62
122
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
123
|
+
{
|
124
|
+
access_token: access_token_response.access_token,
|
125
|
+
expires_at: DateTime.rfc3339(access_token_response.expire_time).to_time,
|
126
|
+
}
|
127
|
+
end
|
67
128
|
end
|
68
129
|
|
69
130
|
def inspect
|
70
|
-
|
71
|
-
"
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
131
|
+
if token_type == :id_token
|
132
|
+
"#<#{self.class.name}" \
|
133
|
+
" @expires_at=#{expires_at.inspect}" \
|
134
|
+
" @id_token=#{@id_token ? '[REDACTED]' : 'nil'}" \
|
135
|
+
" @impersonate_delegates=#{@impersonate_delegates.inspect}" \
|
136
|
+
" @impersonate_include_email=#{@impersonate_include_email.inspect}" \
|
137
|
+
" @impersonate_name=#{@impersonate_name.inspect}" \
|
138
|
+
" @target_audience=#{@target_audience.inspect}" \
|
139
|
+
'>'
|
140
|
+
else
|
141
|
+
"#<#{self.class.name}" \
|
142
|
+
" @access_token=#{@access_token ? '[REDACTED]' : 'nil'}" \
|
143
|
+
" @expires_at=#{expires_at.inspect}" \
|
144
|
+
" @impersonate_delegates=#{@impersonate_delegates.inspect}" \
|
145
|
+
" @impersonate_lifetime=#{@impersonate_lifetime.inspect}" \
|
146
|
+
" @impersonate_name=#{@impersonate_name.inspect}" \
|
147
|
+
'>'
|
148
|
+
end
|
77
149
|
end
|
78
150
|
|
79
151
|
private
|
data/lib/google/auth/extras.rb
CHANGED
@@ -4,6 +4,7 @@ require 'date'
|
|
4
4
|
require 'google/apis/iamcredentials_v1'
|
5
5
|
require 'signet/oauth_2/client'
|
6
6
|
|
7
|
+
require 'google/auth/extras/identity_credential_refresh_patch'
|
7
8
|
require 'google/auth/extras/impersonated_credential'
|
8
9
|
require 'google/auth/extras/static_credential'
|
9
10
|
require 'google/auth/extras/token_info'
|
@@ -22,6 +23,11 @@ module Google
|
|
22
23
|
# A credential that impersonates a service account. For usage with the
|
23
24
|
# older style GCP Ruby SDKs from the google-apis-* gems.
|
24
25
|
#
|
26
|
+
# The `email_address` of the service account to impersonate may be the exact
|
27
|
+
# same as the one represented in `base_credentials` for any desired situation
|
28
|
+
# but a handy usage is for going from and access token to an ID token (aka
|
29
|
+
# using `target_audience`).
|
30
|
+
#
|
25
31
|
# @param base_credentials [Hash, String, Signet::OAuth2::Client]
|
26
32
|
# Credentials to use to impersonate the provided email address.
|
27
33
|
#
|
@@ -32,28 +38,46 @@ module Google
|
|
32
38
|
# @param email_address [String]
|
33
39
|
# Email of the service account to impersonate.
|
34
40
|
#
|
41
|
+
# @param include_email [Boolean]
|
42
|
+
# Include the service account email in the token. If set to true, the token will
|
43
|
+
# contain email and email_verified claims.
|
44
|
+
# Only supported when using a target_audience.
|
45
|
+
#
|
35
46
|
# @param lifetime [String]
|
36
47
|
# The desired lifetime (in seconds) of the token before needing to be refreshed.
|
37
48
|
# Defaults to 1h, adjust as needed given a refresh is automatically performed
|
38
49
|
# when the token less than 60s of remaining life and refresh requires an
|
39
50
|
# additional API call.
|
51
|
+
# Only supported when not using a target_audience.
|
40
52
|
#
|
41
53
|
# @param scope [String, Array<String>]
|
42
|
-
# The OAuth 2
|
54
|
+
# The OAuth 2 scopes to request. Can either be formatted as a comma seperated string or array.
|
55
|
+
# Only supported when not using a target_audience.
|
43
56
|
#
|
44
57
|
# @return [Google::Auth::Extras::ImpersonatedCredential]
|
45
58
|
#
|
46
59
|
# @see https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/generateAccessToken
|
60
|
+
# @see https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/generateIdToken
|
47
61
|
# @see https://cloud.google.com/iam/docs/create-short-lived-credentials-delegated#sa-credentials-permissions
|
48
62
|
# @see https://developers.google.com/identity/protocols/oauth2/scopes
|
49
63
|
#
|
50
|
-
def impersonated_authorization(
|
64
|
+
def impersonated_authorization(
|
65
|
+
email_address:,
|
66
|
+
base_credentials: nil,
|
67
|
+
delegate_email_addresses: nil,
|
68
|
+
include_email: nil,
|
69
|
+
lifetime: nil,
|
70
|
+
scope: nil,
|
71
|
+
target_audience: nil
|
72
|
+
)
|
51
73
|
ImpersonatedCredential.new(
|
52
74
|
base_credentials: base_credentials,
|
53
75
|
delegate_email_addresses: delegate_email_addresses,
|
54
76
|
email_address: email_address,
|
77
|
+
include_email: include_email,
|
55
78
|
lifetime: lifetime,
|
56
79
|
scope: scope,
|
80
|
+
target_audience: target_audience,
|
57
81
|
)
|
58
82
|
end
|
59
83
|
|
@@ -70,29 +94,47 @@ module Google
|
|
70
94
|
# @param email_address [String]
|
71
95
|
# Email of the service account to impersonate.
|
72
96
|
#
|
97
|
+
# @param include_email [Boolean]
|
98
|
+
# Include the service account email in the token. If set to true, the token will
|
99
|
+
# contain email and email_verified claims.
|
100
|
+
# Only supported when using a target_audience.
|
101
|
+
#
|
73
102
|
# @param lifetime [String]
|
74
103
|
# The desired lifetime (in seconds) of the token before needing to be refreshed.
|
75
104
|
# Defaults to 1h, adjust as needed given a refresh is automatically performed
|
76
105
|
# when the token less than 60s of remaining life and refresh requires an
|
77
106
|
# additional API call.
|
107
|
+
# Only supported when not using a target_audience.
|
78
108
|
#
|
79
109
|
# @param scope [String, Array<String>]
|
80
|
-
# The OAuth 2
|
110
|
+
# The OAuth 2 scopes to request. Can either be formatted as a comma seperated string or array.
|
111
|
+
# Only supported when not using a target_audience.
|
81
112
|
#
|
82
113
|
# @return [Google::Auth::Credential<Google::Auth::Extras::ImpersonatedCredential>]
|
83
114
|
#
|
84
115
|
# @see https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/generateAccessToken
|
116
|
+
# @see https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/generateIdToken
|
85
117
|
# @see https://cloud.google.com/iam/docs/create-short-lived-credentials-delegated#sa-credentials-permissions
|
86
118
|
# @see https://developers.google.com/identity/protocols/oauth2/scopes
|
87
119
|
#
|
88
|
-
def impersonated_credential(
|
120
|
+
def impersonated_credential(
|
121
|
+
email_address:,
|
122
|
+
base_credentials: nil,
|
123
|
+
delegate_email_addresses: nil,
|
124
|
+
include_email: nil,
|
125
|
+
lifetime: nil,
|
126
|
+
scope: nil,
|
127
|
+
target_audience: nil
|
128
|
+
)
|
89
129
|
wrap_authorization(
|
90
130
|
impersonated_authorization(
|
91
131
|
base_credentials: base_credentials,
|
92
132
|
delegate_email_addresses: delegate_email_addresses,
|
93
133
|
email_address: email_address,
|
134
|
+
include_email: include_email,
|
94
135
|
lifetime: lifetime,
|
95
136
|
scope: scope,
|
137
|
+
target_audience: target_audience,
|
96
138
|
),
|
97
139
|
)
|
98
140
|
end
|
@@ -122,7 +164,7 @@ module Google
|
|
122
164
|
end
|
123
165
|
|
124
166
|
# Take an authorization and turn it into a credential, primarily used
|
125
|
-
# for setting up both the old and new style
|
167
|
+
# for setting up both the old and new style SDKs.
|
126
168
|
#
|
127
169
|
# @param client [Signet::OAuth2::Client]
|
128
170
|
# Authorization credential to wrap.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: googleauth-extras
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Persona Identities
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-07-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: addressable
|
@@ -76,16 +76,22 @@ dependencies:
|
|
76
76
|
name: signet
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
78
78
|
requirements:
|
79
|
-
- - "
|
79
|
+
- - ">="
|
80
80
|
- !ruby/object:Gem::Version
|
81
81
|
version: 0.17.0
|
82
|
+
- - "<"
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: 0.19.0
|
82
85
|
type: :runtime
|
83
86
|
prerelease: false
|
84
87
|
version_requirements: !ruby/object:Gem::Requirement
|
85
88
|
requirements:
|
86
|
-
- - "
|
89
|
+
- - ">="
|
87
90
|
- !ruby/object:Gem::Version
|
88
91
|
version: 0.17.0
|
92
|
+
- - "<"
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 0.19.0
|
89
95
|
description:
|
90
96
|
email:
|
91
97
|
- alex.coomans@withpersona.com
|
@@ -107,6 +113,7 @@ files:
|
|
107
113
|
- bin/setup
|
108
114
|
- googleauth-extras.gemspec
|
109
115
|
- lib/google/auth/extras.rb
|
116
|
+
- lib/google/auth/extras/identity_credential_refresh_patch.rb
|
110
117
|
- lib/google/auth/extras/impersonated_credential.rb
|
111
118
|
- lib/google/auth/extras/static_credential.rb
|
112
119
|
- lib/google/auth/extras/token_info.rb
|
@@ -136,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
136
143
|
- !ruby/object:Gem::Version
|
137
144
|
version: '0'
|
138
145
|
requirements: []
|
139
|
-
rubygems_version: 3.
|
146
|
+
rubygems_version: 3.4.10
|
140
147
|
signing_key:
|
141
148
|
specification_version: 4
|
142
149
|
summary: Additions to the googleauth gem for unsupported authentication schemes.
|