| #!/usr/bin/env python3 |
| |
| import time |
| import re |
| |
| import pytest |
| import quart |
| |
| import asfquart.auth |
| from asfquart.auth import Requirements as R |
| |
| |
| def _string_to_re(s): |
| """convert arbitrary string to fullmatch regex""" |
| return re.escape(s) + '$' |
| |
| @pytest.mark.auth |
| async def test_auth_basics(): |
| app = asfquart.construct("foobar", token_file=None) |
| |
| # Generic auth test, just requires a valid session |
| @asfquart.auth.require |
| async def requires_session(): |
| pass |
| |
| # Test with no session, should fail |
| quart.session = {} |
| with pytest.raises(asfquart.auth.AuthenticationFailed, match=_string_to_re(R.E_NOT_LOGGED_IN)): |
| await requires_session() |
| |
| # Test with session, should work. |
| quart.session = {app.app_id: {"uts": time.time(), "foo": "bar"}} |
| await requires_session() |
| |
| # Test with a bad requirement, should fail with a TypeError. |
| with pytest.raises(TypeError): |
| @asfquart.auth.require({R.member, print}) |
| async def requires_bad_thing(): |
| pass |
| # Same bad one, but with explicit any_of |
| with pytest.raises(TypeError): |
| @asfquart.auth.require(any_of={R.member, print}) |
| async def requires_bad_thingy(): |
| pass |
| |
| |
| @pytest.mark.auth |
| async def test_mfa_auth(): |
| """MFA tests""" |
| |
| app = asfquart.construct("foobar", token_file=None) |
| |
| @asfquart.auth.require(R.mfa_enabled) |
| async def requires_mfa(): |
| pass |
| |
| # Test MFA with no session, should fail exactly like auth_required |
| quart.session = {} |
| with pytest.raises(asfquart.auth.AuthenticationFailed, match=_string_to_re(R.E_NOT_LOGGED_IN)): |
| await requires_mfa() |
| |
| # Test with session without MFA, should fail. |
| quart.session = {app.app_id: {"uts": time.time(), "foo": "bar"}} |
| with pytest.raises(asfquart.auth.AuthenticationFailed, match=_string_to_re(R.E_NO_MFA)): |
| await requires_mfa() |
| |
| # Test with session with MFA, should work. |
| quart.session = {app.app_id: {"uts": time.time(), "foo": "bar", "mfa": True}} |
| await requires_mfa() |
| |
| |
| @pytest.mark.auth |
| async def test_role_auth(): |
| """Role tests""" |
| |
| app = asfquart.construct("foobar", token_file=None) |
| |
| # Set up some role tests |
| @asfquart.auth.require # no args implies any valid account |
| async def test_committer_auth(): |
| pass |
| |
| @asfquart.auth.require(R.member) |
| async def test_member_auth(): |
| pass |
| |
| @asfquart.auth.require({R.member, R.chair}) |
| async def test_member_and_chair_auth(): |
| pass |
| |
| @asfquart.auth.require(any_of={R.member, R.chair}) |
| async def test_member_or_chair_auth(): |
| pass |
| |
| # Test role with no session, should fail exactly like auth_required |
| quart.session = {} |
| with pytest.raises(asfquart.auth.AuthenticationFailed, match=_string_to_re(R.E_NOT_LOGGED_IN)): |
| await test_committer_auth() |
| |
| # Test with session , should work |
| quart.session = {app.app_id: {"uts": time.time(), "foo": "bar"}} |
| await test_committer_auth() |
| |
| # Test with a role we don't have, should fail |
| with pytest.raises(asfquart.auth.AuthenticationFailed, match=_string_to_re(R.E_NOT_MEMBER)): |
| await test_member_auth() |
| |
| # Test with for both member and chair, while only being member. should pass on member check, fail on chair |
| quart.session = {app.app_id: {"uts": time.time(), "foo": "bar", "isMember": True}} |
| with pytest.raises(asfquart.auth.AuthenticationFailed, match=_string_to_re(R.E_NOT_CHAIR)): |
| await test_member_and_chair_auth() |
| |
| # Test for either member of chair, should work as we have chair (but not member) |
| quart.session = {app.app_id: {"uts": time.time(), "foo": "bar", "isChair": True}} |
| await test_member_or_chair_auth() |
| |
| # Test for both member and chair, when we are both. should work. |
| quart.session = {app.app_id: {"uts": time.time(), "foo": "bar", "isMember": True, "isChair": True}} |
| await test_member_and_chair_auth() |