def test_get_valid_service_account_id_for_client(client_id, prefix): """ Test that even when client id starts with a number, we can get a valid name """ user_id = 54 result = get_valid_service_account_id_for_client(client_id, user_id, prefix=prefix) assert prefix in result assert str(user_id) in result assert len(result) > 6 assert len(result) <= 30
def create_service_account(client_id, user_id, username, proxy_group_id): """ Create a Google Service account for the current client and user. Args: g_cloud_manager (cirrus.GoogleCloudManager): instance of cloud manager to use Returns: fence.models.GoogleServiceAccount: New service account """ if proxy_group_id: if client_id: service_account_id = get_valid_service_account_id_for_client( client_id, user_id) else: service_account_id = get_valid_service_account_id_for_user( user_id, username) with GoogleCloudManager() as g_cloud: new_service_account = g_cloud.create_service_account_for_proxy_group( proxy_group_id, account_id=service_account_id) service_account = GoogleServiceAccount( google_unique_id=new_service_account["uniqueId"], client_id=client_id, user_id=user_id, email=new_service_account["email"], google_project_id=new_service_account["projectId"], ) current_session.add(service_account) current_session.commit() flask.current_app.logger.info( "Created service account {} for proxy group {}.".format( new_service_account["email"], proxy_group_id)) return service_account else: flask.abort( 404, "Could not find Google proxy group for current user in the " "given token.", )
def get_or_create_service_account(client_id, user_id, username, proxy_group_id): """ Create a Google Service account for the current client and user. This effectively handles conflicts in Google and will update our db accordingly based on the newest information from Google. Args: g_cloud_manager (cirrus.GoogleCloudManager): instance of cloud manager to use Returns: fence.models.GoogleServiceAccount: New service account """ if proxy_group_id: if client_id: service_account_id = get_valid_service_account_id_for_client( client_id, user_id, prefix=config["GOOGLE_SERVICE_ACCOUNT_PREFIX"]) else: service_account_id = get_valid_service_account_id_for_user( user_id, username, prefix=config["GOOGLE_SERVICE_ACCOUNT_PREFIX"]) with GoogleCloudManager() as g_cloud: new_service_account = g_cloud.create_service_account_for_proxy_group( proxy_group_id, account_id=service_account_id) return _update_service_account_db_entry(client_id, user_id, proxy_group_id, new_service_account) else: flask.abort( 404, "Could not find Google proxy group for current user in the given token.", )
def _update_service_account_db_entry( client_id, user_id, proxy_group_id, new_service_account ): """ Now that SA exists in Google so lets check our db and update/add as necessary """ # if we're now using a prefix for SAs, cleanup the db if config["GOOGLE_SERVICE_ACCOUNT_PREFIX"]: # - if using the old naming convention without a prefix, # remove that SA from the db b/c we'll be using the new one from now on # - construct old email using account id provided and # domain from new email to find the db entry old_service_account_id = get_valid_service_account_id_for_client( client_id, user_id ) old_sa_email = "@".join( (old_service_account_id, new_service_account["email"].split("@")[-1]) ) # clear out old SA and keys if there is one old_service_account_db_entry = ( current_session.query(GoogleServiceAccount) .filter(GoogleServiceAccount.email == old_sa_email) .first() ) if old_service_account_db_entry: logger.info( "Found Google Service Account using old naming convention without a prefix: " "{}. Removing from db. Keys should still have access in Google until " "cronjob removes them (e.g. fence-create google-manage-keys). NOTE: " "the SA will still exist in Google but fence will use new SA {} for " "new keys.".format(old_sa_email, new_service_account["email"]) ) old_service_account_keys_db_entries = ( current_session.query(GoogleServiceAccountKey) .filter( GoogleServiceAccountKey.service_account_id == old_service_account_db_entry.id ) .all() ) # remove the keys then the sa itself from db for old_key in old_service_account_keys_db_entries: current_session.delete(old_key) current_session.commit() current_session.delete(old_service_account_db_entry) service_account_db_entry = ( current_session.query(GoogleServiceAccount) .filter(GoogleServiceAccount.email == new_service_account["email"]) .first() ) if not service_account_db_entry: service_account_db_entry = GoogleServiceAccount( google_unique_id=new_service_account["uniqueId"], client_id=client_id, user_id=user_id, email=new_service_account["email"], google_project_id=new_service_account["projectId"], ) current_session.add(service_account_db_entry) else: service_account_db_entry.google_unique_id = new_service_account["uniqueId"] service_account_db_entry.email = new_service_account["email"] service_account_db_entry.google_project_id = (new_service_account["projectId"],) current_session.commit() logger.info( "Created service account {} for proxy group {}.".format( new_service_account["email"], proxy_group_id ) ) return service_account_db_entry
def get_service_account(client_id, user_id, username): """ Return the service account (from Fence db) for given client. Get the service account that is associated with the given client for this user. There will be a single service account per client. NOTE: The user themselves have a "primary" service account which you can retrieve by passing in `None` as the client_id. Returns: fence.models.GoogleServiceAccount: Client's service account """ service_accounts = ( current_session.query(GoogleServiceAccount) .filter_by(client_id=client_id, user_id=user_id) .all() ) if len(service_accounts) == 1: return service_accounts[0] # in rare cases there's a possible that 2 SA's exist for 1 user that haven't # been cleaned up yet. This happens when a users username is changed. To ensure # getting the newest SA, we need to check for the SA ID based off the current # username service_account = None # determine expected SA name based off username if client_id: service_account_id = get_valid_service_account_id_for_client( client_id, user_id, prefix=config["GOOGLE_SERVICE_ACCOUNT_PREFIX"] ) else: service_account_id = get_valid_service_account_id_for_user( user_id, username, prefix=config["GOOGLE_SERVICE_ACCOUNT_PREFIX"] ) for sa in service_accounts: if service_account_id in sa.email: service_account = sa else: logger.info( "Found Google Service Account using invalid/old name: " "{}. Removing from db. Keys should still have access in Google until " "cronjob removes them (e.g. fence-create google-manage-keys). NOTE: " "the SA will still exist in Google but fence will use new SA {} for " "new keys.".format(sa.email, service_account_id) ) old_service_account_keys_db_entries = ( current_session.query(GoogleServiceAccountKey) .filter(GoogleServiceAccountKey.service_account_id == sa.id) .all() ) # remove the keys then the sa itself from db for old_key in old_service_account_keys_db_entries: current_session.delete(old_key) # commit the deletion of keys first, then do SA deletion current_session.commit() current_session.delete(sa) current_session.commit() return service_account