Giter VIP home page Giter VIP logo

flask-principal's Introduction

Flask-Principal

image

Identity management for Flask applications. This extension was originally written by Ali Afshar. Thanks to him for his great work. This is the new and official repository for this project.

Documentation: http://packages.python.org/Flask-Principal/

flask-principal's People

Contributors

aliafshar avatar auha avatar buztard avatar coyotevz avatar jyelloz avatar masom avatar mattupstate avatar mickey06 avatar s0undt3ch avatar sorki avatar techniq avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

flask-principal's Issues

Declare permission that never allows anything

I'd like to declare a permission whose .can() method always returns False (background: it's returned from a factory function and the meaning is that some objects may not be edited/removed by anyone).

There are a couple of ways to do this:

  • subclass Permission and override the method;
  • crate a Need that is shared by all identites and return a permission that excludes it.

I prefer the need-based method because it retains the ability to perform permission algebra with the new permission. So then, how to add this need to the AnonymousIdentity? How about we define a Principal.get_default_identity method that subclasses can override?

Add documentation for using with flask-jwt

Hi Matt,

since you are already the original author of flask-jwt and since flask-principal has the option to go without session, could you perhaps add a little example that goes beside the more classical flask-login example which shows how to properly use this with flask-jwt?

If you lack the time to do so properly, could you roughly describe me the process in this report for now?

Permission decorators

Add a view method decorator that can accept one or more permission class objects to control access. These permission classes will have a relationship with a specific HTTP resource.

use mongoengine

principal is very good.
i do`t know how to use principal use mongodb.
can you update you doc,give a demo about mongoengine and principal?
thk.

Consider adding ability to lazily load data for permission objects

Considering the hypothetical example in the current documentation for granular resource protection, what if a user has hundreds, even thousands of posts or some other sort of attribute. Perhaps adding a way to lazily load some sort of condition in the permission object can avoid loading all that data and inflating the identity on every request.

Mongo based sessions do not allow dots as key names

Hi,

I have been using MongoEngineSessionInterface from flask-mongoengine library for server side sessions in a flask app. The flask principal extension seems to depend on storing identity.id and identity.auth_type in session and retrieving them later to store the identity of user in session. However, in a mongo based session this fails since mongo does not allow dots as key names.

I tried use_sessions=False setting but it was not very clear how to load the identity of the logged in user in that case.

I could rename them but would rather not create a custom fork of the library. Would you be willing to take in a pull request to change identity.id and identity.auth_type renamed to remove dots?

why is there noway to create an 'perm = a or b'

sorry for creating a ticket for this, but idk where else to put this.

I've ran into this multiple times now and was wondering if there's a specific reason for this feature not being available which I'm overseeing, otherwise I could work on adding it maybe ;-)

Often I have stuff that is accessible with 2 different permissions (for example 2 different roles), but the or doesn't do an 'or', it instead does a 'difference' ... which is fine I guess (you build it in for a reason) but it would be nice if we could still have another way of combining 2 permissions as an 'or' !?

Is this library maintained?

I've noticed it is not updated since 2014
For instance, my code is affected by this bug: #30 but I've checked the code at it is not merged

So the question is the title: is this library maintained? and if not, what alternative did I have?

Thanks!

Small mistake in test_principal.py

This

    def test_and_permissions_view(self):
            self.assertRaises(PermissionDenied, self.client.open, '/g')

should be

    def test_and_permissions_view(self):
            self.assertRaises(PermissionDenied, self.client.open, '/h')

As it stands /h is never tested.

Fixed per-role permissions

Hi, this is more of a question than a bug (potentially it may become RFE):
I have an application where I want to have:

  • users
  • possibly multiple roles for each user
  • "fixed" set of permissions (possibly growing in time) that I can assign/unassign to/from certain roles

Made-up example:

  • There is a developer role and a manager role
  • All developers have "change-code" permission and "create-new-repository" permission
  • All managers have "manipulate-team-members" permission
  • After a while, I decide that developers are creating too many repos, so I want to move the permission from developers to managers - just by changing permissions that are associated to these roles in DB, I don't want to touch application code

AFAICS this is not supported approach at this time, cause it would need adding a permission model with M:N relation to role model. I think this should be pretty easy to actually add to my application while still using flask-principal, but I wanted to ask if there's a preferred/recommended way of doing this or if you have some plans in this direction (or if I'm just missing something and doing everything wrong ;)). Thanks!

Possible security hole in AnonymousIdentity implementaion

AnonymousIdentity instance uses 'anon' as a name that is equal to Identity instance with name 'anon'. If we have a user with that name then we have a security problem, because any anonymous (logged out) user gets 'anon' permissions.

Lazy load Identity object

Currently, the identity object is loaded on each request using Principle._on_before_request and Principle.identity_loaders.

The problem is that the identity is not already required for each request and each access to the identity implies an access to the session data.

Ideally, the identity would only be loaded when needed.

Is this a planned feature? Something that I could help out with?

Raise TypeError if Flask.static_folder is None

When I use static_folder=None argument in Flask application, principal code raises TypeError.

app = Flask(app_name, static_folder=None)
principals = Principal(skip_static=True)

The use of static_folder=None is because a blueprint handle static files.

Issue with classes in sets

Hello,

I love this library but I have ran into an issue I thought I could pick you brain on.

In the example https://pythonhosted.org/Flask-Principal/#granular-resource-protection i implemented almost identically to how it states there but I have an issue. When calling if permission.can(): I get False back from the following line... https://github.com/mattupstate/flask-principal/blob/master/flask_principal.py#L333-L334

In order to make this work I had to implement the following.

class EditBlogPostPermission(Permission):
    def __init__(self, post_id):
        need = EditBlogPostNeed(unicode(post_id))
        super(EditBlogPostPermission, self).__init__(need)
        self.need = need

    def __eq__(self, other):
        """Override the default Equals behavior."""
        if isinstance(other, self.need.__class__):
            return self.need == other
        return False

    def __ne__(self, other):
        """Override the default Unequal behavior."""
        return self.need != other

    def __hash__(self):
        """Override the default Hash behavior."""
        return hash(self.need)

Do you have any suggestions on how to better implement this? I dont see any tests in your test file for this use case.

I also considered the following instead of the __eq__, __ne__, __hash__

    def allows(self, identity):
        for prov in identity.provides:
            if isinstance(self, type(prov)) and self.needs == prov.needs:
                return True
         
        return False

deque mutated during iteration

Hi,

we use flask-principal in a small application with blueprints. Authentication has its own blueprint. Apparently at random we have errors like the one below. Did you know that behavior? Here I read that I may get around that problem by creating a list and 'freeze' the deque. Should I give it a try?

  File
"/opt/venvs/geocalc-login/lib/python3.4/site-packages/flask_principal.py"
, line 479, in _on_before_request
    self.set_identity(identity)
  File
"/opt/venvs/geocalc-login/lib/python3.4/site-packages/flask_principal.py"
, line 419, in set_identity
    for saver in self.identity_savers:
RuntimeError: deque mutated during iteration

Bug in flask-login example

The flask-login example in the documentation is extremely helpful (common use case, I would think) but it has a significant bug in it!

The sample code shows Flask-Principal being registered before Flask-Login, but if you do this, then flask principal will send the identity_loaded message before Flask-Login has had a chance to load the current_user proxy. Therefore, the identity_loaded handler will always return the anonymous user!

I realize it's not meant to be a complete example, but it tripped me up as well as at least one person on Stack Overflow: http://stackoverflow.com/questions/18190067/flask-login-and-principal-current-user-is-anonymous-even-though-im-logged-in/18935921

It can be fixed simply by reversing the order of Principal(app) and login_manager = LoginManager(app).

skip_static only whitelists the app's static endpoint, not those from blueprints

I've seen a lot of issues cropping up related to the use of flask_principal or flask_security with blueprints where, even when skip_static is set, static files provided by blueprints will block and eventually thow a 500 with an error message along these lines:

sqlalchemy.exc.TimeoutError

sqlalchemy.exc.TimeoutError: QueuePool limit of size 5 overflow 10 reached, connection timed out, timeout 30 (Background on this error at: http://sqlalche.me/e/3o7r)

While letting Flask serving static files is arguably not a good idea in production (though still very much useful in developpement), separating static files per blueprint has been a core feature of Flask for many years, one which I see no reason to ignore in an extension as widespread as this. The current workaround of putting all assets from blueprints in the root static folder goes against the idea of keeping blueprints as independent modules (blueprints can't have their internal static folder point outside of their URL prefix, so while it's easy to have the static directory point to /myapp/myblueprint/static, it's impossible to set it to /myapp/static/myblueprint) and isn't possible for extensions that wrap blueprints like flask-admin, since you can't rewrite their url_for routes.

Flask has some mechanisms that would allow for something like Flask-Principal to identify static folders from blueprints (though I'm not seeing a callback to automatically do that on blueprint registration).

Intersection of required and provided needs is not sufficient

The test for access in the allows method of the Permission class using the intersection of the required and provided needs in insufficient. The documentation says the needs in a permission "Represents needs, any of which must be present to access a resource". But with the intersection, if you have at least one need in common, the intersection will be not empty and the test succeeds.

I think we should use issubset instead:

def allows(self, identity):
        """Whether the identity can access this permission.

        :param identity: The identity
        """
        if not self.needs.issubset(identity.provides):
            return False

        if self.excludes and self.excludes.intersection(identity.provides):
            return False

        return True

Struggling with using `http_exception=`

I'm starting to use Flask-Principal for adding granular resource protection to a REST API written using Flask-RESTful/Flask-RestPlus. For almost all of my permission checks I just want to abort with a 403 error when presented with insufficient permissions so I'm trying to use the decorators like so:

admin_permission = Permission(RoleNeed('admin'))

@app.route('/foo')
class Foo(Resource):
    @login_required
    @admin_permission.require(http_exception=403)
    def get(self):
        pass

However if I trigger a permission denied error, I end up getting:

Traceback (most recent call last):
  File ".../venv/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File ".../venv/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File ".../venv/lib/python2.7/site-packages/flask_restful/__init__.py", line 270, in error_router
    return original_handler(e)
  File ".../venv/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File ".../venv/lib/python2.7/site-packages/flask_restful/__init__.py", line 267, in error_router
    return self.handle_error(e)
  File ".../venv/lib/python2.7/site-packages/flask_restplus/api.py", line 379, in handle_error
    return super(Api, self).handle_error(e)
  File ".../venv/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File ".../venv/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File ".../venv/lib/python2.7/site-packages/flask_restful/__init__.py", line 270, in error_router
    return original_handler(e)
  File ".../venv/lib/python2.7/site-packages/flask/app.py", line 1363, in handle_user_exception
    assert exc_value is e
AssertionError

If I don't use http_exception= then I get PermissionDenied exceptions with a 500 error code which aren't terribly useful. The only way I can seem to get things working is with:

admin_permission = Permission(RoleNeed('admin'))

@app.route('/foo')
class Foo(Resource):
    @login_required
    def get(self):
        if admin_permission.can():
            pass
        else:
            abort(403)

I'm concerned I'm going to end up writing the same block of code everywhere so I'd like to make use of http_exception= if possible. Is it possibly because I'm using Flask-RESTful/Flask-RestPlus which tries to JSON-ify responses perhaps?

Flask 0.10.1, app_context and "_AppCtxGlobals object has no 'identity'"

I've got an issue that I don't quite know how to articulate but it's due to updates in Flask from 0.9 -> 0.10. I'm using Flask-Principal==0.4.0, Flask-Login==0.2.7.

I've got a permission-decorated function that's somethink like the below:

@admin_role.require(http_exception=401)
def do_stuff():
    return jsonify(code=200)

content_editor_role is defined as:

admin_role = Permission(RoleNeed('admin'))

Something changed between between flask==0.9 and flask==0.10.1 which is causing the below exception stack to be thrown on this decorated (permission-restricted) function:

  File "/Users/sundar/.virtualenvs/mmweb/lib/python2.6/site-packages/flask_principal.py", line 198, in _decorated
    with self:
  File "/Users/sundar/.virtualenvs/mmweb/lib/python2.6/site-packages/flask_principal.py", line 205, in __enter__
    if not self.can():
  File "/Users/sundar/.virtualenvs/mmweb/lib/python2.6/site-packages/flask_principal.py", line 193, in can
    return self.identity.can(self.permission)
  File "/Users/sundar/.virtualenvs/mmweb/lib/python2.6/site-packages/flask_principal.py", line 188, in identity
    return g.identity
  File "/Users/sundar/.virtualenvs/mmweb/lib/python2.6/site-packages/werkzeug/local.py", line 338, in __getattr__
    return getattr(self._get_current_object(), name)
AttributeError: '_AppCtxGlobals' object has no attribute 'identity'

Note that this happens ONLY when I run this from a flask-script through an app_context():

def run_script_task():
    with app.app_context():
        from myapp.views.api import cleanup
        cleanup.do_stuff()

And this basically is telling me that something is weird when I use the app_context to "fake" a user's identity.

I'm posting this here in case anyone knows what this might be from, since I'm at a bit of a loss. I'm going to start looking at the source to see if I can trace anything, but would appreciate any suggestions as well.

Thanks much!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.