3636import  datetime 
3737import  io 
3838import  json 
39+ import  re 
3940
41+ from  google .auth  import  _constants 
4042from  google .auth  import  _helpers 
4143from  google .auth  import  credentials 
4244from  google .auth  import  exceptions 
@@ -50,6 +52,7 @@ class Credentials(
5052    credentials .CredentialsWithQuotaProject ,
5153    credentials .ReadOnlyScoped ,
5254    credentials .CredentialsWithTokenUri ,
55+     credentials .CredentialsWithTrustBoundary ,
5356):
5457    """Credentials for External Account Authorized Users. 
5558
@@ -83,6 +86,7 @@ def __init__(
8386        scopes = None ,
8487        quota_project_id = None ,
8588        universe_domain = credentials .DEFAULT_UNIVERSE_DOMAIN ,
89+         trust_boundary = None ,
8690    ):
8791        """Instantiates a external account authorized user credentials object. 
8892
@@ -108,6 +112,7 @@ def __init__(
108112            create the credentials. 
109113        universe_domain (Optional[str]): The universe domain. The default value 
110114            is googleapis.com. 
115+         trust_boundary (Mapping[str,str]): A credential trust boundary. 
111116
112117        Returns: 
113118            google.auth.external_account_authorized_user.Credentials: The 
@@ -118,7 +123,7 @@ def __init__(
118123        self .token  =  token 
119124        self .expiry  =  expiry 
120125        self ._audience  =  audience 
121-         self ._refresh_token  =  refresh_token 
126+         self ._refresh_token_val  =  refresh_token 
122127        self ._token_url  =  token_url 
123128        self ._token_info_url  =  token_info_url 
124129        self ._client_id  =  client_id 
@@ -128,6 +133,7 @@ def __init__(
128133        self ._scopes  =  scopes 
129134        self ._universe_domain  =  universe_domain  or  credentials .DEFAULT_UNIVERSE_DOMAIN 
130135        self ._cred_file_path  =  None 
136+         self ._trust_boundary  =  trust_boundary 
131137
132138        if  not  self .valid  and  not  self .can_refresh :
133139            raise  exceptions .InvalidOperation (
@@ -164,7 +170,7 @@ def info(self):
164170    def  constructor_args (self ):
165171        return  {
166172            "audience" : self ._audience ,
167-             "refresh_token" : self ._refresh_token ,
173+             "refresh_token" : self ._refresh_token_val ,
168174            "token_url" : self ._token_url ,
169175            "token_info_url" : self ._token_info_url ,
170176            "client_id" : self ._client_id ,
@@ -175,6 +181,7 @@ def constructor_args(self):
175181            "scopes" : self ._scopes ,
176182            "quota_project_id" : self ._quota_project_id ,
177183            "universe_domain" : self ._universe_domain ,
184+             "trust_boundary" : self ._trust_boundary ,
178185        }
179186
180187    @property  
@@ -184,7 +191,7 @@ def scopes(self):
184191
185192    @property  
186193    def  requires_scopes (self ):
187-         """  False: OAuth 2.0 credentials have their scopes set when 
194+         """False: OAuth 2.0 credentials have their scopes set when 
188195        the initial token is requested and can not be changed.""" 
189196        return  False 
190197
@@ -201,13 +208,13 @@ def client_secret(self):
201208    @property  
202209    def  audience (self ):
203210        """Optional[str]: The STS audience which contains the resource name for the 
204-              workforce pool and the provider identifier in that pool.""" 
211+         workforce pool and the provider identifier in that pool.""" 
205212        return  self ._audience 
206213
207214    @property  
208215    def  refresh_token (self ):
209216        """Optional[str]: The OAuth 2.0 refresh token.""" 
210-         return  self ._refresh_token 
217+         return  self ._refresh_token_val 
211218
212219    @property  
213220    def  token_url (self ):
@@ -226,13 +233,18 @@ def revoke_url(self):
226233
227234    @property  
228235    def  is_user (self ):
229-         """  True: This credential always represents a user.""" 
236+         """True: This credential always represents a user.""" 
230237        return  True 
231238
232239    @property  
233240    def  can_refresh (self ):
234241        return  all (
235-             (self ._refresh_token , self ._token_url , self ._client_id , self ._client_secret )
242+             (
243+                 self ._refresh_token_val ,
244+                 self ._token_url ,
245+                 self ._client_id ,
246+                 self ._client_secret ,
247+             )
236248        )
237249
238250    def  get_project_id (self , request = None ):
@@ -266,7 +278,7 @@ def to_json(self, strip=None):
266278        strip  =  strip  if  strip  else  []
267279        return  json .dumps ({k : v  for  (k , v ) in  self .info .items () if  k  not  in strip })
268280
269-     def  refresh (self , request ):
281+     def  _refresh_token (self , request ):
270282        """Refreshes the access token. 
271283
272284        Args: 
@@ -285,18 +297,29 @@ def refresh(self, request):
285297            )
286298
287299        now  =  _helpers .utcnow ()
288-         response_data  =  self ._make_sts_request (request )
300+         response_data  =  self ._sts_client . refresh_token (request ,  self . _refresh_token_val )
289301
290302        self .token  =  response_data .get ("access_token" )
291303
292304        lifetime  =  datetime .timedelta (seconds = response_data .get ("expires_in" ))
293305        self .expiry  =  now  +  lifetime 
294306
295307        if  "refresh_token"  in  response_data :
296-             self ._refresh_token  =  response_data ["refresh_token" ]
308+             self ._refresh_token_val  =  response_data ["refresh_token" ]
309+ 
310+     def  _build_trust_boundary_lookup_url (self ):
311+         """Builds and returns the URL for the trust boundary lookup API.""" 
312+         # Audience format: //iam.googleapis.com/locations/global/workforcePools/POOL_ID/providers/PROVIDER_ID 
313+         match  =  re .search (r"locations/[^/]+/workforcePools/([^/]+)" , self ._audience )
314+ 
315+         if  not  match :
316+             raise  exceptions .InvalidValue ("Invalid workforce pool audience format." )
317+ 
318+         pool_id  =  match .groups ()[0 ]
297319
298-     def  _make_sts_request (self , request ):
299-         return  self ._sts_client .refresh_token (request , self ._refresh_token )
320+         return  _constants ._WORKFORCE_POOL_TRUST_BOUNDARY_LOOKUP_ENDPOINT .format (
321+             universe_domain = self ._universe_domain , pool_id = pool_id 
322+         )
300323
301324    @_helpers .copy_docstring (credentials .Credentials ) 
302325    def  get_cred_info (self ):
@@ -331,6 +354,12 @@ def with_universe_domain(self, universe_domain):
331354        cred ._universe_domain  =  universe_domain 
332355        return  cred 
333356
357+     @_helpers .copy_docstring (credentials .CredentialsWithTrustBoundary ) 
358+     def  with_trust_boundary (self , trust_boundary ):
359+         cred  =  self ._make_copy ()
360+         cred ._trust_boundary  =  trust_boundary 
361+         return  cred 
362+ 
334363    @classmethod  
335364    def  from_info (cls , info , ** kwargs ):
336365        """Creates a Credentials instance from parsed external account info. 
@@ -375,6 +404,7 @@ def from_info(cls, info, **kwargs):
375404            universe_domain = info .get (
376405                "universe_domain" , credentials .DEFAULT_UNIVERSE_DOMAIN 
377406            ),
407+             trust_boundary = info .get ("trust_boundary" ),
378408            ** kwargs 
379409        )
380410
0 commit comments