Skip to content

Commit 579d82a

Browse files
committed
Updating authenticators from latest in Tiled
1 parent be0025b commit 579d82a

File tree

5 files changed

+365
-173
lines changed

5 files changed

+365
-173
lines changed

bluesky_httpserver/app.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from fastapi.middleware.cors import CORSMiddleware
1616
from fastapi.openapi.utils import get_openapi
1717

18-
from .authentication import Mode
18+
from .authentication import ExternalAuthenticator, InternalAuthenticator
1919
from .console_output import CollectPublishedConsoleOutput, ConsoleOutputStream, SystemInfoStream
2020
from .core import PatchedStreamingResponse
2121
from .database.core import purge_expired
@@ -179,20 +179,19 @@ def build_app(authentication=None, api_access=None, resource_access=None, server
179179
for spec in authentication["providers"]:
180180
provider = spec["provider"]
181181
authenticator = spec["authenticator"]
182-
mode = authenticator.mode
183-
if mode == Mode.password:
182+
if isinstance(authenticator, InternalAuthenticator):
184183
authentication_router.post(f"/provider/{provider}/token")(
185184
build_handle_credentials_route(authenticator, provider)
186185
)
187-
elif mode == Mode.external:
186+
elif isinstance(authenticator, ExternalAuthenticator):
188187
authentication_router.get(f"/provider/{provider}/code")(
189188
build_auth_code_route(authenticator, provider)
190189
)
191190
authentication_router.post(f"/provider/{provider}/code")(
192191
build_auth_code_route(authenticator, provider)
193192
)
194193
else:
195-
raise ValueError(f"unknown authentication mode {mode}")
194+
raise ValueError(f"unknown authenticator type {type(authenticator)}")
196195
for custom_router in getattr(authenticator, "include_routers", []):
197196
authentication_router.include_router(custom_router, prefix=f"/provider/{provider}")
198197

bluesky_httpserver/authentication.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131
from pydantic_settings import BaseSettings
3232

3333
from . import schemas
34+
from .authentication.authenticator_base import (
35+
ExternalAuthenticator,
36+
InternalAuthenticator,
37+
UserSessionState,
38+
)
3439
from .authorization._defaults import _DEFAULT_ANONYMOUS_PROVIDER_NAME
3540
from .core import json_or_msgpack
3641
from .database import orm
@@ -54,12 +59,6 @@ def utcnow():
5459
"UTC now with second resolution"
5560
return datetime.utcnow().replace(microsecond=0)
5661

57-
58-
class Mode(enum.Enum):
59-
password = "password"
60-
external = "external"
61-
62-
6362
class Token(BaseModel):
6463
access_token: str
6564
token_type: str
@@ -421,7 +420,8 @@ async def auth_code(
421420
api_access_manager=Depends(get_api_access_manager),
422421
):
423422
request.state.endpoint = "auth"
424-
username = await authenticator.authenticate(request)
423+
user_session_state = await authenticator.authenticate(request)
424+
username = user_session_state.user_name if user_session_state else None
425425

426426
if username and api_access_manager.is_user_known(username):
427427
scopes = api_access_manager.get_user_scopes(username)
@@ -450,7 +450,8 @@ async def handle_credentials(
450450
api_access_manager=Depends(get_api_access_manager),
451451
):
452452
request.state.endpoint = "auth"
453-
username = await authenticator.authenticate(username=form_data.username, password=form_data.password)
453+
user_session_state = await authenticator.authenticate(username=form_data.username, password=form_data.password)
454+
username = user_session_state.user_name if user_session_state else None
454455

455456
err_msg = None
456457
if not username:
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from .authenticator_base import (
2+
ExternalAuthenticator,
3+
InternalAuthenticator,
4+
UserSessionState,
5+
)
6+
7+
__all__ = [
8+
"ExternalAuthenticator",
9+
"InternalAuthenticator",
10+
"UserSessionState",
11+
]
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
from abc import ABC
2+
from dataclasses import dataclass
3+
from typing import Optional
4+
5+
from fastapi import Request
6+
7+
8+
@dataclass
9+
class UserSessionState:
10+
"""Data transfer class to communicate custom session state information."""
11+
12+
user_name: str
13+
state: dict = None
14+
15+
16+
class InternalAuthenticator(ABC):
17+
"""
18+
Base class for authenticators that use username/password credentials.
19+
20+
Subclasses must implement the authenticate method which takes a username
21+
and password and returns a UserSessionState on success or None on failure.
22+
"""
23+
24+
async def authenticate(
25+
self, username: str, password: str
26+
) -> Optional[UserSessionState]:
27+
raise NotImplementedError
28+
29+
30+
class ExternalAuthenticator(ABC):
31+
"""
32+
Base class for authenticators that use external identity providers.
33+
34+
Subclasses must implement the authenticate method which takes a FastAPI
35+
Request object and returns a UserSessionState on success or None on failure.
36+
"""
37+
38+
async def authenticate(self, request: Request) -> Optional[UserSessionState]:
39+
raise NotImplementedError

0 commit comments

Comments
 (0)