from abc import ABCMeta, abstractmethod from six import add_metaclass from enum import Enum from data import model from auth.credential_consts import ( ACCESS_TOKEN_USERNAME, OAUTH_TOKEN_USERNAME, APP_SPECIFIC_TOKEN_USERNAME, ) class ContextEntityKind(Enum): """ Defines the various kinds of entities in an auth context. Note that the string values of these fields *must* match the names of the fields in the ValidatedAuthContext class, as we fill them in directly based on the string names here. """ anonymous = "anonymous" user = "user" robot = "robot" token = "token" oauthtoken = "oauthtoken" appspecifictoken = "appspecifictoken" signed_data = "signed_data" @add_metaclass(ABCMeta) class ContextEntityHandler(object): """ Interface that represents handling specific kinds of entities under an auth context. """ @abstractmethod def credential_username(self, entity_reference): """ Returns the username to create credentials for this entity, if any. """ pass @abstractmethod def get_serialized_entity_reference(self, entity_reference): """ Returns the entity reference for this kind of auth context, serialized into a form that can be placed into a JSON object and put into a JWT. This is typically a DB UUID or another unique identifier for the object in the DB. """ pass @abstractmethod def deserialize_entity_reference(self, serialized_entity_reference): """ Returns the deserialized reference to the entity in the database, or None if none. """ pass @abstractmethod def description(self, entity_reference): """ Returns a human-readable and *public* description of the current entity. """ pass @abstractmethod def analytics_id_and_public_metadata(self, entity_reference): """ Returns the analyitics ID and a dict of public metadata for the current entity. """ pass class AnonymousEntityHandler(ContextEntityHandler): def credential_username(self, entity_reference): return None def get_serialized_entity_reference(self, entity_reference): return None def deserialize_entity_reference(self, serialized_entity_reference): return None def description(self, entity_reference): return "anonymous" def analytics_id_and_public_metadata(self, entity_reference): return "anonymous", {} class UserEntityHandler(ContextEntityHandler): def credential_username(self, entity_reference): return entity_reference.username def get_serialized_entity_reference(self, entity_reference): return entity_reference.uuid def deserialize_entity_reference(self, serialized_entity_reference): return model.user.get_user_by_uuid(serialized_entity_reference) def description(self, entity_reference): return "user %s" % entity_reference.username def analytics_id_and_public_metadata(self, entity_reference): return entity_reference.username, {"username": entity_reference.username,} class RobotEntityHandler(ContextEntityHandler): def credential_username(self, entity_reference): return entity_reference.username def get_serialized_entity_reference(self, entity_reference): return entity_reference.username def deserialize_entity_reference(self, serialized_entity_reference): return model.user.lookup_robot(serialized_entity_reference) def description(self, entity_reference): return "robot %s" % entity_reference.username def analytics_id_and_public_metadata(self, entity_reference): return entity_reference.username, {"username": entity_reference.username, "is_robot": True,} class TokenEntityHandler(ContextEntityHandler): def credential_username(self, entity_reference): return ACCESS_TOKEN_USERNAME def get_serialized_entity_reference(self, entity_reference): return entity_reference.get_code() def deserialize_entity_reference(self, serialized_entity_reference): return model.token.load_token_data(serialized_entity_reference) def description(self, entity_reference): return "token %s" % entity_reference.friendly_name def analytics_id_and_public_metadata(self, entity_reference): return "token:%s" % entity_reference.id, {"token": entity_reference.friendly_name,} class OAuthTokenEntityHandler(ContextEntityHandler): def credential_username(self, entity_reference): return OAUTH_TOKEN_USERNAME def get_serialized_entity_reference(self, entity_reference): return entity_reference.uuid def deserialize_entity_reference(self, serialized_entity_reference): return model.oauth.lookup_access_token_by_uuid(serialized_entity_reference) def description(self, entity_reference): return "oauthtoken for user %s" % entity_reference.authorized_user.username def analytics_id_and_public_metadata(self, entity_reference): return ( "oauthtoken:%s" % entity_reference.id, { "oauth_token_id": entity_reference.id, "oauth_token_application_id": entity_reference.application.client_id, "oauth_token_application": entity_reference.application.name, "username": entity_reference.authorized_user.username, }, ) class AppSpecificTokenEntityHandler(ContextEntityHandler): def credential_username(self, entity_reference): return APP_SPECIFIC_TOKEN_USERNAME def get_serialized_entity_reference(self, entity_reference): return entity_reference.uuid def deserialize_entity_reference(self, serialized_entity_reference): return model.appspecifictoken.get_token_by_uuid(serialized_entity_reference) def description(self, entity_reference): tpl = (entity_reference.title, entity_reference.user.username) return "app specific token %s for user %s" % tpl def analytics_id_and_public_metadata(self, entity_reference): return ( "appspecifictoken:%s" % entity_reference.id, { "app_specific_token": entity_reference.uuid, "app_specific_token_title": entity_reference.title, "username": entity_reference.user.username, }, ) class SignedDataEntityHandler(ContextEntityHandler): def credential_username(self, entity_reference): return None def get_serialized_entity_reference(self, entity_reference): raise NotImplementedError def deserialize_entity_reference(self, serialized_entity_reference): raise NotImplementedError def description(self, entity_reference): return "signed" def analytics_id_and_public_metadata(self, entity_reference): return "signed", {"signed": entity_reference} CONTEXT_ENTITY_HANDLERS = { ContextEntityKind.anonymous: AnonymousEntityHandler, ContextEntityKind.user: UserEntityHandler, ContextEntityKind.robot: RobotEntityHandler, ContextEntityKind.token: TokenEntityHandler, ContextEntityKind.oauthtoken: OAuthTokenEntityHandler, ContextEntityKind.appspecifictoken: AppSpecificTokenEntityHandler, ContextEntityKind.signed_data: SignedDataEntityHandler, }