A flask extension for managing permissions and scopes

Overview

Flask-Pundit Build Status

A simple flask extension to organize resource authorization and scoping. This extension is heavily inspired by the ruby Pundit library.

Installation

pip install flask-pundit

Initialization

You can initialize the extension in one of 2 ways -

  1. pundit = FlaskPundit(app) where app is the application object.
  2. pundit.init_app(app) after constructing the FlaskPundit object without an app object.

When initializing the extension, you can provide an optional policies_path parameter which tells Flask-Pundit where to find your policy classes. If no value is specified this defaults to policies.

What is this policies_path exactly?

Flask-Pundit expects you to have 1 policy per model class. To find the Policy for a particular model it needs to know where to look. That is the policies_path.

Policies

A policy class defines the 'rules' used to authorize a model. You can write your own policy class as follows:

class PostPolicy():
        def __init__(self, user, post):
                self.user = user
                self.post = post
        
        def get(self):
                return self.user == 'admin' and self.post.id == 1

The user object is the currently 'logged' in user and the post object is the model instance you want to authorize. The get method is an authorization 'action' handler that you might want to execute when a user is trying to read a post.

You could alternatively define your own BasePolicy class and extend it in a similar fashion or use the ApplicationPolicy class provided by the extension in which case the code would be:

from flask_pundit.application_policy import ApplicationPolicy

class PostPolicy(ApplicationPolicy):
        def get(self):
                return self.user == 'admin' and self.record.id == 1

Note that now we're using record inside the method. By inheriting from ApplicationPolicy all instance methods now use record to represent the model instance being authorized.

To authorize a post object inside a resource (or a blueprint or just a app.route decorated function) you would call self.pundit.authorize(post). This will cause flask-pundit to look for the PostPolicy class at policies/post. If you want a different root to be searched, you can specify the policies_path when initializing the extension.

This example shows how to use the authorize method in a single module app.

app = Flask('blog_series')
pundit = FlaskPundit(app)

@app.route('/blogs/<id>')
def read_blog_post(id):
        blog = Post.get_by_id(id)
        if pundit.authorize(post):
                return blog
        return ForbiddenError, 403

The authorize method takes 3 parameters:

  1. A record - This can be either an object or class and corresponds to a 'model' that you're doing the authorization on.

  2. An action - This corresponds to the policy method that you want to invoke for doing the authorization. If no value is provided it defaults to request.method.lowercase(). Thus in the previous snippet the get method of a BlogPolicy object would be invoked.

  3. A user - This is akin to the currently 'logged in' user. If no user object is provided, flask-pundit tries to pick either flask.g.user or flask.g.current_user, whichever is available.

Thus in the above set of examples, invoking authorize executes the get method in the PostPolicy class at policies/post with the record being the post object filtered by id.

Scopes

The authorize method acts more as a true/false guard. On the other hand the policy_scope method returns a 'scoped' version of a model. For example, if you have a page with all posts, you might want to let an admin see all of them but restrict the ones staff users see. This is where you'd want to use policy_scope instead of authorize.

To do so, you need to define a scope method in your policy.

from flask_pundit.application_policy import ApplicationPolicy

class PostPolicy(ApplicationPolicy):
        def get(self):
                return self.user == 'admin' and self.record.id == 1


        def scope(self):
                if self.user == 'admin':
                        return record.all()
                return record.filter_by(author='staff')
        

When you call the policy_scope(model) with a model class (it doesn't make sense to pass an object here), the scope method gets called.

from app import pundit

@app.route('/posts)
def index():
        all_posts = pundit.policy_scope(Post)
        return all_posts

The examples here show how to return all posts for an admin and only staff posts for a staff user.

The policy_scope method takes 2 arguments:

  1. A model - This is the class that is to be 'scoped'.

  2. A user object - This is just like the user object in the authorize case.

Verification

Flask-Pundit has 2 decorators you can use to verify authorize/ policy_scope has been called. They are verify_authorized and verify_policy_scoped.

In a single module app you would use verify_authorized as:

from flask_pundit import verify_authorized
from app import app, pundit

@app.route('/posts/<id>')
@verify_authorized
def read_blog_post(id):
        blog_post = Post.get_by_id(id)
        if pundit.authorize(blog_post):
                return blog_post
        return ForbiddenError, 403

If you remove the call to authorize the decorator will throw a RuntimeError as it expects a call but found none.

The verify_policy_scoped decorator would be used in the exact same way. Using these 2 would prove more useful if you're using something like Flask-Restful where you could specify these as method_decorators in your resource, if you wanted all the methods to be verified.

If you prefer not using decorators you could use pundit._verify_authorized and pundit._verify_policy_scoped directly inside your methods. Calling them directly will return True or False.

Custom Policy class

You could override the policy class lookup behaviour by adding a __policy_class__ property on your models. This should reference the class that you want to be used against this model. For example,

from policies.commenting import CommentingPolicy

class Comment:
        __policy_class__ = CommentingPolicy

Now when doing either authorize or policy_scope against an instance of Comment or the class itself, CommentingPolicy will be used.

License

Licensed under MIT license

Comments
  • Feature/add authorized or scoped decorator

    Feature/add authorized or scoped decorator

    This is just a convenience decorator for me. I’m blanket enforcing that resources do some sort of authorization. I don’t really care if they’re using a scope or direct auth, as long as they’re checking one of the two.

    For the tests I just copied the existing tests you have for those decorators and made sure that it will pass if either function is called.

    I’m happy to add a mention of this decorator into the readme if you agree it’s a good idea.

    If I end up writing anything else while using this, is just creating a pull request a good way to offer back the suggestions? Or would you rather I put in an issue first and ask?

    Thanks!

    opened by dbanty 3
  • Support Flask 1.0.0+

    Support Flask 1.0.0+

    Hello,

    I was just about to try using Flask-pundit which looks amazing and exactly what I've been searching for. However, I'm using Flask 1.0.2 which pip thinks is incompatible with this extension. I see you already changed the requirements to the new version of Flask, will you be uploading a release soon with this support?

    Thanks!

    opened by dbanty 3
  • Unpin Flask requirement

    Unpin Flask requirement

    As Flask releases bug fixes (e.g. 1.0.3), new features (e.g. 1.1.0), etc. that do not break compatibility (according to semver) it would be nice for Pundit to not complain about using newer releases. I've updated setup.py to reflect this.

    opened by dbanty 2
  • Python 3 Support

    Python 3 Support

    Using Python 3.7 I get an IndexError when passing in a resource to the authorize function. It looks like the regex pattern in Python 3 is matching a final, empty string, so when name[-1] is called, it's an error.

    The basic fix is pretty easy, just check if the string is empty in the internal dasherize function and if so, return that empty string.

    I'm fixing it anyway for my own usage, so I'll put in a pull request.

    opened by dbanty 0
  • Remove scope classes and replace them with scope methods

    Remove scope classes and replace them with scope methods

    Scope classes are just unnecessary complexity and can be achieved by a method.

    I still like the idea of having a policy_scopemethod vs just calling authorize with an action as scope. This is primarily because its more indicative that this is 'different' behaviour.

    opened by anurag90x 0
  • Support Flask 2

    Support Flask 2

    Right now Flask Pundit has a dependency on flask. flask<2,>=1.0.2

    https://flask.palletsprojects.com/en/2.0.x/changes/

    The major changes are the drop of official support for Py2 but since this lib already supports py3.7, It might be just fine to bump the dependency

    opened by sergioisidoro 0
Releases(1.0.2)
Owner
Anurag Chaudhury
Anurag Chaudhury
Flask JWT Router is a Python library that adds authorised routes to a Flask app.

Read the docs: Flask-JWT-Router Flask JWT Router Flask JWT Router is a Python library that adds authorised routes to a Flask app. Both basic & Google'

Joe Gasewicz 52 Jan 03, 2023
Todo app with authentication system.

todo list web app with authentication system. User can register, login, logout. User can login and create, delete, update task Home Page here you will

Anurag verma 3 Aug 18, 2022
Official implementation of the AAAI 2022 paper "Learning Token-based Representation for Image Retrieval"

Token: Token-based Representation for Image Retrieval PyTorch training code for Token-based Representation for Image Retrieval. We propose a joint loc

Hui Wu 42 Dec 06, 2022
Generate payloads that force authentication against an attacker machine

Hashgrab Generates scf, url & lnk payloads to put onto a smb share. These force authentication to an attacker machine in order to grab hashes (for exa

xct 35 Dec 20, 2022
REST implementation of Django authentication system.

djoser REST implementation of Django authentication system. djoser library provides a set of Django Rest Framework views to handle basic actions such

Sunscrapers 2.2k Jan 01, 2023
A JSON Web Token authentication plugin for the Django REST Framework.

Simple JWT Abstract Simple JWT is a JSON Web Token authentication plugin for the Django REST Framework. For full documentation, visit django-rest-fram

Jazzband 3.2k Dec 28, 2022
This project is an open-source project which I made due to sharing my experience around the Python programming language.

django-tutorial This project is an open-source project which I made due to sharing my experience around the Django framework. What is Django? Django i

MohammadMasoumi 6 May 12, 2022
Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (social) account authentication.

Welcome to django-allauth! Integrated set of Django applications addressing authentication, registration, account management as well as 3rd party (soc

Raymond Penners 7.7k Jan 03, 2023
Imia is an authentication library for Starlette and FastAPI (python 3.8+).

Imia Imia (belarussian for "a name") is an authentication library for Starlette and FastAPI (python 3.8+). Production status The library is considered

Alex Oleshkevich 91 Nov 24, 2022
JWT Key Confusion PoC (CVE-2015-9235) Written for the Hack the Box challenge - Under Construction

JWT Key Confusion PoC (CVE-2015-9235) Written for the Hack the Box challenge - Under Construction This script performs a Java Web Token Key Confusion

Alex Fronteddu 1 Jan 13, 2022
A JSON Web Token authentication plugin for the Django REST Framework.

Simple JWT Abstract Simple JWT is a JSON Web Token authentication plugin for the Django REST Framework. For full documentation, visit django-rest-fram

Jazzband 3.2k Dec 29, 2022
Script that provides your TESLA access_token and refresh_token

TESLA tokens This script helps you get your TESLA access_token and refresh_token in order to connect to third party applications (Teslamate, TeslaFi,

Bun-Ny TAN 3 Apr 28, 2022
Provide OAuth2 access to your app

django-oml Welcome to the documentation for django-oml! OML means Object Moderation Layer, the idea is to have a mixin model that allows you to modera

Caffeinehit 334 Jul 27, 2022
A secure authentication module to validate user credentials in a Streamlit application.

Streamlit-Authenticator A secure authentication module to validate user credentials in a Streamlit application. Installation Streamlit-Authenticator i

M Khorasani 336 Dec 31, 2022
Simple yet powerful authorization / authentication client library for Python web applications.

Authomatic Authomatic is a framework agnostic library for Python web applications with a minimalistic but powerful interface which simplifies authenti

1k Dec 28, 2022
API with high performance to create a simple blog and Auth using OAuth2 ⛏

DogeAPI API with high performance built with FastAPI & SQLAlchemy, help to improve connection with your Backend Side to create a simple blog and Cruds

Yasser Tahiri 111 Jan 05, 2023
FastAPI-Login tries to provide similar functionality as Flask-Login does.

FastAPI-Login FastAPI-Login tries to provide similar functionality as Flask-Login does. Installation $ pip install fastapi-login Usage To begin we hav

417 Jan 07, 2023
Per object permissions for Django

django-guardian django-guardian is an implementation of per object permissions [1] on top of Django's authorization backend Documentation Online docum

3.3k Jan 01, 2023
A recipe sharing API built using Django rest framework.

Recipe Sharing API This is the backend API for the recipe sharing platform at https://mesob-recipe.netlify.app/ This API allows users to share recipes

Hannah 21 Dec 30, 2022
蓝鲸用户管理是蓝鲸智云提供的企业组织架构和用户管理解决方案,为企业统一登录提供认证源服务。

蓝鲸用户管理 简体中文 | English 蓝鲸用户管理是蓝鲸智云提供的企业组织架构和用户管理解决方案,为企业统一登录提供认证源服务。 总览 架构设计 代码目录 功能 支持多层级的组织架构管理 支持通过多种方式同步数据:OpenLDAP、Microsoft Active Directory(MAD)

腾讯蓝鲸 35 Dec 14, 2022