diff --git a/docs/quickstart.rst b/docs/quickstart.rst index f79d8e0..2468ab4 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -54,6 +54,7 @@ The following configuration values exist for Flask-Multipass: ``MULTIPASS_FAILURE_CATEGORY`` Category of message when flashing after unsuccessful login ``MULTIPASS_ALL_MATCHING_IDENTITIES`` If true, all matching identities are passed after successful authentication ``MULTIPASS_REQUIRE_IDENTITY`` If true, ``IdentityRetrievalFailed`` is raised when no matching identities are found, otherwise empty list is passed +``MULTIPASS_HIDE_NO_SUCH_USER`` If true, ``InvalidCredentials`` instead of ``NoSuchUser`` is raised when no user is found in the system ====================================== ========================================= A configuration example can be found here: :ref:`config_example` diff --git a/flask_multipass/core.py b/flask_multipass/core.py index a9f5c02..dc00948 100644 --- a/flask_multipass/core.py +++ b/flask_multipass/core.py @@ -12,7 +12,13 @@ from werkzeug.exceptions import NotFound from flask_multipass.auth import AuthProvider -from flask_multipass.exceptions import GroupRetrievalFailed, IdentityRetrievalFailed, MultipassException +from flask_multipass.exceptions import ( + GroupRetrievalFailed, + IdentityRetrievalFailed, + InvalidCredentials, + MultipassException, + NoSuchUser, +) from flask_multipass.identity import IdentityProvider from flask_multipass.util import ( get_canonical_provider_map, @@ -72,6 +78,7 @@ def init_app(self, app): app.config.setdefault('MULTIPASS_FAILURE_CATEGORY', 'error') app.config.setdefault('MULTIPASS_ALL_MATCHING_IDENTITIES', False) app.config.setdefault('MULTIPASS_REQUIRE_IDENTITY', True) + app.config.setdefault('MULTIPASS_HIDE_NO_SUCH_USER', False) with app.app_context(): self._create_login_rule() state.auth_providers = ImmutableDict(self._create_providers('AUTH', AuthProvider)) @@ -528,6 +535,8 @@ def handle_login_form(self, provider, data): try: response = provider.process_local_login(data) except MultipassException as e: + if isinstance(e, NoSuchUser) and current_app.config['MULTIPASS_HIDE_NO_SUCH_USER']: + e = InvalidCredentials(e.provider) self.handle_auth_error(e) else: return response diff --git a/flask_multipass/exceptions.py b/flask_multipass/exceptions.py index 320ee44..f7b37cc 100644 --- a/flask_multipass/exceptions.py +++ b/flask_multipass/exceptions.py @@ -32,8 +32,9 @@ def __init__(self, details=None, provider=None): class InvalidCredentials(AuthenticationFailed): """Indicates a failure to authenticate using the given credentials.""" - def __init__(self, details=None, provider=None): + def __init__(self, details=None, provider=None, identifier=None): AuthenticationFailed.__init__(self, 'Invalid credentials', details=details, provider=provider) + self.identifier = identifier class IdentityRetrievalFailed(MultipassException): diff --git a/flask_multipass/providers/ldap/providers.py b/flask_multipass/providers/ldap/providers.py index a764c62..dcce6e4 100644 --- a/flask_multipass/providers/ldap/providers.py +++ b/flask_multipass/providers/ldap/providers.py @@ -81,7 +81,7 @@ def process_local_login(self, data): raise NoSuchUser(provider=self) current_ldap.connection.simple_bind_s(user_dn, password) except INVALID_CREDENTIALS: - raise InvalidCredentials(provider=self) + raise InvalidCredentials(provider=self, identifier=data['username']) auth_info = AuthInfo(self, identifier=user_data[self.ldap_settings['uid']][0]) return self.multipass.handle_auth_success(auth_info) diff --git a/flask_multipass/providers/sqlalchemy.py b/flask_multipass/providers/sqlalchemy.py index 5beeaba..25293fb 100644 --- a/flask_multipass/providers/sqlalchemy.py +++ b/flask_multipass/providers/sqlalchemy.py @@ -55,7 +55,7 @@ def process_local_login(self, data): if not identity: raise NoSuchUser(provider=self) if not self.check_password(identity, data['password']): - raise InvalidCredentials(provider=self) + raise InvalidCredentials(provider=self, identifier=data['identifier']) auth_info = AuthInfo(self, identity=identity) return self.multipass.handle_auth_success(auth_info) diff --git a/flask_multipass/providers/static.py b/flask_multipass/providers/static.py index 96c05e7..7399ede 100644 --- a/flask_multipass/providers/static.py +++ b/flask_multipass/providers/static.py @@ -44,7 +44,7 @@ def process_local_login(self, data): if password is None: raise NoSuchUser(provider=self) if password != data['password']: - raise InvalidCredentials(provider=self) + raise InvalidCredentials(provider=self, identifier=data['username']) auth_info = AuthInfo(self, username=data['username']) return self.multipass.handle_auth_success(auth_info)