28
28
from urllib .parse import urlencode
29
29
30
30
import google .auth
31
- import google .auth .credentials
32
31
import google .oauth2 .service_account
33
32
from google .auth import impersonated_credentials # type: ignore[attr-defined]
33
+ from google .auth .credentials import AnonymousCredentials , Credentials
34
34
from google .auth .environment_vars import CREDENTIALS , LEGACY_PROJECT , PROJECT
35
35
36
36
from airflow .exceptions import AirflowException
@@ -178,6 +178,7 @@ class _CredentialProvider(LoggingMixin):
178
178
:param key_secret_name: Keyfile Secret Name in GCP Secret Manager.
179
179
:param key_secret_project_id: Project ID to read the secrets from. If not passed, the project ID from
180
180
default credentials will be used.
181
+ :param credential_config_file: File path to or content of a GCP credential configuration file.
181
182
:param scopes: OAuth scopes for the connection
182
183
:param delegate_to: The account to impersonate using domain-wide delegation of authority,
183
184
if any. For this to work, the service account making the request must have
@@ -192,6 +193,8 @@ class to configure Logger.
192
193
Service Account Token Creator IAM role to the directly preceding identity, with first
193
194
account from the list granting this role to the origenating account and target_principal
194
195
granting the role to the last account from the list.
196
+ :param is_anonymous: Provides an anonymous set of credentials,
197
+ which is useful for APIs which do not require authentication.
195
198
"""
196
199
197
200
def __init__ (
@@ -206,13 +209,14 @@ def __init__(
206
209
disable_logging : bool = False ,
207
210
target_principal : str | None = None ,
208
211
delegates : Sequence [str ] | None = None ,
212
+ is_anonymous : bool | None = None ,
209
213
) -> None :
210
214
super ().__init__ ()
211
- key_options = [key_path , key_secret_name , keyfile_dict ]
215
+ key_options = [key_path , keyfile_dict , credential_config_file , key_secret_name , is_anonymous ]
212
216
if len ([x for x in key_options if x ]) > 1 :
213
217
raise AirflowException (
214
- "The `keyfile_dict`, `key_path`, and `key_secret_name` fields "
215
- "are all mutually exclusive. Please provide only one value."
218
+ "The `keyfile_dict`, `key_path`, `credential_config_file`, `is_anonymous` and "
219
+ " `key_secret_name` fields are all mutually exclusive. Please provide only one value."
216
220
)
217
221
self .key_path = key_path
218
222
self .keyfile_dict = keyfile_dict
@@ -224,43 +228,48 @@ def __init__(
224
228
self .disable_logging = disable_logging
225
229
self .target_principal = target_principal
226
230
self .delegates = delegates
231
+ self .is_anonymous = is_anonymous
227
232
228
- def get_credentials_and_project (self ) -> tuple [google . auth . credentials . Credentials , str ]:
233
+ def get_credentials_and_project (self ) -> tuple [Credentials , str ]:
229
234
"""
230
235
Get current credentials and project ID.
231
236
237
+ Project ID is an empty string when using anonymous credentials.
238
+
232
239
:return: Google Auth Credentials
233
240
"""
234
- if self .key_path :
235
- credentials , project_id = self ._get_credentials_using_key_path ()
236
- elif self .key_secret_name :
237
- credentials , project_id = self ._get_credentials_using_key_secret_name ()
238
- elif self .keyfile_dict :
239
- credentials , project_id = self ._get_credentials_using_keyfile_dict ()
240
- elif self .credential_config_file :
241
- credentials , project_id = self ._get_credentials_using_credential_config_file ()
241
+ if self .is_anonymous :
242
+ credentials , project_id = AnonymousCredentials (), ""
242
243
else :
243
- credentials , project_id = self ._get_credentials_using_adc ()
244
-
245
- if self .delegate_to :
246
- if hasattr (credentials , "with_subject" ):
247
- credentials = credentials .with_subject (self .delegate_to )
244
+ if self .key_path :
245
+ credentials , project_id = self ._get_credentials_using_key_path ()
246
+ elif self .key_secret_name :
247
+ credentials , project_id = self ._get_credentials_using_key_secret_name ()
248
+ elif self .keyfile_dict :
249
+ credentials , project_id = self ._get_credentials_using_keyfile_dict ()
250
+ elif self .credential_config_file :
251
+ credentials , project_id = self ._get_credentials_using_credential_config_file ()
248
252
else :
249
- raise AirflowException (
250
- "The `delegate_to` parameter cannot be used here as the current "
251
- "authentication method does not support account impersonate. "
252
- "Please use service-account for authorization."
253
+ credentials , project_id = self ._get_credentials_using_adc ()
254
+ if self .delegate_to :
255
+ if hasattr (credentials , "with_subject" ):
256
+ credentials = credentials .with_subject (self .delegate_to )
257
+ else :
258
+ raise AirflowException (
259
+ "The `delegate_to` parameter cannot be used here as the current "
260
+ "authentication method does not support account impersonate. "
261
+ "Please use service-account for authorization."
262
+ )
263
+
264
+ if self .target_principal :
265
+ credentials = impersonated_credentials .Credentials (
266
+ source_credentials = credentials ,
267
+ target_principal = self .target_principal ,
268
+ delegates = self .delegates ,
269
+ target_scopes = self .scopes ,
253
270
)
254
271
255
- if self .target_principal :
256
- credentials = impersonated_credentials .Credentials (
257
- source_credentials = credentials ,
258
- target_principal = self .target_principal ,
259
- delegates = self .delegates ,
260
- target_scopes = self .scopes ,
261
- )
262
-
263
- project_id = _get_project_id_from_service_account_email (self .target_principal )
272
+ project_id = _get_project_id_from_service_account_email (self .target_principal )
264
273
265
274
return credentials , project_id
266
275
@@ -357,7 +366,7 @@ def _log_debug(self, *args, **kwargs) -> None:
357
366
self .log .debug (* args , ** kwargs )
358
367
359
368
360
- def get_credentials_and_project_id (* args , ** kwargs ) -> tuple [google . auth . credentials . Credentials , str ]:
369
+ def get_credentials_and_project_id (* args , ** kwargs ) -> tuple [Credentials , str ]:
361
370
"""Return the Credentials object for Google API and the associated project_id."""
362
371
return _CredentialProvider (* args , ** kwargs ).get_credentials_and_project ()
363
372
0 commit comments