-
-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Revamp admin authentication dashboard with built-in permission
- Loading branch information
1 parent
209497c
commit 85e65ea
Showing
9 changed files
with
134 additions
and
32 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
from fief.models import Permission, Role | ||
from fief.repositories import PermissionRepository, RoleRepository | ||
|
||
ADMIN_PERMISSION_CODENAME = "fief:admin" | ||
ADMIN_PERMISSION_NAME = "Fief Administrator" | ||
ADMIN_ROLE_NAME = "Administrator" | ||
|
||
|
||
async def init_admin_role( | ||
role_repository: RoleRepository, permission_repository: PermissionRepository | ||
) -> Role: | ||
permission = await permission_repository.create( | ||
Permission(name=ADMIN_PERMISSION_NAME, codename=ADMIN_PERMISSION_CODENAME) | ||
) | ||
role = await role_repository.create( | ||
Role(name=ADMIN_ROLE_NAME, permissions=[permission], user_permissions=[]) | ||
) | ||
return role | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,6 +41,11 @@ | |
Webhook, | ||
WebhookLog, | ||
) | ||
from fief.services.admin import ( | ||
ADMIN_PERMISSION_CODENAME, | ||
ADMIN_PERMISSION_NAME, | ||
ADMIN_ROLE_NAME, | ||
) | ||
from fief.services.email import AvailableEmailProvider | ||
from fief.services.email_template.types import EmailTemplateType | ||
from fief.services.oauth_provider import AvailableOAuthProvider | ||
|
@@ -313,6 +318,15 @@ class TestData(TypedDict): | |
} | ||
|
||
users: ModelMapping[User] = { | ||
"admin": User( | ||
id=uuid.uuid4(), | ||
created_at=datetime.now(tz=UTC), | ||
email="[email protected]", | ||
email_verified=True, | ||
user_field_values=[], | ||
hashed_password=hashed_password, | ||
tenant=tenants["default"], | ||
), | ||
"regular": User( | ||
id=uuid.uuid4(), | ||
created_at=datetime.now(tz=UTC), | ||
|
@@ -813,6 +827,10 @@ class TestData(TypedDict): | |
} | ||
|
||
permissions: ModelMapping[Permission] = { | ||
ADMIN_PERMISSION_CODENAME: Permission( | ||
name=ADMIN_PERMISSION_NAME, | ||
codename=ADMIN_PERMISSION_CODENAME, | ||
), | ||
"castles:create": Permission( | ||
name="Create Castles", | ||
codename="castles:create", | ||
|
@@ -832,6 +850,11 @@ class TestData(TypedDict): | |
} | ||
|
||
roles: ModelMapping[Role] = { | ||
"fief_admin": Role( | ||
name=ADMIN_ROLE_NAME, | ||
granted_by_default=False, | ||
permissions=[permissions[ADMIN_PERMISSION_CODENAME]], | ||
), | ||
"castles_visitor": Role( | ||
name="Castles Visitor", | ||
granted_by_default=True, | ||
|
@@ -850,6 +873,11 @@ class TestData(TypedDict): | |
} | ||
|
||
user_permissions: ModelMapping[UserPermission] = { | ||
"admin": UserPermission( | ||
user=users["admin"], | ||
permission=permissions[ADMIN_PERMISSION_CODENAME], | ||
from_role=roles["fief_admin"], | ||
), | ||
"default_castles_visitor_from_role": UserPermission( | ||
user=users["regular"], | ||
permission=permissions["castles:read"], | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,10 +3,10 @@ | |
import httpx | ||
import pytest | ||
from fastapi import status | ||
from fief_client import FiefAccessTokenMissingPermission | ||
|
||
from fief.crypto.token import get_token_hash | ||
from fief.db import AsyncSession | ||
from fief.models import AdminSessionToken | ||
from fief.repositories import AdminSessionTokenRepository | ||
from fief.settings import settings | ||
from tests.helpers import HTTPXResponseAssertion | ||
|
@@ -44,6 +44,28 @@ async def test_missing_code(self, test_client_dashboard: httpx.AsyncClient): | |
|
||
assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY | ||
|
||
async def test_missing_permission( | ||
self, test_client_dashboard: httpx.AsyncClient, fief_client_mock: MagicMock | ||
): | ||
fief_client_mock.auth_callback.side_effect = AsyncMock( | ||
return_value=( | ||
{"access_token": "ACCESS_TOKEN", "id_token": "ID_TOKEN"}, | ||
{"email": "[email protected]"}, | ||
) | ||
) | ||
fief_client_mock.validate_access_token.side_effect = ( | ||
FiefAccessTokenMissingPermission() | ||
) | ||
|
||
response = await test_client_dashboard.get( | ||
"/auth/callback", params={"code": "CODE"} | ||
) | ||
|
||
assert response.status_code == status.HTTP_403_FORBIDDEN | ||
|
||
session_cookie = response.cookies.get(settings.fief_admin_session_cookie_name) | ||
assert session_cookie is None | ||
|
||
async def test_success( | ||
self, | ||
test_client_dashboard: httpx.AsyncClient, | ||
|
@@ -107,10 +129,15 @@ async def test_unauthorized(self, test_client_dashboard: httpx.AsyncClient): | |
async def test_valid( | ||
self, | ||
test_client_dashboard: httpx.AsyncClient, | ||
admin_session_token: tuple[AdminSessionToken, str], | ||
main_session: AsyncSession, | ||
fief_client_mock: MagicMock, | ||
): | ||
token = test_client_dashboard.cookies.get( | ||
settings.fief_admin_session_cookie_name | ||
) | ||
assert token is not None | ||
token_hash = get_token_hash(token) | ||
|
||
fief_client_mock.base_url = "https://bretagne.fief.dev" | ||
response = await test_client_dashboard.get("/auth/logout") | ||
|
||
|
@@ -125,7 +152,7 @@ async def test_valid( | |
assert "Set-Cookie" in response.headers | ||
|
||
admin_session_token_repository = AdminSessionTokenRepository(main_session) | ||
deleted_admin_session_token = await admin_session_token_repository.get_by_id( | ||
admin_session_token[0].id | ||
deleted_admin_session_token = await admin_session_token_repository.get_by_token( | ||
token_hash | ||
) | ||
assert deleted_admin_session_token is None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters