"""Logic for identities.""" import flask import neo4j from flask import g from owsresponse import response from pythonfeatures import pythonfeatures from pythonfeatures.constants import split as split_constants from permissions import types from permissions.connectors import neo4j as neo4j_connector from permissions.constants import constants from permissions.exceptions.incomplete_result_error import IncompleteResultError from permissions.models import ( auth0 as auth0_model, identity as identity_model, resource, ) def get_identity_by_id(identity_id: str) -> response.Response: """Get identity if it exists. Args: identity_id (str): Identity UUID. Return: response (obj) """ with neo4j_connector.db_session(access_mode=constants.NEO4j_READ_ACCESS) as session: try: identity = session.read_transaction(identity_model.get_identity_by_id, identity_id) return response.Response(identity) except IncompleteResultError as err: return response.create_not_found_response(err.message) def get_identity_by_email(email: str) -> types.Identity | None: """Get identity by email if it exists. Args: email(str): Email of user. Return: Identity | None """ with neo4j_connector.db_session(access_mode=constants.NEO4j_READ_ACCESS) as session: return identity_model.get_identity_by_email(session=session, email=email) def deactivate_identity(session: neo4j.Session, identity: types.Identity, admin_id: str): """Set an identity to inactive and deactivate in auth0.""" identity_model.update_identity_active_status( session=session, identity_id=identity.id, active='N', audit_user_id=admin_id, ) if identity.is_pending(): g.log.info( 'Pending user has no auth0 user yet; skipping auth0 deactivation', resources={'identity_id': identity.id}, ) return auth0_model.activate_deactivate_user(auth0_id=identity.auth0_user_id, active=False) def activate_user(admin_context: dict[str, str | int], identity_id: str) -> response.Response: """Activate a user and unblock the auth0 user too. Args: admin_context (dict): Admin's context data. identity_id (str): Users identity id. Return: Response: containing dict of identity. """ identity = get_identity_by_id(identity_id) if not identity: return identity if not identity.message.get('active') or identity.message.get('active') == 'Y': return response.Response(identity.message, status=202) g.log.info( 'Activating user', resources={ 'admin_identity_id': admin_context['identity_id'], 'identity_id': identity_id, 'email': identity.message.get('email'), }, ) return resource.activate_user( admin_id=admin_context['identity_id'], identity_id=identity_id, ) def reactivate_user_if_needed( admin: types.AdminIdentity, identity_with_auth0: types.IdentityWithAuth0, ) -> bool: """Check if user needs reactivation and reactivate them if so. Args: admin: The admin making the change. identity_with_auth0: The identity to potentially reactivate. Returns: True if reactivation occurred, False otherwise. """ reactivate_needed = identity_with_auth0.active != 'Y' if reactivate_needed: g.log.info( 'Reactivating user via adding a tenant', resources={'identity_id': identity_with_auth0.id}, ) result = activate_user( admin_context={ 'identity_id': admin.id, 'profile_id': admin.settings_profile.profile_id, }, identity_id=identity_with_auth0.id, ) if not result: g.log.error( 'Tried to reactivate user during update, but activation failed', resources={'identity_id': identity_with_auth0.id}, ) raise RuntimeError('Failed to reactivate user during update') return reactivate_needed def is_identity_super_admin( request_context: flask.ctx.RequestContext, identity_id: str, ) -> bool: """Check if an identity has access to all labels and is a 'super admin'.""" if not ( pythonfeatures.get_single_feature(constants.EDIT_SUPER_ADMINS, request_context).message == split_constants.FEATURE_ENABLED ): g.log.info('User is not in feature flag', resources={'identity_id': identity_id}) return False with neo4j_connector.db_session(access_mode=constants.NEO4j_READ_ACCESS) as session: has_vendor_star = resource.get_vendor_star_for_admin_by_identity_id( identity_id=identity_id, session=session ) if has_vendor_star: return True else: g.log.info('User does not have vendor * access', resources={'identity_id': identity_id}) return False