Exemplo n.º 1
0
class AppContext(SurrogatePK, Model):
    """A context for an APP"""

    __tablename__ = 'app_contexts'
    name = Column(db.String(80), unique=True, nullable=False)
    _context_credentials = Column(db.Text, nullable=False)
    application_id = reference_col('applications', nullable=True)
    application = relationship('Application', backref='app_contexts')
    created_on = Column(db.DateTime, default=dt.datetime.now())
    last_update = Column(db.DateTime, onupdate=dt.datetime.now())
    is_active = Column(db.Boolean, default=True)

    def __init__(self, **kwargs):
        """Create instance."""
        db.Model.__init__(self, **kwargs)

    @property
    def context_credentials(self):
        return json.loads(s.loads(self._context_credentials))

    @context_credentials.setter
    def context_credentials(self, value):
        self._context_credentials = s.dumps(json.dumps(json.loads(value)))

    @property
    def serialized(self):
        return serialize_object(self,
                                self.__class__,
                                context_credentials=self.context_credentials)

    def __repr__(self):
        """Represent instance as a unique string."""
        return '<AppContext({name})>'.format(name=self.name)
Exemplo n.º 2
0
class Application(SurrogatePK, Model):
    """A category for scopes."""

    __tablename__ = 'applications'
    name = Column(db.String(80), unique=True, nullable=False)
    _white_listed_ips = Column(db.Text, default="[]")
    created_on = Column(db.DateTime, default=dt.datetime.now())
    last_update = Column(db.DateTime, onupdate=dt.datetime.now())

    def __init__(self, **kwargs):
        """Create instance."""
        db.Model.__init__(self, **kwargs)

    @property
    def white_listed_ips(self):
        return json.loads(self._white_listed_ips)

    @white_listed_ips.setter
    def white_listed_ips(self, value):
        self._white_listed_ips = json.dumps(json.loads(value))    

    @property
    def serialized(self):
        print(self.white_listed_ips, type(self.white_listed_ips))
        return serialize_object(self, self.__class__, white_listed_ips=self.white_listed_ips)

    def __repr__(self):
        """Represent instance as a unique string."""
        return '<Application({name})>'.format(name=self.name)
Exemplo n.º 3
0
class InvalidToken(SurrogatePK, Model):
    """A category for scopes."""

    __tablename__ = 'invalid_tokens'
    token = Column(db.String(255), unique=True, nullable=False)

    def __init__(self, **kwargs):
        """Create instance."""
        db.Model.__init__(self, **kwargs)

    def __repr__(self):
        """Represent instance as a unique string."""
        return '<InvalidToken({name})>'.format(name=self.token)
Exemplo n.º 4
0
class Category(SurrogatePK, Model):
    """A category for scopes."""

    __tablename__ = 'categories'
    name = Column(db.String(80), unique=True, nullable=False)
    created_on = Column(db.DateTime, default=dt.datetime.now())
    last_update = Column(db.DateTime, onupdate=dt.datetime.now())

    def __init__(self, **kwargs):
        """Create instance."""
        db.Model.__init__(self, **kwargs)

    @property
    def serialized(self):
        return serialize_object(self, self.__class__)

    def __repr__(self):
        """Represent instance as a unique string."""
        return '<Category({name})>'.format(name=self.name)
Exemplo n.º 5
0
class UserScopeMapping(SurrogatePK, Model):
    """A user_scope_mapping for a user."""

    __tablename__ = 'user_scope_mappings'
    role = Column(db.String(80), nullable=False)
    scope_id = reference_col('scopes', nullable=False)
    scope = relationship('Scope', backref='user_scope_mappings')
    created_on = Column(db.DateTime, default=dt.datetime.now())
    last_update = Column(db.DateTime, onupdate=dt.datetime.now())

    def __init__(self, **kwargs):
        """Create instance."""
        db.Model.__init__(self, **kwargs)

    @property
    def serialized(self):
        return serialize_object(self, self.__class__)

    def __repr__(self):
        """Represent instance as a unique string."""
        return '<UserScopeMapping({role} on {scope})>'.format(role=self.role, scope=self.scope)
Exemplo n.º 6
0
class Scope(SurrogatePK, Model):
    """A scope which is hierarchical model."""

    __tablename__ = 'scopes'
    id = Column(db.Integer, primary_key=True)
    name = Column(db.String(80), nullable=False)
    parent_scope_id = Column(db.Integer, db.ForeignKey('scopes.id'))
    created_on = Column(db.DateTime, default=dt.datetime.now())
    last_update = Column(db.DateTime, onupdate=dt.datetime.now())
    parent = relationship('Scope',
                          lazy="joined",
                          join_depth=8,
                          backref='children',
                          remote_side=id)
    category_id = reference_col('categories', nullable=True)
    category = relationship('Category', backref='scopes')

    def __init__(self, **kwargs):
        """Create instance."""
        db.Model.__init__(self, **kwargs)

    @property
    def serialized(self):
        return serialize_object(self, self.__class__)

    def tree_serialized(self, user):
        return serialize_object(self, self.__class__,
                                children=[
                                    child.tree_serialized(user) \
                                    if user.can.view.scope_id(self.id) \
                                    else {'id': self.id, 'error': 'not authorized'} \
                                    for child in self.children])

    def __repr__(self):
        """Represent instance as a unique string."""
        return '<Scope({name}:{id})>'.format(name=self.name, id=self.id)
Exemplo n.º 7
0
class User(UserMixin, SurrogatePK, Model):
    """A user of the app."""

    __tablename__ = 'users'
    username = Column(db.String(80), unique=True, nullable=False)
    first_name = Column(db.String(80))
    last_name = Column(db.String(80))
    mobile_number = Column(db.String(80))
    created_on = Column(db.DateTime, default=dt.datetime.now())
    last_update = Column(db.DateTime, onupdate=dt.datetime.now())
    is_deleted = Column(db.Boolean, default=False)
    email_verified = Column(db.Boolean, default=False)
    email = Column(db.String(80), unique=True, nullable=False)
    #: The hashed password
    password = Column(db.Binary(128), nullable=True)
    user_scope_mappings = relationship("UserScopeMapping",
                         secondary=rel_users_user_scope_mappings,
                         backref="users")
    app_user = False


    def __init__(self, password=None, app_user=False, **kwargs):
        """Create instance."""
        db.Model.__init__(self, **kwargs)
        if password:
            self.set_password(password)
        else:
            self.password = None

        """If a new user object is created as an app_user like `user = User(app_user=True)`
        then this user will automatically have root admin permissions. This user cannot
        be saved to the database and only exists for the length of a request. It is a 'Ghost'
        user designed to give an application the same kind of permission calls as a regular
        user without needing to store it in the database."""
        self.app_user = app_user


    def traverse_up_tree_from_node(self, starting_node):
        """Starting at the `starting_node` we walk up the node (scope) tree
        by calling `starting_node.parent` to go up one level checking for
        the correct permission at each level. If nothing is found by the time
        we reach the root node (no parent) then we return False as the permission
        doesn't exist."""
        for user_scope_mapping in starting_node.user_scope_mappings:
            for user in user_scope_mapping.users:
                if user == self and user_scope_mapping.role in self.permission_types:
                    print(user, 'has permission on', starting_node)
                    return True
        if starting_node.parent:
            return self.traverse_up_tree_from_node(starting_node.parent)
        else:
            return False

    @property
    def is_root_admin(self):
        root_scope = Scope.query.filter_by(parent_scope_id=None).first()
        for user_scope_mapping in root_scope.user_scope_mappings:
            for user in user_scope_mapping.users:
                if user == self:
                    return True
        return self.app_user or False

    @property
    def can(self):
        self.permission_types = []
        return self

    @property
    def view(self):
        self.permission_types = ['READ', 'READ-WRITE', 'ADMIN']
        return self

    @property
    def modify(self):
        self.permission_types = ['READ-WRITE', 'ADMIN']
        return self

    @property
    def delete(self):
        self.permission_types = ['ADMIN']
        return self

    def user_id(self, _user_id):
        """If a user has no user_scope_mappings for any scope they are 'free-floating' users
        and only super admins and the user themself should be able to edit them or view 
        them. If a user has at least one user_scope_mapping then we can look at all of their 
        user_scope_mappings and check to see that we have permission in at least one of those 
        user_scope_mappings to do the requested action."""

        # Must be admin to do anything with users
        self.permission_types = ['ADMIN']

        user = self.query.filter_by(id=_user_id).first()

        if not self.is_root_admin:
            if self == user:
                return True
            else:
                return False


        # Free floating user
        if not user.user_scope_mappings:
            # Users can always have access to themselves
            if user == self:
                return True
            # ADMIN users on the root node can also have access 
            for user_scope_mapping in self.user_scope_mappings:
                # user has access to the root node with the correct permission
                if not user_scope_mapping.scope.parent and user_scope_mapping.role in \
                                                                            self.permission_types:
                    return True
                else:
                    return False

        user_scope_mappings_with_permission = []
        for user_scope_mapping in user.user_scope_mappings:
            if self.traverse_up_tree_from_node(user_scope_mapping.scope):
                user_scope_mappings_with_permission.append(user_scope_mapping.scope)
        return self.app_user or (True if user_scope_mappings_with_permission else False)

    def user_scope_mapping_id(self, _user_scope_mapping_id):
        """Start with the user_scope_mapping to be modified, and use the attached scope as
        the starting scope for determining permission to modify the user_scope_mapping."""

        # Must be admin to do anything with user_scope_mappings
        self.permission_types = ['ADMIN']

        user_scope_mapping = UserScopeMapping.query.filter_by(id=_user_scope_mapping_id).first()
        if not user_scope_mapping:
            return False

        if self.id in [user.id for user in user_scope_mapping.users]:
            return True

        return self.app_user or self.traverse_up_tree_from_node(user_scope_mapping.scope)

    def scope_id(self, _scope_id):
        """Start with the scope to be read/modified/deleted and go up the tree
        looking for permissions on the target scope or any parent. The _scope_id
        passed in here is the parent scope of whatever scope is being modified."""

        # Must be admin to do anything with scopes
        self.permission_types = ['ADMIN']

        scope = Scope.query.filter_by(id=_scope_id).first()
        # Scope must always have a parent unless it is the root scope
        if not scope:
            return False
        return self.app_user or self.traverse_up_tree_from_node(scope)

    def category_id(self, _category_id):
        """The approach here is to find every scope that is being used by the
        category in question. The user would have to have the right permission
        on every scope attached to the category in orer to modify/read/delete 
        the category."""
        category = Category.query.filter_by(id=_category_id).first()
        scopes_with_permission = []
        if not category.scopes:
            return self.app_user or self.is_root_admin
        for scope in category.scopes:
            if self.traverse_up_tree_from_node(scope):
                scopes_with_permission.append(scope)
        return self.app_user or scopes_with_permission


    def set_password(self, password):
        """Set password."""
        self.password = bcrypt.generate_password_hash(password)

    def check_password(self, value):
        """Check password."""
        return bcrypt.check_password_hash(self.password, value)

    def generate_auth_token(self):
        s = Serializer(Config.SECRET_KEY)
        return s.dumps(self.email, salt='recover-key')

    @staticmethod
    def verify_auth_token(token):
        s = Serializer(Config.SECRET_KEY)
        try:
            email = s.loads(token, salt="recover-key", max_age=3600)
        except SignatureExpired:
            return None # valid token, but expired
        except BadSignature:
            return None # invalid token
        return User.query.filter_by(email=email).first()

    @property
    def full_name(self):
        """Full user name."""
        return '{0} {1}'.format(self.first_name, self.last_name)

    @property
    def serialized(self):
        return serialize_object(self, self.__class__,
                                is_root_admin=self.is_root_admin)

    def __repr__(self):
        """Represent instance as a unique string."""
        return '<User({username!r})>'.format(username=self.username)