|
@@ -16,6 +16,8 @@ class StopAuthentication(BaseFlaskBBError):
|
|
"""
|
|
"""
|
|
Used by Authentication providers to halt any further
|
|
Used by Authentication providers to halt any further
|
|
attempts to authenticate a user.
|
|
attempts to authenticate a user.
|
|
|
|
+
|
|
|
|
+ :param reason str: The reason why authentication was halted
|
|
"""
|
|
"""
|
|
|
|
|
|
def __init__(self, reason):
|
|
def __init__(self, reason):
|
|
@@ -26,6 +28,8 @@ class StopAuthentication(BaseFlaskBBError):
|
|
class ForceLogout(BaseFlaskBBError):
|
|
class ForceLogout(BaseFlaskBBError):
|
|
"""
|
|
"""
|
|
Used to forcefully log a user out.
|
|
Used to forcefully log a user out.
|
|
|
|
+
|
|
|
|
+ :param reason str: The reason why the user was force logged out
|
|
"""
|
|
"""
|
|
|
|
|
|
def __init__(self, reason):
|
|
def __init__(self, reason):
|
|
@@ -34,22 +38,69 @@ class ForceLogout(BaseFlaskBBError):
|
|
|
|
|
|
|
|
|
|
class AuthenticationManager(ABC):
|
|
class AuthenticationManager(ABC):
|
|
|
|
+ """
|
|
|
|
+ Used to handle the authentication process. A default is implemented,
|
|
|
|
+ however this interface is provided in case alternative flows are needed.
|
|
|
|
+
|
|
|
|
+ If a user successfully passes through the entire authentication process,
|
|
|
|
+ then it should be returned to the caller.
|
|
|
|
+ """
|
|
|
|
|
|
@abstractmethod
|
|
@abstractmethod
|
|
def authenticate(self, identifier, secret):
|
|
def authenticate(self, identifier, secret):
|
|
"""
|
|
"""
|
|
- Manages the entire authentication process in FlaskBB.
|
|
|
|
|
|
+ This method is abstract.
|
|
|
|
+
|
|
|
|
+ :param str identifier: An identifer for the user, typically this is
|
|
|
|
+ either a username or an email.
|
|
|
|
+ :param str secret: A secret to verify the user is who they say they are
|
|
|
|
+ :returns: A fully authenticated but not yet logged in user
|
|
|
|
+ :rtype: :class:`User<flaskbb.user.models.User>`
|
|
|
|
|
|
- If a user is successfully authenticated, it is returned
|
|
|
|
- from this method.
|
|
|
|
"""
|
|
"""
|
|
pass
|
|
pass
|
|
|
|
|
|
|
|
|
|
class AuthenticationProvider(ABC):
|
|
class AuthenticationProvider(ABC):
|
|
|
|
+ """
|
|
|
|
+ Used to provide an authentication service for FlaskBB.
|
|
|
|
+
|
|
|
|
+ For example, an implementer may choose to use LDAP as an authentication
|
|
|
|
+ source::
|
|
|
|
+
|
|
|
|
+ class LDAPAuthenticationProvider(AuthenticationProvider):
|
|
|
|
+ def __init__(self, ldap_client):
|
|
|
|
+ self.ldap_client = ldap_client
|
|
|
|
+
|
|
|
|
+ def authenticate(self, identifier, secret):
|
|
|
|
+ user_dn = "uid={},ou=flaskbb,ou=org".format(identifier)
|
|
|
|
+ try:
|
|
|
|
+ self.ldap_client.bind_user(user_dn, secret)
|
|
|
|
+ return User.query.join(
|
|
|
|
+ UserLDAP
|
|
|
|
+ ).filter(
|
|
|
|
+ UserLDAP.dn==user_dn
|
|
|
|
+ ).with_entities(User).one()
|
|
|
|
+ except Exception:
|
|
|
|
+ return None
|
|
|
|
+
|
|
|
|
+ During an authentication process, a provider may raise a
|
|
|
|
+ :class:`StopAuthentication<flaskbb.core.auth.authentication.StopAuthentication>`
|
|
|
|
+ exception to completely, but safely halt the process. This is most useful
|
|
|
|
+ when multiple providers are being used.
|
|
|
|
+ """
|
|
|
|
|
|
@abstractmethod
|
|
@abstractmethod
|
|
def authenticate(self, identifier, secret):
|
|
def authenticate(self, identifier, secret):
|
|
|
|
+ """
|
|
|
|
+ This method is abstract.
|
|
|
|
+
|
|
|
|
+ :param str identifier: An identifer for the user, typically this is
|
|
|
|
+ either a username or an email.
|
|
|
|
+ :param str secret: A secret to verify the user is who they say they are
|
|
|
|
+ :returns: An authenticated user.
|
|
|
|
+ :rtype: :class:`User<flaskbb.user.models.User>`
|
|
|
|
+ """
|
|
pass
|
|
pass
|
|
|
|
|
|
def __call__(self, identifier, secret):
|
|
def __call__(self, identifier, secret):
|
|
@@ -57,9 +108,26 @@ class AuthenticationProvider(ABC):
|
|
|
|
|
|
|
|
|
|
class AuthenticationFailureHandler(ABC):
|
|
class AuthenticationFailureHandler(ABC):
|
|
|
|
+ """
|
|
|
|
+ Used to post process authentication failures, such as no provider returning
|
|
|
|
+ a user or a provider raising
|
|
|
|
+ :class:`StopAuthentication<flaskbb.core.auth.authentication.StopAuthentication>`.
|
|
|
|
+
|
|
|
|
+ Postprocessing may take many forms, such as incrementing the login attempts
|
|
|
|
+ locking an account if too many attempts are made, forcing a reauth if
|
|
|
|
+ the user is currently authenticated in a different session, etc.
|
|
|
|
+
|
|
|
|
+ Failure handlers should not return a value as it will not be considered.
|
|
|
|
+ """
|
|
|
|
|
|
@abstractmethod
|
|
@abstractmethod
|
|
def handle_authentication_failure(self, identifier):
|
|
def handle_authentication_failure(self, identifier):
|
|
|
|
+ """
|
|
|
|
+ This method is abstract.
|
|
|
|
+
|
|
|
|
+ :param str identifier: An identifer for the user, typically this is
|
|
|
|
+ either a username or an email.
|
|
|
|
+ """
|
|
pass
|
|
pass
|
|
|
|
|
|
def __call__(self, identifier):
|
|
def __call__(self, identifier):
|
|
@@ -67,9 +135,35 @@ class AuthenticationFailureHandler(ABC):
|
|
|
|
|
|
|
|
|
|
class PostAuthenticationHandler(ABC):
|
|
class PostAuthenticationHandler(ABC):
|
|
|
|
+ """
|
|
|
|
+ Used to post process authentication success. Post authentication handlers
|
|
|
|
+ recieve the user instance that was returned by the successful
|
|
|
|
+ authentication rather than the identifer.
|
|
|
|
+
|
|
|
|
+ Postprocessors may decide to preform actions such as flashing a message
|
|
|
|
+ to the user, clearing failed login attempts, etc.
|
|
|
|
+
|
|
|
|
+ Alternatively, a postprocessor can decide to fail the authentication
|
|
|
|
+ process anyways by raising
|
|
|
|
+ :class:`StopAuthentication<flaskbb.core.auth.authentication.StopAuthentication>`,
|
|
|
|
+ for example a user may successfully authenticate but has not yet activated
|
|
|
|
+ their account.
|
|
|
|
+
|
|
|
|
+ Cancelling a successful authentication will cause registered
|
|
|
|
+ :class:`AuthenticationFailureHandler<flaskbb.core.auth.authentication.AuthenticationFailureHandler>`
|
|
|
|
+ instances to be run.
|
|
|
|
+
|
|
|
|
+ Success handlers should not return a value as it will not be considered.
|
|
|
|
+ """
|
|
|
|
|
|
@abstractmethod
|
|
@abstractmethod
|
|
def handle_post_auth(self, user):
|
|
def handle_post_auth(self, user):
|
|
|
|
+ """
|
|
|
|
+ This method is abstact.
|
|
|
|
+
|
|
|
|
+ :param user: An authenticated but not yet logged in user
|
|
|
|
+ :type user: :class:`User<flaskbb.user.model.User>`
|
|
|
|
+ """
|
|
pass
|
|
pass
|
|
|
|
|
|
def __call__(self, user):
|
|
def __call__(self, user):
|
|
@@ -77,9 +171,23 @@ class PostAuthenticationHandler(ABC):
|
|
|
|
|
|
|
|
|
|
class ReauthenticateManager(ABC):
|
|
class ReauthenticateManager(ABC):
|
|
|
|
+ """
|
|
|
|
+ Used to handle the reauthentication process in FlaskBB. A default
|
|
|
|
+ implementation is provided, however this is interface exists in case
|
|
|
|
+ alternative flows are desired.
|
|
|
|
|
|
|
|
+ Unlike the AuthenticationManager, there is no need to return the user to
|
|
|
|
+ the caller.
|
|
|
|
+ """
|
|
@abstractmethod
|
|
@abstractmethod
|
|
def reauthenticate(self, user, secret):
|
|
def reauthenticate(self, user, secret):
|
|
|
|
+ """
|
|
|
|
+ This method is abstract.
|
|
|
|
+
|
|
|
|
+ :param user: The current user instance
|
|
|
|
+ :param str secret: The secret provided by the user
|
|
|
|
+ :type user: :class:`User<flaskbb.user.models.User>`
|
|
|
|
+ """
|
|
pass
|
|
pass
|
|
|
|
|
|
def __call__(self, user, secret):
|
|
def __call__(self, user, secret):
|
|
@@ -87,9 +195,50 @@ class ReauthenticateManager(ABC):
|
|
|
|
|
|
|
|
|
|
class ReauthenticateProvider(ABC):
|
|
class ReauthenticateProvider(ABC):
|
|
|
|
+ """
|
|
|
|
+ Used to reauthenticate a user that is already logged into the system,
|
|
|
|
+ for example when suspicious activity is detected in their session.
|
|
|
|
+
|
|
|
|
+ ReauthenticateProviders are similiar to
|
|
|
|
+ :class:`AuthenticationProvider<flaskbb.core.auth.authentication.AuthenticationProvider>`
|
|
|
|
+ except they receive a user instance rather than an identifer for a user.
|
|
|
|
+
|
|
|
|
+ A successful reauthentication should return True while failures should
|
|
|
|
+ return None in order to give other providers an attempt run.
|
|
|
|
+
|
|
|
|
+ If a ReauthenticateProvider determines that reauthentication should
|
|
|
|
+ immediately end, it may raise
|
|
|
|
+ :class:`StopAuthentication<flaskbb.core.auth.authentication.StopAuthentication>`
|
|
|
|
+ to safely end the process.
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ An example::
|
|
|
|
+
|
|
|
|
+ class LDAPReauthenticateProvider(ReauthenticateProvider):
|
|
|
|
+ def __init__(self, ldap_client):
|
|
|
|
+ self.ldap_client = ldap_client
|
|
|
|
+
|
|
|
|
+ def reauthenticate(self, user, secret):
|
|
|
|
+ user_dn = "uid={},ou=flaskbb,ou=org".format(user.username)
|
|
|
|
+ try:
|
|
|
|
+ self.ldap_client.bind_user(user_dn, secret)
|
|
|
|
+ return True
|
|
|
|
+ except Exception:
|
|
|
|
+ return None
|
|
|
|
+
|
|
|
|
+ """
|
|
|
|
|
|
@abstractmethod
|
|
@abstractmethod
|
|
def reauthenticate(self, user, secret):
|
|
def reauthenticate(self, user, secret):
|
|
|
|
+ """
|
|
|
|
+ This method is abstract.
|
|
|
|
+
|
|
|
|
+ :param user: The current user instance
|
|
|
|
+ :param str secret: The secret provided by the user
|
|
|
|
+ :type user: :class:`User<flaskbb.user.models.User>`
|
|
|
|
+ :returns: True for a successful reauth, otherwise None
|
|
|
|
+ """
|
|
|
|
+
|
|
pass
|
|
pass
|
|
|
|
|
|
def __call__(self, user, secret):
|
|
def __call__(self, user, secret):
|
|
@@ -97,9 +246,21 @@ class ReauthenticateProvider(ABC):
|
|
|
|
|
|
|
|
|
|
class ReauthenticateFailureHandler(ABC):
|
|
class ReauthenticateFailureHandler(ABC):
|
|
|
|
+ """
|
|
|
|
+ Used to manager reauthentication failures in FlaskBB.
|
|
|
|
|
|
|
|
+ ReauthenticateFailureHandlers are similiar to
|
|
|
|
+ :class:`AuthenticationFailureHandler<flaskbb.core.auth.authentication.AuthenticationFailureHandler>`
|
|
|
|
+ except they receive the user instance rather than an indentifier for a user
|
|
|
|
+ """
|
|
@abstractmethod
|
|
@abstractmethod
|
|
def handle_reauth_failure(self, user):
|
|
def handle_reauth_failure(self, user):
|
|
|
|
+ """
|
|
|
|
+ This method is abstract.
|
|
|
|
+
|
|
|
|
+ :param user: The current user instance that failed the reauth attempt
|
|
|
|
+ :type user: :class:`User<flaskbb.user.models.User>`
|
|
|
|
+ """
|
|
pass
|
|
pass
|
|
|
|
|
|
def __call__(self, user):
|
|
def __call__(self, user):
|
|
@@ -107,9 +268,23 @@ class ReauthenticateFailureHandler(ABC):
|
|
|
|
|
|
|
|
|
|
class PostReauthenticateHandler(ABC):
|
|
class PostReauthenticateHandler(ABC):
|
|
|
|
+ """
|
|
|
|
+ Used to post process successful reauthentication attempts.
|
|
|
|
+
|
|
|
|
+ PostAuthenticationHandlers are similar to
|
|
|
|
+ :class:`PostAuthenticationHandler<flaskbb.core.auth.authentication.PostAuthenticationHandler>`,
|
|
|
|
+ including their ability to cancel a successful attempt by raising
|
|
|
|
+ :class:`StopAuthentication<flaskbb.core.auth.authentication.StopAuthentication>`
|
|
|
|
+ """
|
|
|
|
|
|
@abstractmethod
|
|
@abstractmethod
|
|
def handle_post_reauth(self, user):
|
|
def handle_post_reauth(self, user):
|
|
|
|
+ """
|
|
|
|
+ This method is abstract.
|
|
|
|
+
|
|
|
|
+ :param user: The current user instance that passed the reauth attempt
|
|
|
|
+ :type user: :class:`User<flaskbb.user.models.User>`
|
|
|
|
+ """
|
|
pass
|
|
pass
|
|
|
|
|
|
def __call__(self, user):
|
|
def __call__(self, user):
|