mirror of
https://gitlab.archlinux.org/archlinux/aurweb.git
synced 2025-02-03 10:43:03 +01:00
aurweb.auth: add user credentials and matcher functions
This clones the behavior already present in the PHP implementation, but it uses a global dict with credential constant keys to validation functions to determine if a given user has a credential. Signed-off-by: Kevin Morris <kevr@0cost.org>
This commit is contained in:
parent
670f711b59
commit
07d5907ecd
4 changed files with 154 additions and 1 deletions
101
aurweb/auth.py
101
aurweb/auth.py
|
@ -17,6 +17,10 @@ class AnonymousUser:
|
|||
def is_authenticated():
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def has_credential(credential):
|
||||
return False
|
||||
|
||||
|
||||
class BasicAuthBackend(AuthenticationBackend):
|
||||
async def authenticate(self, conn: HTTPConnection):
|
||||
|
@ -75,3 +79,100 @@ def auth_required(is_required: bool = True,
|
|||
return wrapper
|
||||
|
||||
return decorator
|
||||
|
||||
|
||||
CRED_ACCOUNT_CHANGE_TYPE = 1
|
||||
CRED_ACCOUNT_EDIT = 2
|
||||
CRED_ACCOUNT_EDIT_DEV = 3
|
||||
CRED_ACCOUNT_LAST_LOGIN = 4
|
||||
CRED_ACCOUNT_SEARCH = 5
|
||||
CRED_ACCOUNT_LIST_COMMENTS = 28
|
||||
CRED_COMMENT_DELETE = 6
|
||||
CRED_COMMENT_UNDELETE = 27
|
||||
CRED_COMMENT_VIEW_DELETED = 22
|
||||
CRED_COMMENT_EDIT = 25
|
||||
CRED_COMMENT_PIN = 26
|
||||
CRED_PKGBASE_ADOPT = 7
|
||||
CRED_PKGBASE_SET_KEYWORDS = 8
|
||||
CRED_PKGBASE_DELETE = 9
|
||||
CRED_PKGBASE_DISOWN = 10
|
||||
CRED_PKGBASE_EDIT_COMAINTAINERS = 24
|
||||
CRED_PKGBASE_FLAG = 11
|
||||
CRED_PKGBASE_LIST_VOTERS = 12
|
||||
CRED_PKGBASE_NOTIFY = 13
|
||||
CRED_PKGBASE_UNFLAG = 15
|
||||
CRED_PKGBASE_VOTE = 16
|
||||
CRED_PKGREQ_FILE = 23
|
||||
CRED_PKGREQ_CLOSE = 17
|
||||
CRED_PKGREQ_LIST = 18
|
||||
CRED_TU_ADD_VOTE = 19
|
||||
CRED_TU_LIST_VOTES = 20
|
||||
CRED_TU_VOTE = 21
|
||||
|
||||
|
||||
def has_any(user, *account_types):
|
||||
return str(user.AccountType) in set(account_types)
|
||||
|
||||
|
||||
def user_developer_or_trusted_user(user):
|
||||
return has_any(user, "User", "Trusted User", "Developer",
|
||||
"Trusted User & Developer")
|
||||
|
||||
|
||||
def trusted_user(user):
|
||||
return has_any(user, "Trusted User", "Trusted User & Developer")
|
||||
|
||||
|
||||
def developer(user):
|
||||
return has_any(user, "Developer", "Trusted User & Developer")
|
||||
|
||||
|
||||
def trusted_user_or_dev(user):
|
||||
return has_any(user, "Trusted User", "Developer",
|
||||
"Trusted User & Developer")
|
||||
|
||||
|
||||
# A mapping of functions that users must pass to have credentials.
|
||||
cred_filters = {
|
||||
CRED_PKGBASE_FLAG: user_developer_or_trusted_user,
|
||||
CRED_PKGBASE_NOTIFY: user_developer_or_trusted_user,
|
||||
CRED_PKGBASE_VOTE: user_developer_or_trusted_user,
|
||||
CRED_PKGREQ_FILE: user_developer_or_trusted_user,
|
||||
CRED_ACCOUNT_CHANGE_TYPE: trusted_user_or_dev,
|
||||
CRED_ACCOUNT_EDIT: trusted_user_or_dev,
|
||||
CRED_ACCOUNT_LAST_LOGIN: trusted_user_or_dev,
|
||||
CRED_ACCOUNT_LIST_COMMENTS: trusted_user_or_dev,
|
||||
CRED_ACCOUNT_SEARCH: trusted_user_or_dev,
|
||||
CRED_COMMENT_DELETE: trusted_user_or_dev,
|
||||
CRED_COMMENT_UNDELETE: trusted_user_or_dev,
|
||||
CRED_COMMENT_VIEW_DELETED: trusted_user_or_dev,
|
||||
CRED_COMMENT_EDIT: trusted_user_or_dev,
|
||||
CRED_COMMENT_PIN: trusted_user_or_dev,
|
||||
CRED_PKGBASE_ADOPT: trusted_user_or_dev,
|
||||
CRED_PKGBASE_SET_KEYWORDS: trusted_user_or_dev,
|
||||
CRED_PKGBASE_DELETE: trusted_user_or_dev,
|
||||
CRED_PKGBASE_EDIT_COMAINTAINERS: trusted_user_or_dev,
|
||||
CRED_PKGBASE_DISOWN: trusted_user_or_dev,
|
||||
CRED_PKGBASE_LIST_VOTERS: trusted_user_or_dev,
|
||||
CRED_PKGBASE_UNFLAG: trusted_user_or_dev,
|
||||
CRED_PKGREQ_CLOSE: trusted_user_or_dev,
|
||||
CRED_PKGREQ_LIST: trusted_user_or_dev,
|
||||
CRED_TU_ADD_VOTE: trusted_user,
|
||||
CRED_TU_LIST_VOTES: trusted_user,
|
||||
CRED_TU_VOTE: trusted_user,
|
||||
CRED_ACCOUNT_EDIT_DEV: developer,
|
||||
}
|
||||
|
||||
|
||||
def has_credential(user: User,
|
||||
credential: int,
|
||||
approved_users: list = tuple()):
|
||||
|
||||
if user in approved_users:
|
||||
return True
|
||||
|
||||
if credential in cred_filters:
|
||||
cred_filter = cred_filters.get(credential)
|
||||
return cred_filter(user)
|
||||
|
||||
return False
|
||||
|
|
|
@ -141,6 +141,11 @@ class User:
|
|||
request.cookies["AURSID"] = self.session.SessionID
|
||||
return self.session.SessionID
|
||||
|
||||
def has_credential(self, credential: str, approved: list = tuple()):
|
||||
import aurweb.auth
|
||||
cred = getattr(aurweb.auth, credential)
|
||||
return aurweb.auth.has_credential(self, cred, approved)
|
||||
|
||||
def logout(self, request):
|
||||
from aurweb.db import session
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@ import pytest
|
|||
|
||||
from starlette.authentication import AuthenticationError
|
||||
|
||||
from aurweb.auth import BasicAuthBackend, has_credential
|
||||
from aurweb.db import query
|
||||
from aurweb.auth import BasicAuthBackend
|
||||
from aurweb.models.account_type import AccountType
|
||||
from aurweb.testing import setup_test_db
|
||||
from aurweb.testing.models import make_session, make_user
|
||||
|
@ -78,3 +78,8 @@ async def test_basic_auth_backend():
|
|||
LastUpdateTS=now_ts + 5)
|
||||
_, result = await backend.authenticate(request)
|
||||
assert result == user
|
||||
|
||||
|
||||
def test_has_fake_credential_fails():
|
||||
# Fake credential 666 does not exist.
|
||||
assert not has_credential(user, 666)
|
||||
|
|
|
@ -163,6 +163,11 @@ def test_user_minimum_passwd_length():
|
|||
assert User.minimum_passwd_length() == passwd_min_len
|
||||
|
||||
|
||||
def test_user_has_credential():
|
||||
assert user.has_credential("CRED_PKGBASE_FLAG")
|
||||
assert not user.has_credential("CRED_ACCOUNT_CHANGE_TYPE")
|
||||
|
||||
|
||||
def test_user_ssh_pub_key():
|
||||
from aurweb.db import session
|
||||
|
||||
|
@ -178,3 +183,40 @@ def test_user_ssh_pub_key():
|
|||
|
||||
session.delete(ssh_pub_key)
|
||||
session.commit()
|
||||
|
||||
|
||||
def test_user_credential_types():
|
||||
from aurweb.db import session
|
||||
|
||||
assert aurweb.auth.user_developer_or_trusted_user(user)
|
||||
assert not aurweb.auth.trusted_user(user)
|
||||
assert not aurweb.auth.developer(user)
|
||||
assert not aurweb.auth.trusted_user_or_dev(user)
|
||||
|
||||
trusted_user_type = query(AccountType,
|
||||
AccountType.AccountType == "Trusted User")\
|
||||
.first()
|
||||
user.AccountType = trusted_user_type
|
||||
session.commit()
|
||||
|
||||
assert aurweb.auth.trusted_user(user)
|
||||
assert aurweb.auth.trusted_user_or_dev(user)
|
||||
|
||||
developer_type = query(AccountType,
|
||||
AccountType.AccountType == "Developer")\
|
||||
.first()
|
||||
user.AccountType = developer_type
|
||||
session.commit()
|
||||
|
||||
assert aurweb.auth.developer(user)
|
||||
assert aurweb.auth.trusted_user_or_dev(user)
|
||||
|
||||
type_str = "Trusted User & Developer"
|
||||
elevated_type = query(AccountType,
|
||||
AccountType.AccountType == type_str).first()
|
||||
user.AccountType = elevated_type
|
||||
session.commit()
|
||||
|
||||
assert aurweb.auth.trusted_user(user)
|
||||
assert aurweb.auth.developer(user)
|
||||
assert aurweb.auth.trusted_user_or_dev(user)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue