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, }