File: flask_basicauth.py

package info (click to toggle)
flask-basicauth 0.2.0-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 168 kB
  • sloc: python: 217; makefile: 140
file content (111 lines) | stat: -rw-r--r-- 3,601 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
"""
    flask_basicauth
    ~~~~~~~~~~~~~~~~~~~

    Flask-BasicAuth is a Flask extension that provides an easy way to protect
    certain views or your whole application with HTTP basic access
    authentication.

    :copyright: (c) 2013 Janne Vanhala.
    :license: BSD, see LICENSE for more details.
"""
import base64
from functools import wraps

from flask import current_app, request, Response


__version__ = '0.2.0'


class BasicAuth(object):
    """
    A Flask extension for adding HTTP basic access authentication to the
    application.

    :param app: a :class:`~flask.Flask` instance. Defaults to `None`. If no
        application is provided on creation, then it can be provided later on
        via :meth:`init_app`.
    """
    def __init__(self, app=None):
        if app is not None:
            self.app = app
            self.init_app(app)
        else:
            self.app = None

    def init_app(self, app):
        """
        Initialize this BasicAuth extension for the given application.

        :param app: a :class:`~flask.Flask` instance
        """
        app.config.setdefault('BASIC_AUTH_FORCE', False)
        app.config.setdefault('BASIC_AUTH_REALM', '')

        @app.before_request
        def require_basic_auth():
            if not current_app.config['BASIC_AUTH_FORCE']:
                return
            if not self.authenticate():
                return self.challenge()

    def check_credentials(self, username, password):
        """
        Check if the given username and password are correct.

        By default compares the given username and password to
        ``HTTP_BASIC_AUTH_USERNAME`` and ``HTTP_BASIC_AUTH_PASSWORD``
        configuration variables.

        :param username: a username provided by the client
        :param password: a password provided by the client
        :returns: `True` if the username and password combination was correct,
            and `False` otherwise.
        """
        correct_username = current_app.config['BASIC_AUTH_USERNAME']
        correct_password = current_app.config['BASIC_AUTH_PASSWORD']
        return username == correct_username and password == correct_password

    def authenticate(self):
        """
        Check the request for HTTP basic access authentication header and try
        to authenticate the user.

        :returns: `True` if the user is authorized, or `False` otherwise.
        """
        auth = request.authorization
        return (
            auth and auth.type == 'basic' and
            self.check_credentials(auth.username, auth.password)
        )

    def challenge(self):
        """
        Challenge the client for username and password.

        This method is called when the client did not provide username and
        password in the request, or the username and password combination was
        wrong.

        :returns: a :class:`~flask.Response` with 401 response code, including
            the required authentication scheme and authentication realm.
        """
        realm = current_app.config['BASIC_AUTH_REALM']
        return Response(
            status=401,
            headers={'WWW-Authenticate': 'Basic realm="%s"' % realm}
        )

    def required(self, view_func):
        """
        A decorator that can be used to protect specific views with HTTP
        basic access authentication.
        """
        @wraps(view_func)
        def wrapper(*args, **kwargs):
            if self.authenticate():
                return view_func(*args, **kwargs)
            else:
                return self.challenge()
        return wrapper