def account_with_single_auth_creds(db): email = '*****@*****.**' resp = {'access_token': '', 'expires_in': 3600, 'email': email, 'family_name': '', 'given_name': '', 'name': '', 'gender': '', 'id': 0, 'user_id': '', 'id_token': '', 'link': 'http://example.com', 'locale': '', 'picture': '', 'hd': '', 'refresh_token': 'refresh_token_3', 'client_id': 'client_id_1', 'client_secret': 'client_secret_1', 'scope': ' '.join([GOOGLE_CALENDAR_SCOPE, GOOGLE_EMAIL_SCOPE]), 'sync_contacts': False, 'sync_events': True } g = GmailAuthHandler('gmail') g.verify_config = lambda x: True account = g.get_account(SHARD_ID, email, resp) db.session.add(account) db.session.commit() return account
def test_invalid_token_during_connect(db, patch_access_token_getter, account_with_single_auth_creds): account_id = account_with_single_auth_creds.id patch_access_token_getter.revoke_refresh_token( account_with_single_auth_creds.auth_credentials[0].refresh_token) account_with_single_auth_creds.verify_all_credentials() assert len(account_with_single_auth_creds.valid_auth_credentials) == 0 g_token_manager.clear_cache(account_with_single_auth_creds) # connect_account() takes an /expunged/ account object # that has the necessary relationships eager-loaded object_session(account_with_single_auth_creds).expunge( account_with_single_auth_creds) assert not object_session(account_with_single_auth_creds) account = db.session.query(GmailAccount).options( joinedload(GmailAccount.auth_credentials)).get( account_id) db.session.expunge(account) assert not object_session(account) g = GmailAuthHandler('gmail') with pytest.raises(OAuthError): g.connect_account(account) invalid_account = db.session.query(GmailAccount).get(account_id) for auth_creds in invalid_account.auth_credentials: assert not auth_creds.is_valid
def test_token(db, config, encrypt): """ If encryption is enabled, ensure that: * tokens are encrypted. * tokens are decrypted correctly on retrieval. Note: This tests refresh_tokens but passwords work in the same way """ config['ENCRYPT_SECRETS'] = encrypt token = 'tH*$&123abcº™™∞' email = '*****@*****.**' resp = {'access_token': '', 'expires_in': 3600, 'refresh_token': token, 'scope': '', 'email': email, 'family_name': '', 'given_name': '', 'name': '', 'gender': '', 'id': 0, 'user_id': '', 'id_token': '', 'link': 'http://example.com', 'locale': '', 'picture': '', 'hd': ''} g = GmailAuthHandler('gmail') g.verify_config = lambda x: True account = g.create_account(db.session, email, resp) db.session.add(account) db.session.commit() secret_id = account.refresh_token_id secret = db.session.query(Secret).get(secret_id) assert secret == account.secret if encrypt: assert secret._secret != token, 'token not encrypted' else: assert secret._secret == token, \ 'token encrypted when encryption disabled' decrypted_secret = secret.secret assert decrypted_secret == token and \ account.refresh_token == decrypted_secret, \ 'token not decrypted correctly' # Remove auth credentials row, else weird things # happen when we try to read both encrypted and # unencrypted data from the database. for ac in account.auth_credentials: db.session.delete(ac) # db.session.delete(account.auth_credentials[0]) db.session.commit()
def test_token(db, config, encrypt): """ If encryption is enabled, ensure that: * tokens are encrypted. * tokens are decrypted correctly on retrieval. Note: This tests refresh_tokens but passwords work in the same way """ config['ENCRYPT_SECRETS'] = encrypt token = 'tH*$&123abcº™™∞' email = '*****@*****.**' resp = { 'access_token': '', 'expires_in': 3600, 'refresh_token': token, 'scope': '', 'email': email, 'family_name': '', 'given_name': '', 'name': '', 'gender': '', 'id': 0, 'user_id': '', 'id_token': '', 'link': 'http://example.com', 'locale': '', 'picture': '', 'hd': '' } g = GmailAuthHandler('gmail') g.verify_config = lambda x: True account = g.create_account(db.session, email, resp) db.session.add(account) db.session.commit() secret_id = account.refresh_token_id secret = db.session.query(Secret).get(secret_id) assert secret == account.secret if encrypt: assert secret._secret != token, 'token not encrypted' else: assert secret._secret == token, \ 'token encrypted when encryption disabled' decrypted_secret = secret.secret assert decrypted_secret == token and \ account.refresh_token == decrypted_secret, \ 'token not decrypted correctly' # Remove auth credentials row, else weird things # happen when we try to read both encrypted and # unencrypted data from the database. db.session.delete(account.auth_credentials[0]) db.session.commit()
def get_auth_handler(monkeypatch, folders): g = GmailAuthHandler('gmail') def mock_connect(x, y, z): return ConnectionStub() g.connect_account = mock_connect monkeypatch.setattr(GmailCrispinClient, 'folder_names', lambda x: folders) return g
def get_auth_handler(monkeypatch, folders): g = GmailAuthHandler('gmail') def mock_connect(a): return ConnectionStub() g.connect_account = mock_connect monkeypatch.setattr(GmailCrispinClient, 'folder_names', lambda x: folders) return g
def account_with_multiple_auth_creds(db): email = '*****@*****.**' resp = { 'access_token': '', 'expires_in': 3600, 'email': email, 'family_name': '', 'given_name': '', 'name': '', 'gender': '', 'id': 0, 'user_id': '', 'id_token': '', 'link': 'http://example.com', 'locale': '', 'picture': '', 'hd': '' } all_scopes = ' '.join( [GOOGLE_CALENDAR_SCOPE, GOOGLE_CONTACTS_SCOPE, GOOGLE_EMAIL_SCOPE]) first_auth_args = { 'refresh_token': 'refresh_token_1', 'client_id': 'client_id_1', 'client_secret': 'client_secret_1', 'scope': all_scopes, 'sync_contacts': True, 'sync_events': True } second_auth_args = { 'refresh_token': 'refresh_token_2', 'client_id': 'client_id_2', 'client_secret': 'client_secret_2', 'scope': GOOGLE_EMAIL_SCOPE, 'sync_contacts': False, 'sync_events': False } g = GmailAuthHandler('gmail') g.verify_config = lambda x: True resp.update(first_auth_args) account = g.create_account(db.session, email, resp) db.session.add(account) db.session.commit() resp.update(second_auth_args) account = g.create_account(db.session, email, resp) db.session.add(account) db.session.commit() return account
def test_create_account(db): email = '*****@*****.**' resp = { 'access_token': '', 'expires_in': 3600, 'email': email, 'family_name': '', 'given_name': '', 'name': '', 'gender': '', 'id': 0, 'user_id': '', 'id_token': '', 'link': 'http://example.com', 'locale': '', 'picture': '', 'hd': '' } g = GmailAuthHandler('gmail') g.verify_config = lambda x: True # Auth me once... token_1 = 'the_first_token' client_id_1 = 'first client id' client_secret_1 = 'first client secret' scopes_1 = 'scope scop sco sc s' scopes_1_list = scopes_1.split(' ') first_auth_args = { 'refresh_token': token_1, 'scope': scopes_1, 'client_id': client_id_1, 'client_secret': client_secret_1 } resp.update(first_auth_args) account = g.create_account(email, resp) db.session.add(account) db.session.commit() account_id = account.id with session_scope(account_id) as db_session: account = db_session.query(Account).filter( Account.email_address == email).one() assert account.id == account_id assert isinstance(account, GmailAccount) assert len(account.auth_credentials) == 1 auth_creds = account.auth_credentials[0] assert auth_creds.client_id == client_id_1 assert auth_creds.client_secret == client_secret_1 assert auth_creds.scopes == scopes_1_list assert auth_creds.refresh_token == token_1
def account_with_multiple_auth_creds(db): email = '*****@*****.**' resp = {'access_token': '', 'expires_in': 3600, 'email': email, 'family_name': '', 'given_name': '', 'name': '', 'gender': '', 'id': 0, 'user_id': '', 'id_token': '', 'link': 'http://example.com', 'locale': '', 'picture': '', 'hd': ''} all_scopes = ' '.join( [GOOGLE_CALENDAR_SCOPE, GOOGLE_CONTACTS_SCOPE, GOOGLE_EMAIL_SCOPE]) first_auth_args = { 'refresh_token': 'refresh_token_1', 'client_id': 'client_id_1', 'client_secret': 'client_secret_1', 'scope': all_scopes, 'sync_contacts': True, 'sync_events': True } second_auth_args = { 'refresh_token': 'refresh_token_2', 'client_id': 'client_id_2', 'client_secret': 'client_secret_2', 'scope': GOOGLE_EMAIL_SCOPE, 'sync_contacts': False, 'sync_events': False } g = GmailAuthHandler('gmail') g.verify_config = lambda x: True resp.update(first_auth_args) account = g.get_account(SHARD_ID, email, resp) db.session.add(account) db.session.commit() resp.update(second_auth_args) account = g.get_account(SHARD_ID, email, resp) db.session.add(account) db.session.commit() return account
def test_create_account(db): email = '*****@*****.**' resp = {'access_token': '', 'expires_in': 3600, 'email': email, 'family_name': '', 'given_name': '', 'name': '', 'gender': '', 'id': 0, 'user_id': '', 'id_token': '', 'link': 'http://example.com', 'locale': '', 'picture': '', 'hd': ''} g = GmailAuthHandler('gmail') g.verify_config = lambda x: True # Auth me once... token_1 = 'the_first_token' client_id_1 = 'first client id' client_secret_1 = 'first client secret' scopes_1 = 'scope scop sco sc s' scopes_1_list = scopes_1.split(' ') first_auth_args = { 'refresh_token': token_1, 'scope': scopes_1, 'client_id': client_id_1, 'client_secret': client_secret_1 } resp.update(first_auth_args) account = g.create_account(email, resp) db.session.add(account) db.session.commit() account_id = account.id with session_scope(account_id) as db_session: account = db_session.query(Account).filter( Account.email_address == email).one() assert account.id == account_id assert isinstance(account, GmailAccount) assert len(account.auth_credentials) == 1 auth_creds = account.auth_credentials[0] assert auth_creds.client_id == client_id_1 assert auth_creds.client_secret == client_secret_1 assert auth_creds.scopes == scopes_1_list assert auth_creds.refresh_token == token_1
def test_create_account(db): handler = GmailAuthHandler('gmail') # Create an account account = handler.create_account(settings['email'], settings) db.session.add(account) db.session.commit() # Verify its settings id_ = account.id account = db.session.query(Account).get(id_) assert account.email_address == settings['email'] assert account.name == settings['name'] assert account.sync_email == settings['sync_email'] assert account.sync_contacts == settings['contacts'] assert account.sync_events == settings['events']
def test_update_account(db): handler = GmailAuthHandler('gmail') # Create an account account = handler.create_account(settings['email'], settings) db.session.add(account) db.session.commit() id_ = account.id # Verify it is updated correctly. updated_settings = copy.deepcopy(settings) updated_settings['name'] = 'Neu!' account = handler.update_account(account, updated_settings) db.session.add(account) db.session.commit() account = db.session.query(Account).get(id_) assert account.name == 'Neu!'
def login_gmail_account(): authcode = request.values.get('authcode') redirecturi = request.values.get('redirecturi') auth_handler = GmailAuthHandler(provider_name='gmail') auth_handler.OAUTH_REDIRECT_URI = redirecturi auth_info = auth_handler._get_authenticated_user(authcode) email_address = auth_info['email'] with session_scope(0) as db_session: account = db_session.query(Account).filter_by(email_address=email_address).first() if account is None: return default_json_error('The account does not exist!') api_id = account.namespace.public_id return jsonify({"message": "Login successful", "api_id": api_id})
def test_create_account(db): handler = GmailAuthHandler('gmail') # Create an account account = handler.create_account(settings['email'], settings) db.session.add(account) db.session.commit() # Verify its settings id_ = account.id account = db.session.query(Account).get(id_) assert account.email_address == settings['email'] assert account.name == settings['name'] assert account.sync_email == settings['sync_email'] assert account.sync_contacts == settings['contacts'] assert account.sync_events == settings['events'] # Ensure that the emailed events calendar was created assert account._emailed_events_calendar is not None assert account._emailed_events_calendar.name == 'Emailed events'
def test_token(db, config, encrypt): """ If encryption is enabled, ensure that: * tokens are encrypted. * tokens are decrypted correctly on retrieval. Note: This tests refresh_tokens but passwords work in the same way """ config['ENCRYPT_SECRETS'] = encrypt token = 'tH*$&123abcº™™∞' email = '*****@*****.**' resp = { 'access_token': '', 'expires_in': 3600, 'refresh_token': token, 'scope': '', 'email': email, 'family_name': '', 'given_name': '', 'name': '', 'gender': '', 'id': 0, 'user_id': '', 'id_token': '', 'link': 'http://example.com', 'locale': '', 'picture': '', 'hd': '' } account = GmailAuthHandler('gmail').create_account(db.session, email, resp) db.session.add(account) db.session.commit() secret_id = account.refresh_token_id secret = db.session.query(Secret).get(secret_id) assert secret == account.secret if encrypt: assert secret._secret != token, 'token not encrypted' else: assert secret._secret == token, 'token encrypted when encryption disabled' decrypted_secret = secret.secret assert decrypted_secret == token and \ account.refresh_token == decrypted_secret, \ 'token not decrypted correctly'
def new_gmail_account(): logger = get_logger() authcode = request.values.get('authcode') redirecturi = request.values.get('redirecturi') reauth = True auth_handler = GmailAuthHandler(provider_name='gmail') auth_handler.OAUTH_REDIRECT_URI = redirecturi auth_info = auth_handler._get_authenticated_user(authcode) auth_info['contacts'] = True auth_info['events'] = True auth_info['provider'] = 'gmail' email_address = auth_info['email'] account_exists = False # Check for email in allowed emails list emails_filter_enabled = config.get('EMAILS_FILTER_ENABLED') allowed_emails = config.get('ALLOWED_EMAILS') if emails_filter_enabled and allowed_emails and email_address not in allowed_emails: return jsonify({"code": "email_not_allowed", "message": "Email not allowed", "profile": auth_info}) with session_scope(0) as db_session: account = db_session.query(Account).filter_by(email_address=email_address).first() if account is not None and not reauth: api_id = account.namespace.public_id return jsonify({"code": "account_exist", "message": "Account already exist", "api_id": api_id}) elif account is not None and reauth: account_exists = True account = auth_handler.update_account(account, auth_info) else: account = auth_handler.create_account(email_address, auth_info) try: if auth_handler.verify_account(account): db_session.add(account) db_session.commit() except NotSupportedError as e: return default_json_error(e) api_id = account.namespace.public_id if account_exists: return jsonify({"code": "account_updated", "message": "Account already exist and Updated", "api_id": api_id}) return jsonify({"code": "account_created", "message": "new account created", "api_id": api_id})
def test_verify_account(db, patched_gmail_client): handler = GmailAuthHandler('gmail') handler.connect_account = lambda account: None # Create an account with sync_email=True account = handler.create_account(settings['email'], settings) db.session.add(account) db.session.commit() assert account.sync_email is True # Verify an exception is raised if there is an email settings error. with pytest.raises(ImapSupportDisabledError): handler.verify_account(account) # Create an account with sync_email=True updated_settings = copy.deepcopy(settings) updated_settings['email'] = '*****@*****.**' updated_settings['sync_email'] = False account = handler.create_account(updated_settings['email'], updated_settings) db.session.add(account) db.session.commit() assert account.sync_email is False # Verify an exception is NOT raised if there is an email settings error. account = handler.verify_account(account)
def test_verify_account(db, patched_gmail_client): handler = GmailAuthHandler('gmail') handler.connect_account = lambda account: None # Create an account with sync_email=True account = handler.create_account(settings['email'], settings) db.session.add(account) db.session.commit() assert account.sync_email == True # Verify an exception is raised if there is an email settings error. with pytest.raises(ImapSupportDisabledError): handler.verify_account(account) # Create an account with sync_email=True updated_settings = copy.deepcopy(settings) updated_settings['email'] = '*****@*****.**' updated_settings['sync_email'] = False account = handler.create_account(updated_settings['email'], updated_settings) db.session.add(account) db.session.commit() assert account.sync_email == False # Verify an exception is NOT raised if there is an email settings error. account = handler.verify_account(account)
def test_successful_reauth_resets_sync_state(monkeypatch, db): monkeypatch.setattr('inbox.auth.gmail.GmailCrispinClient', mock.Mock()) handler = GmailAuthHandler('gmail') handler.connect_account = lambda account: mock.Mock() account = handler.create_account(settings['email'], settings) assert handler.verify_account(account) is True # Brand new accounts have `sync_state`=None. assert account.sync_state is None db.session.add(account) db.session.commit() # Pretend account sync starts, and subsequently the password changes, # causing the account to be in `sync_state`='invalid'. account.mark_invalid() db.session.commit() assert account.sync_state == 'invalid' # Verify the `sync_state` is reset to 'running' on a successful "re-auth". account = handler.update_account(account, settings) assert handler.verify_account(account) is True assert account.sync_state == 'running' db.session.add(account) db.session.commit()
def test_get_account(db): email = '*****@*****.**' resp = {'access_token': '', 'expires_in': 3600, 'email': email, 'family_name': '', 'given_name': '', 'name': '', 'gender': '', 'id': 0, 'user_id': '', 'id_token': '', 'link': 'http://example.com', 'locale': '', 'picture': '', 'hd': ''} g = GmailAuthHandler('gmail') g.verify_config = lambda x: True # Auth me once... token_1 = 'the_first_token' client_id_1 = 'first client id' client_secret_1 = 'first client secret' scopes_1 = 'scope scop sco sc s' scopes_1_list = scopes_1.split(' ') first_auth_args = { 'refresh_token': token_1, 'scope': scopes_1, 'client_id': client_id_1, 'client_secret': client_secret_1 } resp.update(first_auth_args) account = g.get_account(SHARD_ID, email, resp) db.session.add(account) db.session.commit() db.session.refresh(account) assert len(account.auth_credentials) == 1 auth_creds = account.auth_credentials[0] assert auth_creds.client_id == client_id_1 assert auth_creds.client_secret == client_secret_1 assert auth_creds.scopes == scopes_1_list assert auth_creds.refresh_token == token_1 # Auth me twice... token_2 = 'second_token_!' client_id_2 = 'second client id' client_secret_2 = 'second client secret' scopes_2 = 'scope scop sco sc s' scopes_2_list = scopes_2.split(' ') second_auth_args = { 'refresh_token': token_2, 'scope': scopes_2, 'client_id': client_id_2, 'client_secret': client_secret_2 } resp.update(second_auth_args) account = g.get_account(SHARD_ID, email, resp) db.session.merge(account) db.session.commit() assert len(account.auth_credentials) == 2 auth_creds = next((creds for creds in account.auth_credentials if creds.refresh_token == token_2), False) assert auth_creds assert auth_creds.client_id == client_id_2 assert auth_creds.client_secret == client_secret_2 assert auth_creds.scopes == scopes_2_list # Don't add duplicate row in GmailAuthCredentials for the same # client_id/client_secret pair. resp.update(first_auth_args) resp['refresh_token'] = 'a new refresh token' account = g.get_account(SHARD_ID, email, resp) db.session.merge(account) db.session.commit() assert len(account.auth_credentials) == 2 # Should still work okay if we don't get a refresh token back del resp['refresh_token'] account = g.get_account(SHARD_ID, email, resp) db.session.merge(account) db.session.commit() assert len(account.auth_credentials) == 2
def test_create_account(db): # setup email = '*****@*****.**' resp = { 'access_token': '', 'expires_in': 3600, 'email': email, 'family_name': '', 'given_name': '', 'name': '', 'gender': '', 'id': 0, 'user_id': '', 'id_token': '', 'link': 'http://example.com', 'locale': '', 'picture': '', 'hd': '' } g = GmailAuthHandler('gmail') g.verify_config = lambda x: True # Auth me once... token_1 = 'the_first_token' client_id_1 = 'first client id' client_secret_1 = 'first client secret' scopes_1 = 'scope scop sco sc s' first_auth_args = { 'refresh_token': token_1, 'scope': scopes_1, 'client_id': client_id_1, 'client_secret': client_secret_1 } resp.update(first_auth_args) account = g.create_account(db.session, email, resp) db.session.add(account) db.session.commit() assert len(account.auth_credentials) == 1 auth_creds = account.auth_credentials[0] assert auth_creds.client_id == client_id_1 assert auth_creds.client_secret == client_secret_1 assert auth_creds.scopes == scopes_1 assert auth_creds.refresh_token == token_1 # Auth me twice... token_2 = 'second_token_!!' client_id_2 = 'second client id' client_secret_2 = 'secodn client secret' scopes_2 = 'scope scop sco sc s' second_auth_args = { 'refresh_token': token_2, 'scope': scopes_2, 'client_id': client_id_2, 'client_secret': client_secret_2 } resp.update(second_auth_args) account = g.create_account(db.session, email, resp) db.session.add(account) db.session.commit() assert len(account.auth_credentials) == 2 auth_creds = next((creds for creds in account.auth_credentials if creds.refresh_token == token_2), False) assert auth_creds assert auth_creds.client_id == client_id_2 assert auth_creds.client_secret == client_secret_2 assert auth_creds.scopes == scopes_2 # Don't add duplicate row in GmailAuthCredentials if we get same # refresh_token back resp.update(first_auth_args) account = g.create_account(db.session, email, resp) db.session.add(account) db.session.commit() assert len(account.auth_credentials) == 2