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/
Identity management for Flask applications
License: MIT License
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/
Should read Flask-principal instead of Flask-IdentityContext
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:
Permission
and override the method;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?
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?
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.
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.
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.
To help packaging, especially legal review, it would be nice to have the LICENSE file included in pypi distribution.
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?
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' !?
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!
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.
For tools like caniusepython3.com it would be neat if you'd add classifiers to your python package so we can check if there is python 3 support.
Hi, this is more of a question than a bug (potentially it may become RFE):
I have an application where I want to have:
Made-up example:
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!
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.
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?
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.
In the "Authentication providers" example identity.name should be replaced by identity.id
In the "User Information providers" example the hasattr(current_user, 'id') test doesn't exclude anonymous users anymore. Because all users have the id attribute now.
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
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
just curious
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)
.
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).
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
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?
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!
Instead of writing a full login form example, it would be much simpler and more general to integrate the two using Flask-Login's signals. It has signals for users logging in and logging out.
One would think that setting principals.use_session to True would enable session use at any time.
But, since it is only checked during init_app, this is not the case.
I am getting the following error:
AttributeError: 'NoneType' object has no attribute 'static_path'
Howdy there,
It'd be nice to include LICENSE in your sdist (might need to set it in your MANIFEST.in)
Thanks for your work!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.