def test_multistore_file(self): access_token = 'foo' client_secret = 'cOuDdkfjxxnv+' refresh_token = '1/0/a.df219fjls0' token_expiry = datetime.datetime.utcnow() token_uri = 'https://www.google.com/accounts/o8/oauth2/token' user_agent = 'refresh_checker/1.0' client_id = 'some_client_id' credentials = OAuth2Credentials(access_token, client_id, client_secret, refresh_token, token_expiry, token_uri, user_agent) store = multistore_file.get_credential_storage( FILENAME, credentials.client_id, credentials.user_agent, ['some-scope', 'some-other-scope']) store.put(credentials) credentials = store.get() self.assertNotEquals(None, credentials) self.assertEquals('foo', credentials.access_token) store.delete() credentials = store.get() self.assertEquals(None, credentials) if os.name == 'posix': self.assertEquals('0600', oct(stat.S_IMODE(os.stat(FILENAME).st_mode)))
def resolve_service(service): if service not in SCOPES.keys(): print "Invalid service: {}, try EVERNOTE or GOOGLE_DRIVE" return try: with open(CONFIG_FILE, 'r') as fl: st = oct(os.stat(CONFIG_FILE)[stat.ST_MODE])[-3:] if st != '600': print "Group / Other readable {}, must be 0600".format(CONFIG_FILE) return conf = yaml.safe_load(fl) except IOError: with open(CONFIG_FILE, 'w') as fl: yaml.dump(CONFIG_TPL, fl, default_flow_style=False) os.chmod(CONFIG_FILE, 0600) print "You must edit the {} file adding your API client ID and Key".format(CONFIG_FILE) return storage = get_credential_storage( CREDENTIALS_FILE, conf[service]['client_id'], hashlib.md5(''.join(SCOPES[service])).hexdigest(), SCOPES[service] ) return ( conf[service]['client_id'], conf[service]['client_secret'], SCOPES[service], storage )
def test_multistore_non_existent_file(self): store = multistore_file.get_credential_storage( FILENAME, "some_client_id", "user-agent/1.0", ["some-scope", "some-other-scope"] ) credentials = store.get() self.assertEquals(None, credentials)
def test_read_only_file_fail_lock(self): access_token = 'foo' client_secret = 'cOuDdkfjxxnv+' refresh_token = '1/0/a.df219fjls0' token_expiry = datetime.datetime.utcnow() token_uri = 'https://www.google.com/accounts/o8/oauth2/token' user_agent = 'refresh_checker/1.0' client_id = 'some_client_id' credentials = OAuth2Credentials( access_token, client_id, client_secret, refresh_token, token_expiry, token_uri, user_agent) open(FILENAME, 'a+b').close() os.chmod(FILENAME, 0400) store = multistore_file.get_credential_storage( FILENAME, credentials.client_id, credentials.user_agent, ['some-scope', 'some-other-scope']) store.put(credentials) if os.name == 'posix': self.assertTrue(store._multistore._read_only) os.chmod(FILENAME, 0600)
def CredentialsFromFile(path, client_info, oauth2client_args=None): """Read credentials from a file.""" credential_store = multistore_file.get_credential_storage( path, client_info['client_id'], client_info['user_agent'], client_info['scope']) if hasattr(FLAGS, 'auth_local_webserver'): FLAGS.auth_local_webserver = False credentials = credential_store.get() if credentials is None or credentials.invalid: print('Generating new OAuth credentials ...') for _ in range(20): # If authorization fails, we want to retry, rather than let this # cascade up and get caught elsewhere. If users want out of the # retry loop, they can ^C. try: flow = oauth2client.client.OAuth2WebServerFlow(**client_info) flags = _GetRunFlowFlags(args=oauth2client_args) credentials = tools.run_flow(flow, credential_store, flags) break except (oauth2client.client.FlowExchangeError, SystemExit) as e: # Here SystemExit is "no credential at all", and the # FlowExchangeError is "invalid" -- usually because # you reused a token. print('Invalid authorization: %s' % (e,)) except httplib2.HttpLib2Error as e: print('Communication error: %s' % (e,)) raise exceptions.CredentialsError( 'Communication error creating credentials: %s' % e) return credentials
def WriteTemplate(self): """Write the credential file.""" # straight up credentials in JSON self._WriteFileContents(self._json_path, self.credentials.to_json()) # multistore version self._WriteFileContents(self._multistore_path, '') storage = oauth2_multistore_file.get_credential_storage( self._multistore_path, self.credentials.client_id, self.credentials.user_agent, self.scopes) storage.put(self.credentials) # gae java wants something special self._WriteFileContents(self._gae_java_path, """ oauth2_client_secret: {secret} oauth2_client_id: {id} oauth2_refresh_token: {token} """.format(secret=config.CLOUDSDK_CLIENT_NOTSOSECRET, id=config.CLOUDSDK_CLIENT_ID, token=self.credentials.refresh_token)) # we create a small .boto file for gsutil, to be put in BOTO_PATH self._WriteFileContents(self._gsutil_path, """ [Credentials] gs_oauth2_refresh_token = {token} """.format(token=self.credentials.refresh_token))
def test_multistore_file(self): access_token = 'foo' client_secret = 'cOuDdkfjxxnv+' refresh_token = '1/0/a.df219fjls0' token_expiry = datetime.datetime.utcnow() token_uri = 'https://www.google.com/accounts/o8/oauth2/token' user_agent = 'refresh_checker/1.0' client_id = 'some_client_id' credentials = OAuth2Credentials( access_token, client_id, client_secret, refresh_token, token_expiry, token_uri, user_agent) store = multistore_file.get_credential_storage( FILENAME, credentials.client_id, credentials.user_agent, ['some-scope', 'some-other-scope']) store.put(credentials) credentials = store.get() self.assertNotEquals(None, credentials) self.assertEquals('foo', credentials.access_token) store.delete() credentials = store.get() self.assertEquals(None, credentials) if os.name == 'posix': self.assertEquals('0600', oct(stat.S_IMODE(os.stat(FILENAME).st_mode)))
def test_read_only_file_fail_lock(self): access_token = 'foo' client_secret = 'cOuDdkfjxxnv+' refresh_token = '1/0/a.df219fjls0' token_expiry = datetime.datetime.utcnow() token_uri = 'https://www.google.com/accounts/o8/oauth2/token' user_agent = 'refresh_checker/1.0' client_id = 'some_client_id' credentials = OAuth2Credentials( access_token, client_id, client_secret, refresh_token, token_expiry, token_uri, user_agent) open(FILENAME, 'a+b').close() os.chmod(FILENAME, 0400) store = multistore_file.get_credential_storage( FILENAME, credentials.client_id, credentials.user_agent, ['some-scope', 'some-other-scope']) store.put(credentials) if os.name == 'posix': self.assertTrue(store._multistore._read_only) os.chmod(FILENAME, 0600)
def test_multistore_non_existent_file(self): store = multistore_file.get_credential_storage( FILENAME, 'some_client_id', 'user-agent/1.0', ['some-scope', 'some-other-scope']) credentials = store.get() self.assertEquals(None, credentials)
def test_renewToken(): global requestors storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, 'testuseraccount', ['https://www.googleapis.com/auth/cloudprint']) credentials = client.OAuth2Credentials('test', Auth.clientid, 'testsecret', 'testtoken', 1, 'https://www.googleapis.com/auth/cloudprint', 'testaccount1') # test renewing token exits in non-interactive mode with pytest.raises(SystemExit): Auth.RenewToken(False, requestors[0], credentials, storage, 'test') # test renewing interactively tries to read from stdin with pytest.raises(IOError): assert Auth.RenewToken(True, requestors[0], credentials, storage, 'test') is False
def AddAccountStep2(userid, flow, code, storage=None, permissions=None): """Executes step 2 of OAuth2WebServerFlow, without interaction. Args: userid: string, reference for the account permissions: string or iterable of strings, scope(s) of the credentials being requested storage: storage, instance of storage to store credentials in. flow: OAuth2WebServerFlow, flow instance code: string, code representing user granting CCP permission to call GCP API for user Returns: credentials: A credentials instance with the account details """ if permissions is None: permissions = Auth.normal_permissions if storage is None: storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, userid, permissions) credentials = flow.step2_exchange(code) storage.put(credentials) Utils.FixFilePermissions(Auth.config) return credentials
def AddAccountStep2(userid, flow, code, storage=None, permissions=None): """Executes step 2 of OAuth2WebServerFlow, without interaction. Args: userid: string, reference for the account permissions: string or iterable of strings, scope(s) of the credentials being requested storage: storage, instance of storage to store credentials in. flow: OAuth2WebServerFlow, flow instance code: string, code representing user granting CCP permission to call GCP API for user Returns: credentials: A credentials instance with the account details """ if permissions is None: permissions = Auth.normal_permissions if storage is None: storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, userid, permissions) credentials = flow.step2_exchange(code) storage.put(credentials) Utils.FixFilePermissions(Auth.config) return credentials
def SetupAuth(interactive=False): """Sets up requestors with authentication tokens Args: interactive: boolean, when set to true can prompt user, otherwise returns False if authentication fails Returns: requestor, storage: Authenticated requestors and an instance of storage """ modifiedconfig = False # parse config file and extract useragents, which we use for account names userids = [] if os.path.exists( Auth.config ): content_file = open(Auth.config, 'r') content = content_file.read() data = json.loads(content) for user in data['data']: userids.append(str(user['credential']['user_agent'])) if len(userids) == 0: userids = [ None ] requestors = [] for userid in userids: storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, userid, ['https://www.googleapis.com/auth/cloudprint']) credentials = storage.get() if not credentials and interactive: # pragma: no cover credentials = Auth.AddAccount(storage, userid) modifiedconfig = True if userid == None: userid = credentials.user_agent elif not interactive and not credentials: return False # renew if expired requestor = cloudprintrequestor() if credentials.access_token_expired: # pragma: no cover credentials.refresh(requestor) requestor = credentials.authorize(requestor) requestor.setAccount(userid) requestors.append(requestor) # fix permissions if modifiedconfig: # pragma: no cover try: os.chmod(Auth.config, 0640) os.chown(Auth.config, 0, Auth.GetLPID()) except: sys.stderr.write("DEBUG: Cannot alter file permissions\n") pass return requestors, storage
def SetupAuth(interactive=False): """Sets up requestors with authentication tokens Args: interactive: boolean, when set to true can prompt user, otherwise returns False if authentication fails Returns: requestor, storage: Authenticated requestors and an instance of storage """ modifiedconfig = False # parse config file and extract useragents, which we use for account names userids = [] if os.path.exists( Auth.config ): content_file = open(Auth.config, 'r') content = content_file.read() data = json.loads(content) for user in data['data']: userids.append(str(user['credential']['user_agent'])) if len(userids) == 0: userids = [ None ] requestors = [] for userid in userids: storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, userid, ['https://www.googleapis.com/auth/cloudprint']) credentials = storage.get() if not credentials and interactive: # pragma: no cover credentials = Auth.AddAccount(storage, userid) modifiedconfig = True if userid == None: userid = credentials.user_agent elif not interactive and not credentials: return False # renew if expired requestor = cloudprintrequestor() if credentials.access_token_expired: # pragma: no cover credentials.refresh(requestor) requestor = credentials.authorize(requestor) requestor.setAccount(userid) requestors.append(requestor) # fix permissions if modifiedconfig: # pragma: no cover try: os.chmod(Auth.config, 0640) os.chown(Auth.config, 0, Auth.GetLPID()) except: sys.stderr.write("DEBUG: Cannot alter file permissions\n") pass return requestors, storage
def credential_store(self): storage_path = os.path.join(self.storage_path, 'oauth_credentials') return get_credential_storage( storage_path, self.client_secrets['client_id'], self.user_agent, self.scope )
def AddAccount(storage, userid=None, permissions=None): """Adds an account to the configuration file with an interactive dialog. Args: storage: storage, instance of storage to store credentials in. userid: string, reference for the account permissions: string or iterable of strings, scope(s) of the credentials being requested Returns: credentials: A credentials instance with the account details """ if permissions is None: permissions = Auth.normal_permissions if userid is None: userid = raw_input( "Name for this user account ( eg [email protected] )? ") # setup storage again if just got userid now storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, userid, permissions) url = None while True: if Utils.hasGUI(): url = Auth.SetupHttpReturnServer() Auth.code = None flow, auth_uri = Auth.AddAccountStep1(userid, permissions, url) message = "Open this URL if it doesn't, grant access to CUPS Cloud Print " message += "( for the " + userid + " account ), " message += "then provide the code displayed : \n\n" message += auth_uri + "\n" print message Utils.openBrowserWithUrl(auth_uri) if url is not None: from select import select print 'Code from Google: ' while (Auth.code is None): result, _, _ = select([sys.stdin], [], [], 0.5) if result and Auth.code is None: s = sys.stdin.readline() if s != "": Auth.code = s Auth.httpd.shutdown() else: Auth.code = raw_input('Code from Google: ') try: credentials = Auth.AddAccountStep2(userid, flow, Auth.code, storage, permissions) return credentials except Exception as e: message = "\nThe code does not seem to be valid ( " message += str(e) + " ), please try again.\n" print message
def credential_store(self): storage_path = os.path.join( xdg.BaseDirectory.save_data_path(self.app._meta.label), 'oauth_credentials') return get_credential_storage( storage_path, self.client_secrets['client_id'], self.Meta.user_agent, self.Meta.scope )
def AddAccount(storage, userid=None, permissions=None): """Adds an account to the configuration file with an interactive dialog. Args: storage: storage, instance of storage to store credentials in. userid: string, reference for the account permissions: string or iterable of strings, scope(s) of the credentials being requested Returns: credentials: A credentials instance with the account details """ if permissions is None: permissions = Auth.normal_permissions if userid is None: userid = raw_input( "Name for this user account ( eg [email protected] )? ") # setup storage again if just got userid now storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, userid, permissions) url = None while True: if Utils.hasGUI(): url = Auth.SetupHttpReturnServer() Auth.code = None flow, auth_uri = Auth.AddAccountStep1(userid, permissions, url) message = "Open this URL if it doesn't, grant access to CUPS Cloud Print " message += "( for the " + userid + " account ), " message += "then provide the code displayed : \n\n" message += auth_uri + "\n" print message Utils.openBrowserWithUrl(auth_uri) if url is not None: from select import select print 'Code from Google: ' while (Auth.code is None): result, _, _ = select([sys.stdin], [], [], 0.5) if result and Auth.code is None: s = sys.stdin.readline() if s != "": Auth.code = s Auth.httpd.shutdown() else: Auth.code = raw_input('Code from Google: ') try: credentials = Auth.AddAccountStep2(userid, flow, Auth.code, storage, permissions) return credentials except Exception as e: message = "\nThe code does not seem to be valid ( " message += str(e) + " ), please try again.\n" print message
def process(): if 'redirect' in session and session['redirect']: session['redirect'] = False data = session['request'] elif request.json: data = request.json elif request.args: data = request.args elif request.form: data = request.form else: return jsonify({'error': 'No link or search parameters were specified.'}), 400 if 'user' not in session or not session['user']: vprint("No user found in session. Redirecting to login first") session['redirect'] = True session['request'] = data return redirect('/login', code=301) else: vprint("User %s found in session. Loading credentials" % session['user']) store = get_credential_storage(credential_store, session['user'], oauth_app_creds['user_agent'], oauth_app_creds['scope']) credentials = store.get() if not credentials: return jsonify({'error': 'No user credentials found'}), 500 else: vprint("Refreshing credentials for user %s" % credentials.id_token['email']) http = httplib2.Http() http = credentials.authorize(http) credentials.refresh(http) vprint("Successfully refreshed credentials for user %s" % credentials.id_token['email']) if 'link' not in data and 'search' not in data: error = "No link or search term was specified" vprint(error) return jsonify({'error': error}), 400 abort(400) try: if 'link' in data: # Strip link to current video for now. Uploading playlists should probably be explicit? link = re.findall('v=(.*?)(?:&|$)', data['link'])[0] youtube_to_gmusic.process_link(link, credentials=credentials) elif 'search' in data: youtube_to_gmusic.process_search(data['search'], credentials=credentials) else: raise(Exception("This shouldn't happen!")) return jsonify({'details': 'success!'}), 200 except Exception as e: vprint('Error: ' + e.message) return jsonify({'error': e.message}), 400
def DeleteAccount(userid): """Delete an account from the configuration file Args: userid: string, reference for the account Returns: deleted: boolean , true on success """ storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, userid, Auth.normal_permissions) return storage.delete()
def DeleteAccount(userid=None): # pragma: no cover """Delete an account from the configuration file Args: storage: storage, instance of storage to store credentials in. userid: string, reference for the account Returns: deleted: boolean , true on success """ storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, userid, ["https://www.googleapis.com/auth/cloudprint"] ) return storage.delete()
def test_read_only_file_fail_lock(self): credentials = self.create_test_credentials() open(FILENAME, 'a+b').close() os.chmod(FILENAME, 0o400) store = multistore_file.get_credential_storage( FILENAME, credentials.client_id, credentials.user_agent, ['some-scope', 'some-other-scope']) store.put(credentials) if os.name == 'posix': self.assertTrue(store._multistore._read_only) os.chmod(FILENAME, 0o600)
def test_multistore_no_symbolic_link_files(self): if hasattr(os, 'symlink'): SYMFILENAME = FILENAME + 'sym' os.symlink(FILENAME, SYMFILENAME) store = multistore_file.get_credential_storage( SYMFILENAME, 'some_client_id', 'user-agent/1.0', ['some-scope', 'some-other-scope']) try: store.get() self.fail('Should have raised an exception.') except locked_file.CredentialsFileSymbolicLinkError: pass finally: os.unlink(SYMFILENAME)
def test_read_only_file_fail_lock(self): credentials = self.create_test_credentials() open(FILENAME, "a+b").close() os.chmod(FILENAME, 0o400) store = multistore_file.get_credential_storage( FILENAME, credentials.client_id, credentials.user_agent, ["some-scope", "some-other-scope"] ) store.put(credentials) if os.name == "posix": self.assertTrue(store._multistore._read_only) os.chmod(FILENAME, 0o600)
def test_multistore_file_backwards_compatibility(self): credentials = self.create_test_credentials() scopes = ["scope1", "scope2"] # store the credentials using the legacy key method store = multistore_file.get_credential_storage(FILENAME, "client_id", "user_agent", scopes) store.put(credentials) # retrieve the credentials using a custom key that matches the legacy key key = {"clientId": "client_id", "userAgent": "user_agent", "scope": util.scopes_to_string(scopes)} store = multistore_file.get_credential_storage_custom_key(FILENAME, key) stored_credentials = store.get() self.assertEqual(credentials.access_token, stored_credentials.access_token)
def DeleteAccount(userid=None): """Delete an account from the configuration file Args: storage: storage, instance of storage to store credentials in. userid: string, reference for the account Returns: deleted: boolean , true on success """ storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, userid, ['https://www.googleapis.com/auth/cloudprint']) return storage.delete()
def test_multistore_no_symbolic_link_files(self): if hasattr(os, "symlink"): SYMFILENAME = FILENAME + "sym" os.symlink(FILENAME, SYMFILENAME) store = multistore_file.get_credential_storage( SYMFILENAME, "some_client_id", "user-agent/1.0", ["some-scope", "some-other-scope"] ) try: store.get() self.fail("Should have raised an exception.") except locked_file.CredentialsFileSymbolicLinkError: pass finally: os.unlink(SYMFILENAME)
def GetAuthorizedCredentials(credential_path, env): """Builds authorized credentials used for communicating with backend services. As the file are stored in the repo and are frequently read only, we copy the credentials file to a temp file that is writable. We need the file to be writable so we can update the access token in the file. Otherwise we ask for an access token each time we need to auth, this can lead to us exceeding API rate limits. Args: credential_path: The path to a credentials file. env: What environment to authorize access for. The master set of environments can be found in data_source_config.py. Returns: An authorized credentials object that can be used to build client libraries and issue authorized requests to backend services. Raises: CredentialKeyError: If the env value passed is not a valid environment. """ if env not in config.Environments.All(): raise CredentialKeyError( '%s is not a valid environment. The valid environments are %s' % (env, config.Environments.All())) try: cred_to_use = _CopyCredentialsToTemp(credential_path) except IOError: logging.error( 'Unable to copy credential files to a writable location.') raise client_id = '%s.apps.googleusercontent.com' % config.Services.GetServiceUri( env, config.Services.PROJECT_ID) user_agent = '%s_perfkit_client/1.0' % env storage = multistore_file.get_credential_storage( cred_to_use, client_id, user_agent, CREDENTIALS_SCOPE) credentials = storage.get() if not credentials: msg = ( 'Could not find credentials.\ncred_to_use: %s\nclient_id: %s\n' 'user_agent: %s\nscope: %s') % (cred_to_use, client_id, user_agent, CREDENTIALS_SCOPE) raise Error(msg) return credentials.authorize(httplib2.Http(timeout=config.DEFAULT_TIMEOUT))
def test_multistore_no_symbolic_link_files(self): if hasattr(os, 'symlink'): SYMFILENAME = FILENAME + 'sym' os.symlink(FILENAME, SYMFILENAME) store = multistore_file.get_credential_storage( SYMFILENAME, 'some_client_id', 'user-agent/1.0', ['some-scope', 'some-other-scope']) try: self.assertRaises( locked_file.CredentialsFileSymbolicLinkError, store.get) finally: os.unlink(SYMFILENAME)
def DeleteAccount(userid): """Delete an account from the configuration file Args: userid: string, reference for the account Returns: deleted: boolean , true on success """ storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, userid, Auth.normal_permissions) return storage.delete()
def test_multistore_no_symbolic_link_files(self): if hasattr(os, 'symlink'): SYMFILENAME = FILENAME + 'sym' os.symlink(FILENAME, SYMFILENAME) store = multistore_file.get_credential_storage( SYMFILENAME, 'some_client_id', 'user-agent/1.0', ['some-scope', 'some-other-scope']) try: store.get() self.fail('Should have raised an exception.') except locked_file.CredentialsFileSymbolicLinkError: pass finally: os.unlink(SYMFILENAME)
def test_read_only_file_fail_lock(self): credentials = self.create_test_credentials() open(FILENAME, 'a+b').close() os.chmod(FILENAME, 0400) store = multistore_file.get_credential_storage( FILENAME, credentials.client_id, credentials.user_agent, ['some-scope', 'some-other-scope']) store.put(credentials) if os.name == 'posix': self.assertTrue(store._multistore._read_only) os.chmod(FILENAME, 0600)
def test_setupAuth(): testUserName = '******' # ensure setup with no details doesnt create file assert os.path.exists(Auth.config) is False assert Auth.SetupAuth(False) == (False, False) assert os.path.exists(Auth.config) is True assert Utils.ReadFile(Auth.config) == "{}" os.unlink(Auth.config) # create initial file assert os.path.exists(Auth.config) is False assert Auth.SetupAuth(False, testUserIds=['test']) == (False, False) assert os.path.exists(Auth.config) is True # ensure permissions are correct after creating config assert '0660' == oct(os.stat(Auth.config)[stat.ST_MODE])[-4:] # add dummy details storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, 'testuseraccount', ['https://www.googleapis.com/auth/cloudprint']) credentials = client.OAuth2Credentials('test', Auth.clientid, 'testsecret', 'testtoken', 1, 'https://www.googleapis.com/auth/cloudprint', testUserName) storage.put(credentials) # ensure permissions are correct after populating config assert '0660' == oct(os.stat(Auth.config)[stat.ST_MODE])[-4:] # re-run to test getting credentials requestors, storage = Auth.SetupAuth(False) assert requestors is not None assert storage is not None # check deleting account assert Auth.DeleteAccount(testUserName) is None requestors, storage = Auth.SetupAuth(False) assert requestors is False assert storage is False
def test_renewToken(): global requestors storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, 'testuseraccount', ['https://www.googleapis.com/auth/cloudprint']) credentials = client.OAuth2Credentials( 'test', Auth.clientid, 'testsecret', 'testtoken', 1, 'https://www.googleapis.com/auth/cloudprint', 'testaccount1') # test renewing token exits in non-interactive mode with pytest.raises(SystemExit): Auth.RenewToken(False, requestors[0], credentials, storage, 'test') # test renewing interactively tries to read from stdin with pytest.raises(IOError): assert Auth.RenewToken(True, requestors[0], credentials, storage, 'test') is False
def test_setupAuthOwnership(): assert Auth.SetupAuth(False, testUserIds=['test']) == (False, False) # ensure ownership is correct after creating config assert Utils.GetLPID() == os.stat(Auth.config).st_gid # add dummy details storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, 'testuseraccount', ['https://www.googleapis.com/auth/cloudprint']) credentials = client.OAuth2Credentials( 'test', Auth.clientid, 'testsecret', 'testtoken', 1, 'https://www.googleapis.com/auth/cloudprint', 'testaccount1') storage.put(credentials) # ensure ownership is correct after populating config assert Utils.GetLPID() == os.stat(Auth.config).st_gid
def test_multistore_file_backwards_compatibility(self): credentials = self._create_test_credentials() scopes = ['scope1', 'scope2'] # store the credentials using the legacy key method store = multistore_file.get_credential_storage( FILENAME, 'client_id', 'user_agent', scopes) store.put(credentials) # retrieve the credentials using a custom key that matches the # legacy key key = {'clientId': 'client_id', 'userAgent': 'user_agent', 'scope': util.scopes_to_string(scopes)} store = multistore_file.get_credential_storage_custom_key( FILENAME, key) stored_credentials = store.get() self.assertEqual(credentials.access_token, stored_credentials.access_token)
def test_setupAuth(): testUserName = '******' # ensure setup with no details doesnt create file assert os.path.exists(Auth.config) is False assert Auth.SetupAuth(False) == (False, False) assert os.path.exists(Auth.config) is True assert Utils.ReadFile(Auth.config) == "{}" os.unlink(Auth.config) # create initial file assert os.path.exists(Auth.config) is False assert Auth.SetupAuth(False, testUserIds=['test']) == (False, False) assert os.path.exists(Auth.config) is True # ensure permissions are correct after creating config assert '0660' == oct(os.stat(Auth.config)[stat.ST_MODE])[-4:] # add dummy details storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, 'testuseraccount', ['https://www.googleapis.com/auth/cloudprint']) credentials = client.OAuth2Credentials( 'test', Auth.clientid, 'testsecret', 'testtoken', 1, 'https://www.googleapis.com/auth/cloudprint', testUserName) storage.put(credentials) # ensure permissions are correct after populating config assert '0660' == oct(os.stat(Auth.config)[stat.ST_MODE])[-4:] # re-run to test getting credentials requestors, storage = Auth.SetupAuth(False) assert requestors is not None assert storage is not None # check deleting account assert Auth.DeleteAccount(testUserName) is None requestors, storage = Auth.SetupAuth(False) assert requestors is False assert storage is False
def do_google_oauth(self): oauth_scope = 'https://www.googleapis.com/auth/adexchange.seller.readonly' self.flow = flow_from_clientsecrets('adxseller_client_secrets.json', scope=oauth_scope, redirect_uri='urn:ietf:wg:oauth:2.0:oob') self.storage = multistore_file.get_credential_storage(filename='credentials.file', client_id=self.ad_client_id, user_agent='', scope=oauth_scope) credentials = self.storage.get() if credentials is None or credentials.invalid: authorize_url = self.flow.step1_get_authorize_url(redirect_uri='urn:ietf:wg:oauth:2.0:oob') return {'pending': authorize_url} # print authorize_url # code = raw_input('Enter verification code: ').strip() else: self.http = credentials.authorize(httplib2.Http()) return {'success': None}
def test_setupAuth(): # create initial file assert os.path.exists('/tmp/cloudprint.conf') == False assert Auth.SetupAuth(False) == False assert os.path.exists('/tmp/cloudprint.conf') == True # add dummy details storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, 'testuseraccount', ['https://www.googleapis.com/auth/cloudprint']) credentials = client.OAuth2Credentials( 'test', Auth.clientid, 'testsecret', 'testtoken', 1, 'https://www.googleapis.com/auth/cloudprint', 'testaccount1') storage.put(credentials) # re-run to test getting credentials requestors, storage = Auth.SetupAuth(False) assert requestors != None assert storage != None
def test_setupAuthOwnership(): assert Auth.SetupAuth(False,testUserIds=['test']) == (False, False) # ensure ownership is correct after creating config assert Utils.GetLPID() == os.stat(Auth.config).st_gid # add dummy details storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, 'testuseraccount', ['https://www.googleapis.com/auth/cloudprint']) credentials = client.OAuth2Credentials('test', Auth.clientid, 'testsecret', 'testtoken', 1, 'https://www.googleapis.com/auth/cloudprint', 'testaccount1') storage.put(credentials) # ensure ownership is correct after populating config assert Utils.GetLPID() == os.stat(Auth.config).st_gid
def test_multistore_file(self): credentials = self.create_test_credentials() store = multistore_file.get_credential_storage( FILENAME, credentials.client_id, credentials.user_agent, ["some-scope", "some-other-scope"] ) store.put(credentials) credentials = store.get() self.assertNotEquals(None, credentials) self.assertEquals("foo", credentials.access_token) store.delete() credentials = store.get() self.assertEquals(None, credentials) if os.name == "posix": self.assertEquals("0600", oct(stat.S_IMODE(os.stat(FILENAME).st_mode)))
def test_multistore_file_backwards_compatibility(self): credentials = self.create_test_credentials() scopes = ['scope1', 'scope2'] # store the credentials using the legacy key method store = multistore_file.get_credential_storage(FILENAME, 'client_id', 'user_agent', scopes) store.put(credentials) # retrieve the credentials using a custom key that matches the legacy key key = { 'clientId': 'client_id', 'userAgent': 'user_agent', 'scope': util.scopes_to_string(scopes) } store = multistore_file.get_credential_storage_custom_key( FILENAME, key) stored_credentials = store.get() self.assertEqual(credentials.access_token, stored_credentials.access_token)
def test_multistore_file(self): credentials = self.create_test_credentials() store = multistore_file.get_credential_storage( FILENAME, credentials.client_id, credentials.user_agent, ['some-scope', 'some-other-scope']) store.put(credentials) credentials = store.get() self.assertNotEquals(None, credentials) self.assertEquals('foo', credentials.access_token) store.delete() credentials = store.get() self.assertEquals(None, credentials) if os.name == 'posix': self.assertEquals('0o600', oct(stat.S_IMODE(os.stat(FILENAME).st_mode)))
def test_multistore_file(self): credentials = self.create_test_credentials() store = multistore_file.get_credential_storage( FILENAME, credentials.client_id, credentials.user_agent, ['some-scope', 'some-other-scope']) store.put(credentials) credentials = store.get() self.assertNotEquals(None, credentials) self.assertEqual('foo', credentials.access_token) store.delete() credentials = store.get() self.assertEqual(None, credentials) if os.name == 'posix': self.assertEqual('0o600', oct(stat.S_IMODE(os.stat(FILENAME).st_mode)))
def test_setupAuth(): # create initial file assert os.path.exists('/tmp/cloudprint.conf') == False assert Auth.SetupAuth(False) == False assert os.path.exists('/tmp/cloudprint.conf') == True # add dummy details storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, 'testuseraccount', ['https://www.googleapis.com/auth/cloudprint']) credentials = client.OAuth2Credentials('test', Auth.clientid, 'testsecret', 'testtoken', 1, 'https://www.googleapis.com/auth/cloudprint', 'testaccount1') storage.put(credentials) # re-run to test getting credentials requestors, storage = Auth.SetupAuth(False) assert requestors != None assert storage != None
def oauth2callback(): error = request.args.get('error', '') if error: return jsonify({'error': error}) try: credentials = flow.step2_exchange(code=request.args) user = credentials.id_token['email'] store = get_credential_storage(credential_store, user, oauth_app_creds['user_agent'], oauth_app_creds['scope']) old_credentials = store.get() if old_credentials: ort = old_credentials.refresh_token nrt = old_credentials.refresh_token credentials.refresh_token = ort if not nrt else nrt # Check that the credentials we have are correct before writing them out to storage http = httplib2.Http() http = credentials.authorize(http) credentials.refresh(http) # Clean up old credentials before writing new ones. # For some reason it sometimes ends up with duplicates? store.delete() store.put(credentials) except Exception as e: if 'invalid_grant' in e.message: code = 500 else: code = 400 return jsonify({'error': e.message}), code session['user'] = user if 'redirect' in session and session['redirect']: return redirect('/process', code=301) return redirect('/login', code=301)
if FLAGS.auth_service_account and metadata_present: try: return auto_auth.Credentials(metadata, FLAGS.auth_service_account, scopes, any_available=True) except auto_auth.CredentialsNotPresentError, e: pass except auto_auth.CredentialsError, e: # We failed to get the scopes from the metadata server. if logger: logger.warn( 'Failed to automatically authenticate with service ' 'account: %s' % (e)) storage = oauth2_multistore_file.get_credential_storage( credentials_file, client_id, user_agent, scopes_str) credentials = storage.get() if force_reauth and credentials: credentials.invalid = True if (not credentials or credentials.invalid == True) and ask_user: if FLAGS.auth_service_account and metadata_present: print( 'Service account scopes are not enabled for %s on this instance. ' 'Using manual authentication.') % (FLAGS.auth_service_account) flow = oauth2_client.OAuth2WebServerFlow( client_id=client_id, client_secret=client_secret,
def SetupAuth(interactive=False, permissions=None, testUserIds=None): """Sets up requestors with authentication tokens Args: interactive: boolean, when set to true can prompt user, otherwise returns False if authentication fails Returns: requestor, storage: Authenticated requestors and an instance of storage """ if permissions is None: permissions = Auth.normal_permissions modifiedconfig = False # parse config file and extract useragents, which we use for account # names userids = [] if testUserIds is not None: userids = testUserIds if os.path.exists(Auth.config): data = json.loads(Utils.ReadFile(Auth.config)) if 'data' in data: for user in data['data']: userids.append(str(user['credential']['user_agent'])) else: Utils.WriteFile(Auth.config, '{}') Utils.FixFilePermissions(Auth.config) modifiedconfig = True if len(userids) == 0: userids = [None] requestors = [] storage = None credentials = None for userid in userids: if userid is not None: storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, userid, permissions) credentials = storage.get() if not credentials and interactive: credentials = Auth.AddAccount(storage, userid, permissions) modifiedconfig = True if userid is None: userid = credentials.user_agent if credentials: # renew if expired requestor = CloudPrintRequestor() if credentials.access_token_expired: Auth.RenewToken(interactive, requestor, credentials, storage, userid) requestor = credentials.authorize(requestor) requestor.setAccount(userid) requestors.append(requestor) # fix permissions if modifiedconfig: Utils.FixFilePermissions(Auth.config) if not credentials: return False, False else: return requestors, storage
def WriteTemplate(self): """Write the credential file.""" # straight up credentials in JSON self._WriteFileContents(self._json_path, self.credentials.to_json()) # multistore version self._WriteFileContents(self._multistore_path, '') storage = oauth2_multistore_file.get_credential_storage( self._multistore_path, self.credentials.client_id, self.credentials.user_agent, self.scopes) storage.put(self.credentials) if self.credentials.refresh_token: # gae java wants something special self._WriteFileContents(self._gae_java_path, textwrap.dedent("""\ oauth2_client_secret: {secret} oauth2_client_id: {id} oauth2_refresh_token: {token} """).format(secret=config.CLOUDSDK_CLIENT_NOTSOSECRET, id=config.CLOUDSDK_CLIENT_ID, token=self.credentials.refresh_token)) # we create a small .boto file for gsutil, to be put in BOTO_PATH self._WriteFileContents(self._gsutil_path, textwrap.dedent("""\ [Credentials] gs_oauth2_refresh_token = {token} """).format(token=self.credentials.refresh_token)) if (oauth2_client.HAS_CRYPTO and type(self.credentials) == oauth2_client.SignedJwtAssertionCredentials): with files.OpenForWritingPrivate(self._key_path) as pk: pk.write(base64.b64decode(self.credentials.private_key)) # the .boto file gets some different fields self._WriteFileContents(self._gsutil_path, textwrap.dedent("""\ [Credentials] gs_service_client_id = {account} gs_service_key_file = {key_file} gs_service_key_file_password = {key_password} """).format(account=self.credentials.service_account_name, key_file=self._key_path, key_password=self.credentials.private_key_password)) # pylint: disable=protected-access # Remove linter directive when # https://github.com/google/oauth2client/issues/165 is addressed. if isinstance(self.credentials, oauth2_service_account._ServiceAccountCredentials): # TODO(cherba): Currently activate-service-account discards the JSON # key file after reading it; save it so that we can hand it to gsutil. # For now, serialize the credentials back to their original # JSON key file form. json_key_dict = { 'client_id': self.credentials._service_account_id, 'client_email': self.credentials._service_account_email, 'private_key': self.credentials._private_key_pkcs8_text, 'private_key_id': self.credentials._private_key_id, 'type': 'service_account' } with files.OpenForWritingPrivate(self._json_key_path) as pk: pk.write(json.dumps(json_key_dict)) self._WriteFileContents(self._gsutil_path, textwrap.dedent("""\ [Credentials] gs_service_key_file = {key_file} """).format(key_file=self._json_key_path))
def WriteTemplate(self): """Write the credential file.""" # straight up credentials in JSON self._WriteFileContents(self._json_path, self.credentials.to_json()) # multistore version self._WriteFileContents(self._multistore_path, '') storage = oauth2_multistore_file.get_credential_storage( self._multistore_path, self.credentials.client_id, self.credentials.user_agent, self.scopes) storage.put(self.credentials) if self.credentials.refresh_token: # gae java wants something special self._WriteFileContents( self._gae_java_path, textwrap.dedent("""\ oauth2_client_secret: {secret} oauth2_client_id: {id} oauth2_refresh_token: {token} """).format(secret=config.CLOUDSDK_CLIENT_NOTSOSECRET, id=config.CLOUDSDK_CLIENT_ID, token=self.credentials.refresh_token)) # we create a small .boto file for gsutil, to be put in BOTO_PATH self._WriteFileContents( self._gsutil_path, textwrap.dedent("""\ [Credentials] gs_oauth2_refresh_token = {token} """).format(token=self.credentials.refresh_token)) if (oauth2_client.HAS_CRYPTO and type(self.credentials) == oauth2_client.SignedJwtAssertionCredentials): with files.OpenForWritingPrivate(self._key_path) as pk: pk.write(base64.b64decode(self.credentials.private_key)) # the .boto file gets some different fields self._WriteFileContents( self._gsutil_path, textwrap.dedent("""\ [Credentials] gs_service_client_id = {account} gs_service_key_file = {key_file} gs_service_key_file_password = {key_password} """).format(account=self.credentials.service_account_name, key_file=self._key_path, key_password=self.credentials.private_key_password)) # pylint: disable=protected-access # Remove linter directive when # https://github.com/google/oauth2client/issues/165 is addressed. if isinstance(self.credentials, oauth2_service_account._ServiceAccountCredentials): # TODO(cherba): Currently activate-service-account discards the JSON # key file after reading it; save it so that we can hand it to gsutil. # For now, serialize the credentials back to their original # JSON key file form. json_key_dict = { 'client_id': self.credentials._service_account_id, 'client_email': self.credentials._service_account_email, 'private_key': self.credentials._private_key_pkcs8_text, 'private_key_id': self.credentials._private_key_id, 'type': 'service_account' } with files.OpenForWritingPrivate(self._json_key_path) as pk: pk.write(json.dumps(json_key_dict)) self._WriteFileContents( self._gsutil_path, textwrap.dedent("""\ [Credentials] gs_service_key_file = {key_file} """).format(key_file=self._json_key_path))
def SetupAuth(interactive=False, permissions=['https://www.googleapis.com/auth/cloudprint']): """Sets up requestors with authentication tokens Args: interactive: boolean, when set to true can prompt user, otherwise returns False if authentication fails Returns: requestor, storage: Authenticated requestors and an instance of storage """ modifiedconfig = False # parse config file and extract useragents, which we use for account names userids = [] if os.path.exists(Auth.config): content_file = open(Auth.config, 'r') content = content_file.read() data = json.loads(content) for user in data['data']: userids.append(str(user['credential']['user_agent'])) else: modifiedconfig = True if len(userids) == 0: userids = [None] requestors = [] for userid in userids: storage = multistore_file.get_credential_storage( Auth.config, Auth.clientid, userid, permissions) credentials = storage.get() if not credentials and interactive: credentials = Auth.AddAccount(storage, userid) modifiedconfig = True if userid == None: userid = credentials.user_agent if credentials: # renew if expired requestor = cloudprintrequestor() if credentials.access_token_expired: from oauth2client.client import AccessTokenRefreshError try: credentials.refresh(requestor) except AccessTokenRefreshError as e: sys.stderr.write( "Failed to renew token (error: " + str(e) + "), if you have revoked access to CUPS Cloud Print in your Google Account, please delete /etc/cloudprint.conf and re-run /usr/share/cloudprint-cups/setupcloudprint.py\n" ) sys.exit(1) requestor = credentials.authorize(requestor) requestor.setAccount(userid) requestors.append(requestor) # fix permissions if modifiedconfig: Utils.FixFilePermissions(Auth.config) if not credentials: return False, False else: return requestors, storage
def GetCredentialFromStore(desired_scopes, ask_user=True, force_reauth=False, credentials_file=None, authorization_uri_base=None, client_id=OAUTH2_CLIENT_ID, client_secret=OAUTH2_CLIENT_SECRET, user_agent=USER_AGENT, metadata=metadata_lib.Metadata(), oauth2_gce=oauth2_gce_client, logger=None): """Get OAuth2 credentials for a specific scope. Args: desired_scopes: A list of OAuth2 scopes to request. ask_user: If True, prompt the user to authenticate. force_reauth: If True, force users to reauth credentials_file: The file to use to get/store credentials. If left at None FLAGS.credentials_file will be used. authorization_uri_base: The base URI for auth requests. If left at None FLAGS.authorization_uri_base will be used. client_id: The OAuth2 client id client_secret: The OAuth2 client secret user_agent: The user agent for requests Returns: An OAuth2Credentials object or None """ if not credentials_file: credentials_file = FLAGS.credentials_file if not authorization_uri_base: authorization_uri_base = FLAGS.authorization_uri_base credentials_file = os.path.realpath(os.path.expanduser(credentials_file)) # Ensure that the directory to contain the credentials file exists. credentials_dir = os.path.expanduser(os.path.dirname(credentials_file)) if not os.path.exists(credentials_dir): os.makedirs(credentials_dir) desired_scopes = [ 'https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/cloud-platform', 'https://www.googleapis.com/auth/appengine.admin', 'https://www.googleapis.com/auth/compute' ] desired_scopes_str = ' '.join(desired_scopes) metadata_present = False if FLAGS.auth_service_account: metadata_present = metadata.IsPresent() storage = oauth2_multistore_file.get_credential_storage( credentials_file, client_id, user_agent, desired_scopes_str) if FLAGS.auth_service_account and metadata_present: try: vm_scopes = metadata.GetServiceAccountScopes() # Only use gce auth if there is a compute scope in there. if (scopes.COMPUTE_RW_SCOPE in vm_scopes or scopes.COMPUTE_RO_SCOPE in vm_scopes or scopes.CLOUD_PLATFORM_SCOPE in vm_scopes): try: credentials = oauth2_gce.AppAssertionCredentials([]) credentials.refresh(utils.GetHttp()) http = credentials.authorize(utils.GetHttp()) resp, content = http.request( 'https://www.googleapis.com/userinfo/v2/me') if resp.status == 200: userinfo = json.loads(content) credentials.token_id = userinfo storage.put(credentials) return credentials except httplib2.ServerNotFoundError: # We are not running on a VM. pass except oauth2_client.AccessTokenRefreshError: # We are probably not running on a VM. pass except metadata_lib.MetadataError: # We don't seem to have any scopes. pass credentials = storage.get() if not credentials or credentials.invalid: # Look for the legacy auth scopes, in case they're present, we can use # them instead. legacy_desired_scopes_str = ' '.join(sorted(scopes.LEGACY_AUTH_SCOPES)) legacy_storage = oauth2_multistore_file.get_credential_storage( credentials_file, client_id, user_agent, legacy_desired_scopes_str) credentials = legacy_storage.get() if force_reauth and credentials: credentials.invalid = True if (not credentials or credentials.invalid == True) and ask_user: if FLAGS.auth_service_account and metadata_present: print( 'Service account scopes are not enabled for %s on this instance. ' 'Using manual authentication.') % (FLAGS.auth_service_account) # If gcutil is being run from within the Cloud SDK, do not do the web flow. # Instead, print out a message indicating that the user must log in via # "gcloud auth login". if os.environ.get('CLOUDSDK_WRAPPER', '0') == '1': msg = textwrap.dedent("""\ You are not currently logged in. To authenticate, run $ gcloud auth login """) sys.stderr.write(msg) sys.exit(1) flow = oauth2_client.OAuth2WebServerFlow( client_id=client_id, client_secret=client_secret, scope=desired_scopes_str, user_agent=user_agent, auth_uri=authorization_uri_base + '/auth', token_uri=authorization_uri_base + '/token') credentials = oauth2_tools.run(flow, storage, http=utils.GetHttp()) return credentials