Changed the BasePasswordGetter and BaseUserGetter from abstract to non-abstract, to simplify the code.
This commit is contained in:
parent
cb3e313e21
commit
2aaaa9f47f
38
README.rst
38
README.rst
@ -12,6 +12,10 @@ views.
|
|||||||
|
|
||||||
HTTP Digest Authentication is specified in `RFC 2617`_.
|
HTTP Digest Authentication is specified in `RFC 2617`_.
|
||||||
|
|
||||||
|
|
||||||
|
Why HTTP Digest Authentication?
|
||||||
|
-------------------------------
|
||||||
|
|
||||||
HTTP Digest Authentication has the advantage that it does not send the
|
HTTP Digest Authentication has the advantage that it does not send the
|
||||||
actual password to the server, which greatly enhances the security.
|
actual password to the server, which greatly enhances the security.
|
||||||
It uses the challenge-response authentication scheme. The client
|
It uses the challenge-response authentication scheme. The client
|
||||||
@ -28,6 +32,40 @@ Flask-Digest-Auth works with Flask-Login_. Log in protection can be
|
|||||||
separated with the authentication mechanism. You can create protected
|
separated with the authentication mechanism. You can create protected
|
||||||
Flask modules without knowing the actual authentication mechanisms.
|
Flask modules without knowing the actual authentication mechanisms.
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
|
||||||
|
There are a couple of Flask HTTP digest authentication
|
||||||
|
implementations. Flask-Digest-Auth has the following features:
|
||||||
|
|
||||||
|
|
||||||
|
Flask-Login Integration
|
||||||
|
#######################
|
||||||
|
|
||||||
|
Flask-Digest-Auth features Flask-Login integration. The views
|
||||||
|
can be totally independent with the actual authentication mechanism.
|
||||||
|
You can write a Flask module that requires log in, without specify
|
||||||
|
the actual authentication mechanism. The application can specify
|
||||||
|
either HTTP Digest Authentication, or the log in forms, as needed.
|
||||||
|
|
||||||
|
|
||||||
|
Session Integration
|
||||||
|
###################
|
||||||
|
|
||||||
|
Flask-Digest-Auth features session integration. The user log in
|
||||||
|
is remembered in the session. The authentication information is not
|
||||||
|
requested again. This is different to the practice of the HTTP Digest
|
||||||
|
Authentication, but is convenient for the log in accounting.
|
||||||
|
|
||||||
|
|
||||||
|
Log Out Support
|
||||||
|
###############
|
||||||
|
|
||||||
|
Flask-Digest-Auth supports log out. The user will be prompted for
|
||||||
|
new username and password.
|
||||||
|
|
||||||
|
|
||||||
.. _HTTP Digest Authentication: https://en.wikipedia.org/wiki/Digest_access_authentication
|
.. _HTTP Digest Authentication: https://en.wikipedia.org/wiki/Digest_access_authentication
|
||||||
.. _RFC 2617: https://www.rfc-editor.org/rfc/rfc2617
|
.. _RFC 2617: https://www.rfc-editor.org/rfc/rfc2617
|
||||||
.. _Flask: https://flask.palletsprojects.com
|
.. _Flask: https://flask.palletsprojects.com
|
||||||
|
@ -23,7 +23,6 @@ from __future__ import annotations
|
|||||||
|
|
||||||
import sys
|
import sys
|
||||||
import typing as t
|
import typing as t
|
||||||
from abc import ABC, abstractmethod
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from random import random
|
from random import random
|
||||||
from secrets import token_urlsafe
|
from secrets import token_urlsafe
|
||||||
@ -36,11 +35,10 @@ from flask_digest_auth.algo import calc_response
|
|||||||
from flask_digest_auth.exception import UnauthorizedException
|
from flask_digest_auth.exception import UnauthorizedException
|
||||||
|
|
||||||
|
|
||||||
class BasePasswordHashGetter(ABC):
|
class BasePasswordHashGetter:
|
||||||
"""The base password hash getter."""
|
"""The base password hash getter."""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@abstractmethod
|
|
||||||
def __call__(username: str) -> t.Optional[str]:
|
def __call__(username: str) -> t.Optional[str]:
|
||||||
"""Returns the password hash of a user.
|
"""Returns the password hash of a user.
|
||||||
|
|
||||||
@ -49,13 +47,14 @@ class BasePasswordHashGetter(ABC):
|
|||||||
:raise UnboundLocalError: When the password hash getter function is
|
:raise UnboundLocalError: When the password hash getter function is
|
||||||
not registered yet.
|
not registered yet.
|
||||||
"""
|
"""
|
||||||
|
raise UnboundLocalError("The function to return the password hash"
|
||||||
|
" was not registered yet.")
|
||||||
|
|
||||||
|
|
||||||
class BaseUserGetter(ABC):
|
class BaseUserGetter:
|
||||||
"""The base user getter."""
|
"""The base user getter."""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@abstractmethod
|
|
||||||
def __call__(username: str) -> t.Optional[t.Any]:
|
def __call__(username: str) -> t.Optional[t.Any]:
|
||||||
"""Returns a user.
|
"""Returns a user.
|
||||||
|
|
||||||
@ -64,6 +63,8 @@ class BaseUserGetter(ABC):
|
|||||||
:raise UnboundLocalError: When the user getter function is not
|
:raise UnboundLocalError: When the user getter function is not
|
||||||
registered yet.
|
registered yet.
|
||||||
"""
|
"""
|
||||||
|
raise UnboundLocalError("The function to return the user"
|
||||||
|
" was not registered yet.")
|
||||||
|
|
||||||
|
|
||||||
class DigestAuth:
|
class DigestAuth:
|
||||||
@ -83,41 +84,9 @@ class DigestAuth:
|
|||||||
self.domain: t.List[str] = []
|
self.domain: t.List[str] = []
|
||||||
self.qop: t.List[str] = ["auth", "auth-int"]
|
self.qop: t.List[str] = ["auth", "auth-int"]
|
||||||
self.app: t.Optional[Flask] = None
|
self.app: t.Optional[Flask] = None
|
||||||
|
|
||||||
class DummyPasswordHashGetter(BasePasswordHashGetter):
|
|
||||||
"""The dummy password hash getter."""
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def __call__(username: str) -> t.Optional[str]:
|
|
||||||
"""Returns the password hash of a user.
|
|
||||||
|
|
||||||
:param username: The username.
|
|
||||||
:return: The password hash, or None if the user does not exist.
|
|
||||||
:raise UnboundLocalError: When the password hash getter function
|
|
||||||
is not registered yet.
|
|
||||||
"""
|
|
||||||
raise UnboundLocalError("The function to return the password"
|
|
||||||
" hash was not registered yet.")
|
|
||||||
|
|
||||||
self.__get_password_hash: BasePasswordHashGetter \
|
self.__get_password_hash: BasePasswordHashGetter \
|
||||||
= DummyPasswordHashGetter()
|
= BasePasswordHashGetter()
|
||||||
|
self.__get_user: BaseUserGetter = BaseUserGetter()
|
||||||
class DummyUserGetter(BaseUserGetter):
|
|
||||||
"""The dummy user getter."""
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def __call__(username: str) -> t.Optional[t.Any]:
|
|
||||||
"""Returns a user.
|
|
||||||
|
|
||||||
:param username: The username.
|
|
||||||
:return: The user, or None if the user does not exist.
|
|
||||||
:raise UnboundLocalError: When the user getter function is not
|
|
||||||
registered yet.
|
|
||||||
"""
|
|
||||||
raise UnboundLocalError("The function to return the user"
|
|
||||||
" was not registered yet.")
|
|
||||||
|
|
||||||
self.__get_user: BaseUserGetter = DummyUserGetter()
|
|
||||||
|
|
||||||
def login_required(self, view) -> t.Callable:
|
def login_required(self, view) -> t.Callable:
|
||||||
"""The view decorator for HTTP digest authentication.
|
"""The view decorator for HTTP digest authentication.
|
||||||
|
Loading…
Reference in New Issue
Block a user