@ -245,6 +245,7 @@ class Authenticator(object):
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    self . _external_token  =  None 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  config . refresh_token_json : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      self . _external_token  =  _read_refresh_token_json ( config . refresh_token_json ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    logging . debug ( ' Using auth config  %r ' ,  config ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				  def  login ( self ) : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    """ Performs interactive login flow if necessary. 
 
			
		 
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
			
			 
			 
			
				@ -306,6 +307,7 @@ class Authenticator(object):
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    """ 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    with  self . _lock : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      if  force_refresh : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        logging . debug ( ' Forcing access token refresh ' ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        self . _access_token  =  self . _create_access_token ( allow_user_interaction ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        return  self . _access_token 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
			
			 
			 
			
				@ -381,6 +383,8 @@ class Authenticator(object):
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      cache_key  =  ' %s :refresh_tok: %s '  %  ( self . _token_cache_key ,  token_hash ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    else : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      cache_key  =  self . _token_cache_key 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    logging . debug ( 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        ' Using token storage  %r  (cache key  %r ) ' ,  OAUTH_TOKENS_CACHE ,  cache_key ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    return  multistore_file . get_credential_storage_custom_string_key ( 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        OAUTH_TOKENS_CACHE ,  cache_key ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -389,6 +393,11 @@ class Authenticator(object):
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    storage  =  self . _get_storage ( ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    credentials  =  storage . get ( ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  not  credentials : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      logging . debug ( ' No cached token ' ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    else : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      _log_credentials_info ( ' cached token ' ,  credentials ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    # Is using --auth-refresh-token-json? 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  self . _external_token : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      # Cached credentials are valid and match external token -> use them. It is 
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -400,10 +409,12 @@ class Authenticator(object):
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				          credentials . client_id  ==  self . _external_token . client_id  and 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				          credentials . client_secret  ==  self . _external_token . client_secret ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      if  valid : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        logging . debug ( ' Cached credentials match external refresh token ' ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        return  credentials 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      # Construct new credentials from externally provided refresh token, 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      # associate them with cache storage (so that access_token will be placed 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      # in the cache later too). 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      logging . debug ( ' Putting external refresh token into the cache ' ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      credentials  =  client . OAuth2Credentials ( 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				          access_token = None , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				          client_id = self . _external_token . client_id , 
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -422,8 +433,10 @@ class Authenticator(object):
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				  def  _load_access_token ( self ) : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    """ Returns cached AccessToken if it is not expired yet. """ 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    logging . debug ( ' Reloading access token from cache ' ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    creds  =  self . _get_cached_credentials ( ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  not  creds  or  not  creds . access_token  or  creds . access_token_expired : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      logging . debug ( ' Access token is missing or expired ' ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      return  None 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    return  AccessToken ( str ( creds . access_token ) ,  creds . token_expiry ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -446,13 +459,18 @@ class Authenticator(object):
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      LoginRequiredError  if  user  interaction  is  required ,  but 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				          allow_user_interaction  is  False . 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    """ 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    logging . debug ( 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        ' Making new access token (allow_user_interaction= %r ) ' , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        allow_user_interaction ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    credentials  =  self . _get_cached_credentials ( ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    # 3-legged flow with (perhaps cached) refresh token. 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    refreshed  =  False 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    if  credentials  and  not  credentials . invalid : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      try : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        logging . debug ( ' Attempting to refresh access_token ' ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        credentials . refresh ( httplib2 . Http ( ) ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        _log_credentials_info ( ' refreshed token ' ,  credentials ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        refreshed  =  True 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      except  client . Error  as  err : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        logging . warning ( 
 
			
		 
		
	
	
		
			
				
					
						
						
						
							
								 
							 
						
					 
				
			
			 
			 
			
				@ -466,8 +484,11 @@ class Authenticator(object):
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        raise  AuthenticationError ( 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				            ' Token provided via --auth-refresh-token-json is no longer valid. ' ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      if  not  allow_user_interaction : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        logging . debug ( ' Requesting user to login ' ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        raise  LoginRequiredError ( self . _token_cache_key ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      logging . debug ( ' Launching OAuth browser flow ' ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      credentials  =  _run_oauth_dance ( self . _config ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				      _log_credentials_info ( ' new token ' ,  credentials ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    logging . info ( 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        ' OAuth access_token refreshed. Expires in  %s . ' , 
 
			
		 
		
	
	
		
			
				
					
						
							
								 
							 
						
						
							
								 
							 
						
						
					 
				
			
			 
			 
			
				@ -513,6 +534,18 @@ def _needs_refresh(access_token):
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				  return  False 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				def  _log_credentials_info ( title ,  credentials ) : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				  """ Dumps (non sensitive) part of client.Credentials object to debug log. """ 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				  if  credentials : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    logging . debug ( ' %s  info:  %r ' ,  title ,  { 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        ' access_token_expired ' :  credentials . access_token_expired , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        ' has_access_token ' :  bool ( credentials . access_token ) , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        ' invalid ' :  credentials . invalid , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        ' utcnow ' :  datetime . datetime . utcnow ( ) , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				        ' token_expiry ' :  credentials . token_expiry , 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				    } ) 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				def  _run_oauth_dance ( config ) : 
 
			
		 
		
	
		
			
				 
				 
			
			 
			 
			
				  """ Perform full 3-legged OAuth2 flow with the browser.