From b8a42eee324df7a1ea73cd2ba015d192fc60cf89 Mon Sep 17 00:00:00 2001 From: Bassam Ojeil Date: Tue, 3 Aug 2021 23:28:43 -0700 Subject: [PATCH 1/4] fix(auth): check if user disabled on check_revoked When `verify_session_cookie` or `verify_id_token` is called with `check_revoked` set to `True` we should also check if the user is disabled. If disabled the `UserDisabledError` is raised. --- firebase_admin/_auth_client.py | 12 ++++++++--- firebase_admin/_auth_utils.py | 9 ++++++++ firebase_admin/auth.py | 15 +++++++++++--- integration/test_auth.py | 36 ++++++++++++++++++++++++++++++++ snippets/auth/index.py | 6 ++++++ tests/test_token_gen.py | 38 ++++++++++++++++++++++++++++++++++ 6 files changed, 110 insertions(+), 6 deletions(-) diff --git a/firebase_admin/_auth_client.py b/firebase_admin/_auth_client.py index a58dbef74..ba4558acb 100644 --- a/firebase_admin/_auth_client.py +++ b/firebase_admin/_auth_client.py @@ -100,7 +100,8 @@ def verify_id_token(self, id_token, check_revoked=False): Args: id_token: A string of the encoded JWT. - check_revoked: Boolean, If true, checks whether the token has been revoked (optional). + check_revoked: Boolean, If true, checks whether the token has been revoked or + the user disabled (optional). Returns: dict: A dictionary of key-value pairs parsed from the decoded JWT. @@ -115,6 +116,8 @@ def verify_id_token(self, id_token, check_revoked=False): this ``Client`` instance. CertificateFetchError: If an error occurs while fetching the public key certificates required to verify the ID token. + UserDisabledError: If ``check_revoked`` is ``True`` and the corresponding user + record is disabled. """ if not isinstance(check_revoked, bool): # guard against accidental wrong assignment. @@ -129,7 +132,8 @@ def verify_id_token(self, id_token, check_revoked=False): 'Invalid tenant ID: {0}'.format(token_tenant_id)) if check_revoked: - self._check_jwt_revoked(verified_claims, _token_gen.RevokedIdTokenError, 'ID token') + self._check_jwt_revoked_or_disabled( + verified_claims, _token_gen.RevokedIdTokenError, 'ID token') return verified_claims def revoke_refresh_tokens(self, uid): @@ -720,7 +724,9 @@ def list_saml_provider_configs( """ return self._provider_manager.list_saml_provider_configs(page_token, max_results) - def _check_jwt_revoked(self, verified_claims, exc_type, label): + def _check_jwt_revoked_or_disabled(self, verified_claims, exc_type, label): user = self.get_user(verified_claims.get('uid')) if verified_claims.get('iat') * 1000 < user.tokens_valid_after_timestamp: raise exc_type('The Firebase {0} has been revoked.'.format(label)) + if user.disabled: + raise _auth_utils.UserDisabledError('The user record is disabled.') diff --git a/firebase_admin/_auth_utils.py b/firebase_admin/_auth_utils.py index 50c52812e..5a4e62593 100644 --- a/firebase_admin/_auth_utils.py +++ b/firebase_admin/_auth_utils.py @@ -385,6 +385,15 @@ def __init__(self, message, cause=None, http_response=None): exceptions.NotFoundError.__init__(self, message, cause, http_response) +class UserDisabledError(exceptions.FailedPreconditionError): + """An operation failed due to a user record being disabled.""" + + default_message = 'The user record is disabled' + + def __init__(self, message, cause=None, http_response=None): + exceptions.FailedPreconditionError.__init__(self, message, cause, http_response) + + _CODE_TO_EXC_TYPE = { 'CONFIGURATION_NOT_FOUND': ConfigurationNotFoundError, 'DUPLICATE_EMAIL': EmailAlreadyExistsError, diff --git a/firebase_admin/auth.py b/firebase_admin/auth.py index ed9829aca..40a5b611f 100644 --- a/firebase_admin/auth.py +++ b/firebase_admin/auth.py @@ -62,6 +62,7 @@ 'TokenSignError', 'UidAlreadyExistsError', 'UnexpectedResponseError', + 'UserDisabledError', 'UserImportHash', 'UserImportResult', 'UserInfo', @@ -135,6 +136,7 @@ TokenSignError = _token_gen.TokenSignError UidAlreadyExistsError = _auth_utils.UidAlreadyExistsError UnexpectedResponseError = _auth_utils.UnexpectedResponseError +UserDisabledError = _auth_utils.UserDisabledError UserImportHash = _user_import.UserImportHash UserImportResult = _user_import.UserImportResult UserInfo = _user_mgt.UserInfo @@ -198,7 +200,8 @@ def verify_id_token(id_token, app=None, check_revoked=False): Args: id_token: A string of the encoded JWT. app: An App instance (optional). - check_revoked: Boolean, If true, checks whether the token has been revoked (optional). + check_revoked: Boolean, If true, checks whether the token has been revoked or + the user disabled (optional). Returns: dict: A dictionary of key-value pairs parsed from the decoded JWT. @@ -210,6 +213,8 @@ def verify_id_token(id_token, app=None, check_revoked=False): RevokedIdTokenError: If ``check_revoked`` is ``True`` and the ID token has been revoked. CertificateFetchError: If an error occurs while fetching the public key certificates required to verify the ID token. + UserDisabledError: If ``check_revoked`` is ``True`` and the corresponding user + record is disabled. """ client = _get_client(app) return client.verify_id_token(id_token, check_revoked=check_revoked) @@ -246,7 +251,8 @@ def verify_session_cookie(session_cookie, check_revoked=False, app=None): Args: session_cookie: A session cookie string to verify. - check_revoked: Boolean, if true, checks whether the cookie has been revoked (optional). + check_revoked: Boolean, if true, checks whether the cookie has been revoked or the + user disabled (optional). app: An App instance (optional). Returns: @@ -259,12 +265,15 @@ def verify_session_cookie(session_cookie, check_revoked=False, app=None): RevokedSessionCookieError: If ``check_revoked`` is ``True`` and the cookie has been revoked. CertificateFetchError: If an error occurs while fetching the public key certificates required to verify the session cookie. + UserDisabledError: If ``check_revoked`` is ``True`` and the corresponding user + record is disabled. """ client = _get_client(app) # pylint: disable=protected-access verified_claims = client._token_verifier.verify_session_cookie(session_cookie) if check_revoked: - client._check_jwt_revoked(verified_claims, RevokedSessionCookieError, 'session cookie') + client._check_jwt_revoked_or_disabled( + verified_claims, RevokedSessionCookieError, 'session cookie') return verified_claims diff --git a/integration/test_auth.py b/integration/test_auth.py index 16ae52a86..55ddbb0a0 100644 --- a/integration/test_auth.py +++ b/integration/test_auth.py @@ -569,6 +569,24 @@ def test_verify_id_token_revoked(new_user, api_key): claims = auth.verify_id_token(id_token, check_revoked=True) assert claims['iat'] * 1000 >= user.tokens_valid_after_timestamp +def test_verify_id_token_disabled(new_user, api_key): + custom_token = auth.create_custom_token(new_user.uid) + id_token = _sign_in(custom_token, api_key) + claims = auth.verify_id_token(id_token, check_revoked=True) + + # Disable the user record. + auth.update_user(new_user.uid, disabled=True) + # Verify the ID token without checking revocation. This should + # not raise. + claims = auth.verify_id_token(id_token, check_revoked=False) + assert claims['sub'] == new_user.uid + + # Verify the ID token while checking revocation. This should + # raise an exception. + with pytest.raises(auth.UserDisabledError) as excinfo: + auth.verify_id_token(id_token, check_revoked=True) + assert str(excinfo.value) == 'The user record is disabled.' + def test_verify_session_cookie_revoked(new_user, api_key): custom_token = auth.create_custom_token(new_user.uid) id_token = _sign_in(custom_token, api_key) @@ -591,6 +609,24 @@ def test_verify_session_cookie_revoked(new_user, api_key): claims = auth.verify_session_cookie(session_cookie, check_revoked=True) assert claims['iat'] * 1000 >= user.tokens_valid_after_timestamp +def test_verify_session_cookie_disabled(new_user, api_key): + custom_token = auth.create_custom_token(new_user.uid) + id_token = _sign_in(custom_token, api_key) + session_cookie = auth.create_session_cookie(id_token, expires_in=datetime.timedelta(days=1)) + + # Disable the user record. + auth.update_user(new_user.uid, disabled=True) + # Verify the session cookie without checking revocation. This should + # not raise. + claims = auth.verify_session_cookie(session_cookie, check_revoked=False) + assert claims['sub'] == new_user.uid + + # Verify the session cookie while checking revocation. This should + # raise an exception. + with pytest.raises(auth.UserDisabledError) as excinfo: + auth.verify_session_cookie(session_cookie, check_revoked=True) + assert str(excinfo.value) == 'The user record is disabled.' + def test_import_users(): uid, email = _random_id() user = auth.ImportUserRecord(uid=uid, email=email) diff --git a/snippets/auth/index.py b/snippets/auth/index.py index 9de9cfa03..9d6f29ebd 100644 --- a/snippets/auth/index.py +++ b/snippets/auth/index.py @@ -150,6 +150,9 @@ def verify_token_uid_check_revoke(id_token): except auth.RevokedIdTokenError: # Token revoked, inform the user to reauthenticate or signOut(). pass + except auth.UserDisabledError: + # Token belongs to a disabled user record. + pass except auth.InvalidIdTokenError: # Token is invalid pass @@ -1027,6 +1030,9 @@ def verify_id_token_and_check_revoked_tenant(tenant_client, id_token): except auth.RevokedIdTokenError: # Token revoked, inform the user to reauthenticate or signOut(). pass + except auth.UserDisabledError: + # Token belongs to a disabled user record. + pass except auth.InvalidIdTokenError: # Token is invalid pass diff --git a/tests/test_token_gen.py b/tests/test_token_gen.py index 0a09862ab..436fadaae 100644 --- a/tests/test_token_gen.py +++ b/tests/test_token_gen.py @@ -208,6 +208,12 @@ def revoked_tokens(): mock_user['users'][0]['validSince'] = str(int(time.time())+100) return json.dumps(mock_user) +@pytest.fixture(scope='module') +def get_user_disabled_response(): + mock_user = json.loads(testutils.resource('get_user.json')) + mock_user['users'][0]['disabled'] = True + return json.dumps(mock_user) + class TestCreateCustomToken: @@ -471,6 +477,14 @@ def test_revoked_token_check_revoked(self, user_mgt_app, revoked_tokens, id_toke auth.verify_id_token(id_token, app=user_mgt_app, check_revoked=True) assert str(excinfo.value) == 'The Firebase ID token has been revoked.' + @pytest.mark.parametrize('id_token', valid_tokens.values(), ids=list(valid_tokens)) + def test_disabled_user_check_revoked(self, user_mgt_app, get_user_disabled_response, id_token): + _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) + _instrument_user_manager(user_mgt_app, 200, get_user_disabled_response) + with pytest.raises(auth.UserDisabledError) as excinfo: + auth.verify_id_token(id_token, app=user_mgt_app, check_revoked=True) + assert str(excinfo.value) == 'The user record is disabled.' + @pytest.mark.parametrize('arg', INVALID_BOOLS) def test_invalid_check_revoked(self, user_mgt_app, arg): _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) @@ -485,6 +499,15 @@ def test_revoked_token_do_not_check_revoked(self, user_mgt_app, revoked_tokens, assert claims['admin'] is True assert claims['uid'] == claims['sub'] + @pytest.mark.parametrize('id_token', valid_tokens.values(), ids=list(valid_tokens)) + def test_disabled_user_do_not_check_disabled( + self, user_mgt_app, get_user_disabled_response, id_token): + _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) + _instrument_user_manager(user_mgt_app, 200, get_user_disabled_response) + claims = auth.verify_id_token(id_token, app=user_mgt_app, check_revoked=False) + assert claims['admin'] is True + assert claims['uid'] == claims['sub'] + @pytest.mark.parametrize('id_token', INVALID_JWT_ARGS.values(), ids=list(INVALID_JWT_ARGS)) def test_invalid_arg(self, user_mgt_app, id_token): _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) @@ -622,6 +645,21 @@ def test_revoked_cookie_does_not_check_revoked(self, user_mgt_app, revoked_token _instrument_user_manager(user_mgt_app, 200, revoked_tokens) self._assert_valid_cookie(cookie, app=user_mgt_app, check_revoked=False) + @pytest.mark.parametrize('cookie', valid_cookies.values(), ids=list(valid_cookies)) + def test_disabled_user_check_revoked(self, user_mgt_app, get_user_disabled_response, cookie): + _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) + _instrument_user_manager(user_mgt_app, 200, get_user_disabled_response) + with pytest.raises(auth.UserDisabledError) as excinfo: + auth.verify_session_cookie(cookie, app=user_mgt_app, check_revoked=True) + assert str(excinfo.value) == 'The user record is disabled.' + + @pytest.mark.parametrize('cookie', valid_cookies.values(), ids=list(valid_cookies)) + def test_disabled_user_does_not_check_disabled( + self, user_mgt_app, get_user_disabled_response, cookie): + _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) + _instrument_user_manager(user_mgt_app, 200, get_user_disabled_response) + self._assert_valid_cookie(cookie, app=user_mgt_app, check_revoked=False) + @pytest.mark.parametrize('cookie', INVALID_JWT_ARGS.values(), ids=list(INVALID_JWT_ARGS)) def test_invalid_args(self, user_mgt_app, cookie): _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) From cbb5b8dad05f5a17e0b540cfadfa58bc0466f86b Mon Sep 17 00:00:00 2001 From: Bassam Ojeil Date: Tue, 3 Aug 2021 23:39:28 -0700 Subject: [PATCH 2/4] Fix test names. --- tests/test_token_gen.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_token_gen.py b/tests/test_token_gen.py index 436fadaae..e06bb6e88 100644 --- a/tests/test_token_gen.py +++ b/tests/test_token_gen.py @@ -500,7 +500,7 @@ def test_revoked_token_do_not_check_revoked(self, user_mgt_app, revoked_tokens, assert claims['uid'] == claims['sub'] @pytest.mark.parametrize('id_token', valid_tokens.values(), ids=list(valid_tokens)) - def test_disabled_user_do_not_check_disabled( + def test_disabled_user_do_not_check_revoked( self, user_mgt_app, get_user_disabled_response, id_token): _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) _instrument_user_manager(user_mgt_app, 200, get_user_disabled_response) @@ -654,7 +654,7 @@ def test_disabled_user_check_revoked(self, user_mgt_app, get_user_disabled_respo assert str(excinfo.value) == 'The user record is disabled.' @pytest.mark.parametrize('cookie', valid_cookies.values(), ids=list(valid_cookies)) - def test_disabled_user_does_not_check_disabled( + def test_disabled_user_does_not_check_revoked( self, user_mgt_app, get_user_disabled_response, cookie): _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) _instrument_user_manager(user_mgt_app, 200, get_user_disabled_response) From 8e23e2af5b50df66e2680fd79e0635835e027854 Mon Sep 17 00:00:00 2001 From: Bassam Ojeil Date: Wed, 4 Aug 2021 12:39:11 -0700 Subject: [PATCH 3/4] Addresses review comments. --- firebase_admin/_auth_client.py | 4 +-- firebase_admin/_auth_utils.py | 4 +-- tests/test_token_gen.py | 47 ++++++++++++++++++++++++++-------- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/firebase_admin/_auth_client.py b/firebase_admin/_auth_client.py index ba4558acb..4418a034d 100644 --- a/firebase_admin/_auth_client.py +++ b/firebase_admin/_auth_client.py @@ -726,7 +726,7 @@ def list_saml_provider_configs( def _check_jwt_revoked_or_disabled(self, verified_claims, exc_type, label): user = self.get_user(verified_claims.get('uid')) - if verified_claims.get('iat') * 1000 < user.tokens_valid_after_timestamp: - raise exc_type('The Firebase {0} has been revoked.'.format(label)) if user.disabled: raise _auth_utils.UserDisabledError('The user record is disabled.') + if verified_claims.get('iat') * 1000 < user.tokens_valid_after_timestamp: + raise exc_type('The Firebase {0} has been revoked.'.format(label)) diff --git a/firebase_admin/_auth_utils.py b/firebase_admin/_auth_utils.py index 5a4e62593..e368342e8 100644 --- a/firebase_admin/_auth_utils.py +++ b/firebase_admin/_auth_utils.py @@ -385,13 +385,13 @@ def __init__(self, message, cause=None, http_response=None): exceptions.NotFoundError.__init__(self, message, cause, http_response) -class UserDisabledError(exceptions.FailedPreconditionError): +class UserDisabledError(exceptions.InvalidArgumentError): """An operation failed due to a user record being disabled.""" default_message = 'The user record is disabled' def __init__(self, message, cause=None, http_response=None): - exceptions.FailedPreconditionError.__init__(self, message, cause, http_response) + exceptions.InvalidArgumentError.__init__(self, message, cause, http_response) _CODE_TO_EXC_TYPE = { diff --git a/tests/test_token_gen.py b/tests/test_token_gen.py index e06bb6e88..85bfb0e27 100644 --- a/tests/test_token_gen.py +++ b/tests/test_token_gen.py @@ -209,11 +209,18 @@ def revoked_tokens(): return json.dumps(mock_user) @pytest.fixture(scope='module') -def get_user_disabled_response(): +def user_disabled(): mock_user = json.loads(testutils.resource('get_user.json')) mock_user['users'][0]['disabled'] = True return json.dumps(mock_user) +@pytest.fixture(scope='module') +def user_disabled_and_revoked(): + mock_user = json.loads(testutils.resource('get_user.json')) + mock_user['users'][0]['disabled'] = True + mock_user['users'][0]['validSince'] = str(int(time.time())+100) + return json.dumps(mock_user) + class TestCreateCustomToken: @@ -478,9 +485,19 @@ def test_revoked_token_check_revoked(self, user_mgt_app, revoked_tokens, id_toke assert str(excinfo.value) == 'The Firebase ID token has been revoked.' @pytest.mark.parametrize('id_token', valid_tokens.values(), ids=list(valid_tokens)) - def test_disabled_user_check_revoked(self, user_mgt_app, get_user_disabled_response, id_token): + def test_disabled_user_check_revoked(self, user_mgt_app, user_disabled, id_token): + _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) + _instrument_user_manager(user_mgt_app, 200, user_disabled) + with pytest.raises(auth.UserDisabledError) as excinfo: + auth.verify_id_token(id_token, app=user_mgt_app, check_revoked=True) + assert str(excinfo.value) == 'The user record is disabled.' + + @pytest.mark.parametrize('id_token', valid_tokens.values(), ids=list(valid_tokens)) + def test_disabled_revoked_check_revoked( + self, user_mgt_app, user_disabled_and_revoked, id_token): _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) - _instrument_user_manager(user_mgt_app, 200, get_user_disabled_response) + _instrument_user_manager(user_mgt_app, 200, user_disabled_and_revoked) + # User disabled check should have higher priority. with pytest.raises(auth.UserDisabledError) as excinfo: auth.verify_id_token(id_token, app=user_mgt_app, check_revoked=True) assert str(excinfo.value) == 'The user record is disabled.' @@ -500,10 +517,9 @@ def test_revoked_token_do_not_check_revoked(self, user_mgt_app, revoked_tokens, assert claims['uid'] == claims['sub'] @pytest.mark.parametrize('id_token', valid_tokens.values(), ids=list(valid_tokens)) - def test_disabled_user_do_not_check_revoked( - self, user_mgt_app, get_user_disabled_response, id_token): + def test_disabled_user_do_not_check_revoked(self, user_mgt_app, user_disabled, id_token): _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) - _instrument_user_manager(user_mgt_app, 200, get_user_disabled_response) + _instrument_user_manager(user_mgt_app, 200, user_disabled) claims = auth.verify_id_token(id_token, app=user_mgt_app, check_revoked=False) assert claims['admin'] is True assert claims['uid'] == claims['sub'] @@ -646,18 +662,27 @@ def test_revoked_cookie_does_not_check_revoked(self, user_mgt_app, revoked_token self._assert_valid_cookie(cookie, app=user_mgt_app, check_revoked=False) @pytest.mark.parametrize('cookie', valid_cookies.values(), ids=list(valid_cookies)) - def test_disabled_user_check_revoked(self, user_mgt_app, get_user_disabled_response, cookie): + def test_disabled_user_check_revoked(self, user_mgt_app, user_disabled, cookie): + _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) + _instrument_user_manager(user_mgt_app, 200, user_disabled) + with pytest.raises(auth.UserDisabledError) as excinfo: + auth.verify_session_cookie(cookie, app=user_mgt_app, check_revoked=True) + assert str(excinfo.value) == 'The user record is disabled.' + + @pytest.mark.parametrize('cookie', valid_cookies.values(), ids=list(valid_cookies)) + def test_disabled_revoked_check_revoked( + self, user_mgt_app, user_disabled_and_revoked, cookie): _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) - _instrument_user_manager(user_mgt_app, 200, get_user_disabled_response) + _instrument_user_manager(user_mgt_app, 200, user_disabled_and_revoked) + # User disabled check should have higher priority. with pytest.raises(auth.UserDisabledError) as excinfo: auth.verify_session_cookie(cookie, app=user_mgt_app, check_revoked=True) assert str(excinfo.value) == 'The user record is disabled.' @pytest.mark.parametrize('cookie', valid_cookies.values(), ids=list(valid_cookies)) - def test_disabled_user_does_not_check_revoked( - self, user_mgt_app, get_user_disabled_response, cookie): + def test_disabled_user_does_not_check_revoked(self, user_mgt_app, user_disabled, cookie): _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) - _instrument_user_manager(user_mgt_app, 200, get_user_disabled_response) + _instrument_user_manager(user_mgt_app, 200, user_disabled) self._assert_valid_cookie(cookie, app=user_mgt_app, check_revoked=False) @pytest.mark.parametrize('cookie', INVALID_JWT_ARGS.values(), ids=list(INVALID_JWT_ARGS)) From ff7132f45b869cb9e043d7380a1e1ffaf2e49bee Mon Sep 17 00:00:00 2001 From: Bassam Ojeil Date: Wed, 4 Aug 2021 13:29:13 -0700 Subject: [PATCH 4/4] Renames unclear unit test names. --- tests/test_token_gen.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/test_token_gen.py b/tests/test_token_gen.py index 85bfb0e27..00b7956fa 100644 --- a/tests/test_token_gen.py +++ b/tests/test_token_gen.py @@ -493,11 +493,10 @@ def test_disabled_user_check_revoked(self, user_mgt_app, user_disabled, id_token assert str(excinfo.value) == 'The user record is disabled.' @pytest.mark.parametrize('id_token', valid_tokens.values(), ids=list(valid_tokens)) - def test_disabled_revoked_check_revoked( + def test_check_disabled_before_revoked( self, user_mgt_app, user_disabled_and_revoked, id_token): _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) _instrument_user_manager(user_mgt_app, 200, user_disabled_and_revoked) - # User disabled check should have higher priority. with pytest.raises(auth.UserDisabledError) as excinfo: auth.verify_id_token(id_token, app=user_mgt_app, check_revoked=True) assert str(excinfo.value) == 'The user record is disabled.' @@ -670,11 +669,10 @@ def test_disabled_user_check_revoked(self, user_mgt_app, user_disabled, cookie): assert str(excinfo.value) == 'The user record is disabled.' @pytest.mark.parametrize('cookie', valid_cookies.values(), ids=list(valid_cookies)) - def test_disabled_revoked_check_revoked( + def test_check_disabled_before_revoked( self, user_mgt_app, user_disabled_and_revoked, cookie): _overwrite_cert_request(user_mgt_app, MOCK_REQUEST) _instrument_user_manager(user_mgt_app, 200, user_disabled_and_revoked) - # User disabled check should have higher priority. with pytest.raises(auth.UserDisabledError) as excinfo: auth.verify_session_cookie(cookie, app=user_mgt_app, check_revoked=True) assert str(excinfo.value) == 'The user record is disabled.'