Quickstart

Requirements

  • Python 3.5

Note on Requirements

I do not currently plan to support older versions of python. Python 2 support is very unlikely to arrive as the original author is a die-hard believer in python 3. As for older versions of python 3, my test harnesses depend on some features only available in python 3.5.

Installation

Note

flask-praetorian does not support distutils or setuptools because the author has very strong feelings about python packaging and the role pip plays in taking us into a bright new future of standardized and usable python packaging

Install from pypi

This will install the latest release of flask-praetorian from pypi via pip:

$ pip install flask-praetorian

Install latest version from github

If you would like a version other than the latest published on pypi, you may do so by cloning the git repostiory:

$ git clone https://github.com/dusktreader/flask-praetorian.git

Next, checkout the branch or tag that you wish to use:

$ cd flask-praetorian
$ git checkout integration

Finally, use pip to install from the local directory:

$ pip install .

Example

This is a minimal example of how to use the flask-praetorian decorators:

import flask
import tempfile
import flask_sqlalchemy
import flask_praetorian

db = flask_sqlalchemy.SQLAlchemy()
guard = flask_praetorian.Praetorian()


class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.Text, unique=True)
    password = db.Column(db.Text)
    roles = db.Column(db.Text)

    @property
    def rolenames(self):
        try:
            return self.roles.split(',')
        except:
            return []

    @classmethod
    def lookup(cls, username):
        return cls.query.filter_by(username=username).one_or_none()

    @classmethod
    def identify(cls, id):
        return cls.query.get(id)


app = flask.Flask(__name__)
app.debug = True
app.config['SECRET_KEY'] = 'top secret'

guard.init_app(app, User)

local_database = tempfile.NamedTemporaryFile(prefix='local', suffix='.db')
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///{}'.format(local_database)
db.init_app(app)
with app.app_context():
    db.create_all()
    db.session.add(User(
        username='TheDude',
        password=guard.encrypt_password('abides'),
    ))
    db.session.add(User(
        username='Walter',
        password=guard.encrypt_password('calmerthanyouare'),
        roles='admin'
    ))
    db.session.add(User(
        username='Donnie',
        password=guard.encrypt_password('iamthewalrus'),
        roles='operator'
    ))
    db.session.add(User(
        username='Maude',
        password=guard.encrypt_password('andthorough'),
        roles='operator,admin'
    ))
    db.session.commit()


@app.route('/')
def root():
    return 'root endpoint'


@app.route('/protected')
@flask_praetorian.auth_required()
def protected():
    return 'protected endpoint'


@app.route('/protected_admin_required')
@flask_praetorian.auth_required()
@flask_praetorian.roles_required('admin')
def protected_admin_required():
    return 'protected_admin_required endpoint'


@app.route('/protected_admin_accepted')
@flask_praetorian.auth_required()
@flask_praetorian.roles_accepted('admin', 'operator')
def protected_admin_and_operator_accepted():
    return 'protected_admin_accepted endpoint'


if __name__ == '__main__':
    app.run()

The above code can be found example/basic.py. The server can be started by calling:

$ python example/basic.py

Once the server is up and running, you can login and get an auth token by POSTing to the ‘/auth’ endpoint with a body containing your username and password:

POST /auth HTTP/1.1
Host: localhost:5000
Content-Type: application/json
{
    "username": "TheDude",
    "password": "abides"
}

The response will have a json body containing the token:

HTTP/1.1 200 OK
Content-Type: application/json
{
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E"
}

This token can then be used to make requests against protected endpoints:: Once you have provisioned a token, you can try out the various endpoints that were created above by include the token in the request header like soo:

GET /protected HTTP/1.1
Authorization: JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZGVudGl0eSI6MSwiaWF0IjoxNDQ0OTE3NjQwLCJuYmYiOjE0NDQ5MTc2NDAsImV4cCI6MTQ0NDkxNzk0MH0.KPmI6WSjRjlpzecPvs3q_T3cJQvAgJvaQAPtk1abC_E

You can try out the different endpoints with different users provisioned above to see how the role constraining decorators from flask-praetorian work.