Skip to content

Commit ceaa08b

Browse files
tpoliawdanielballan
authored andcommitted
Use common base type for all access policy types
1 parent d3eae59 commit ceaa08b

File tree

8 files changed

+65
-53
lines changed

8 files changed

+65
-53
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@ Write the date in place of the "Unreleased" in the case a new version is release
44
# Changelog
55

66

7-
## Unreleased
7+
## v0.2.0 (Unreleased)
88

99
### Fixed
1010

1111
- Column names in `TableStructure` are explicitly converted to strings.
1212

13+
### Refactored
14+
15+
- Use common base type for all access policy types
16+
1317

1418
## v0.1.6 (2025-09-29)
1519

tiled/access_control/access_policies.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
from ..queries import AccessBlobFilter
55
from ..utils import Sentinel, import_object
6+
from .protocols import AccessPolicy
67
from .scopes import ALL_SCOPES, PUBLIC_SCOPES
78

89
ALL_ACCESS = Sentinel("ALL_ACCESS")
@@ -20,7 +21,7 @@
2021
logger.setLevel(log_level.upper())
2122

2223

23-
class DummyAccessPolicy:
24+
class DummyAccessPolicy(AccessPolicy):
2425
"Impose no access restrictions."
2526

2627
async def allowed_scopes(self, node, principal, authn_access_tags, authn_scopes):
@@ -30,7 +31,7 @@ async def filters(self, node, principal, authn_access_tags, authn_scopes, scopes
3031
return []
3132

3233

33-
class TagBasedAccessPolicy:
34+
class TagBasedAccessPolicy(AccessPolicy):
3435
def __init__(
3536
self,
3637
*,

tiled/access_control/protocols.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
from abc import ABC, abstractmethod
2+
from typing import Any, Optional, Set
3+
4+
from ..adapters.protocols import BaseAdapter
5+
from ..server.schemas import Principal
6+
from ..type_aliases import Filters, Scopes
7+
8+
9+
class AccessPolicy(ABC):
10+
@abstractmethod
11+
async def allowed_scopes(
12+
self,
13+
node: BaseAdapter,
14+
principal: Principal,
15+
authn_access_tags: Optional[Set[str]],
16+
authn_scopes: Scopes,
17+
) -> Scopes:
18+
pass
19+
20+
@abstractmethod
21+
async def filters(
22+
self,
23+
node: BaseAdapter,
24+
principal: Principal,
25+
authn_access_tags: Optional[Set[str]],
26+
authn_scopes: Scopes,
27+
scopes: Scopes,
28+
) -> Filters:
29+
pass
30+
31+
async def modify_node(
32+
self,
33+
node: BaseAdapter,
34+
principal: Principal,
35+
authn_scopes: Scopes,
36+
access_blob: Optional[dict[str, Any]],
37+
) -> tuple[bool, Optional[dict[str, Any]]]:
38+
return (False, access_blob)

tiled/adapters/protocols.py

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,13 @@
88
from numpy.typing import NDArray
99

1010
from ..ndslice import NDSlice
11-
from ..server.schemas import Principal
1211
from ..storage import Storage
1312
from ..structures.array import ArrayStructure
1413
from ..structures.awkward import AwkwardStructure
1514
from ..structures.core import Spec, StructureFamily
1615
from ..structures.sparse import SparseStructure
1716
from ..structures.table import TableStructure
18-
from ..type_aliases import JSON, Filters, Scopes
17+
from ..type_aliases import JSON
1918
from .awkward_directory_container import DirectoryContainer
2019

2120

@@ -130,26 +129,3 @@ def __getitem__(self, key: str) -> ArrayAdapter:
130129
AnyAdapter = Union[
131130
ArrayAdapter, AwkwardAdapter, ContainerAdapter, SparseAdapter, TableAdapter
132131
]
133-
134-
135-
class AccessPolicy(Protocol):
136-
@abstractmethod
137-
async def allowed_scopes(
138-
self,
139-
node: BaseAdapter,
140-
principal: Principal,
141-
authn_access_tags: Optional[Set[str]],
142-
authn_scopes: Scopes,
143-
) -> Scopes:
144-
pass
145-
146-
@abstractmethod
147-
async def filters(
148-
self,
149-
node: BaseAdapter,
150-
principal: Principal,
151-
authn_access_tags: Optional[Set[str]],
152-
authn_scopes: Scopes,
153-
scopes: Scopes,
154-
) -> Filters:
155-
pass

tiled/server/app.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,7 @@
3636
HTTP_500_INTERNAL_SERVER_ERROR,
3737
)
3838

39-
from tiled.query_registration import QueryRegistry, default_query_registry
40-
from tiled.server.protocols import ExternalAuthenticator, InternalAuthenticator
41-
from tiled.type_aliases import AppTask, TaskMap
42-
39+
from ..access_control.protocols import AccessPolicy
4340
from ..catalog.adapter import WouldDeleteData
4441
from ..config import (
4542
Authentication,
@@ -60,8 +57,11 @@
6057
from ..validation_registration import ValidationRegistry, default_validation_registry
6158
from .authentication import move_api_key
6259
from .compression import CompressionMiddleware
60+
from .query_registration import QueryRegistry, default_query_registry
6361
from .router import get_metrics_router, get_router
62+
from .server.protocols import ExternalAuthenticator, InternalAuthenticator
6463
from .settings import Settings, get_settings
64+
from .type_aliases import AppTask, TaskMap
6565
from .utils import API_KEY_COOKIE_NAME, CSRF_COOKIE_NAME, get_root_url, record_timing
6666
from .zarr import get_zarr_router_v2, get_zarr_router_v3
6767

@@ -124,7 +124,7 @@ def build_app(
124124
validation_registry: Optional[ValidationRegistry] = None,
125125
tasks: Optional[dict[str, list[AppTask]]] = None,
126126
scalable=False,
127-
access_policy=None,
127+
access_policy: Optional[AccessPolicy] = None,
128128
):
129129
"""
130130
Serve a Tree
@@ -136,7 +136,7 @@ def build_app(
136136
Dict of authentication configuration.
137137
server_settings: dict, optional
138138
Dict of other server configuration.
139-
access_policy:
139+
access_policy: AccessPolicy, optional
140140
AccessPolicy object encoding rules for which users can see which entries.
141141
"""
142142
authentication = authentication or Authentication()

tiled/server/dependencies.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,13 @@
44
from fastapi import HTTPException, Query, Request
55
from starlette.status import HTTP_403_FORBIDDEN, HTTP_404_NOT_FOUND, HTTP_410_GONE
66

7-
from tiled.adapters.protocols import AnyAdapter
8-
from tiled.server.schemas import Principal
9-
from tiled.structures.core import StructureFamily
10-
7+
from ..access_control.protocols import AccessPolicy
8+
from ..adapters.protocols import AnyAdapter
9+
from ..structures.core import StructureFamily
1110
from ..type_aliases import Scopes
1211
from ..utils import BrokenLink
1312
from .core import NoEntry
13+
from .schemas import Principal
1414
from .utils import filter_for_access, record_timing
1515

1616

@@ -28,7 +28,7 @@ async def get_entry(
2828
session_state: dict,
2929
metrics: dict,
3030
structure_families: Optional[set[StructureFamily]] = None,
31-
access_policy=None,
31+
access_policy: Optional[AccessPolicy] = None,
3232
) -> AnyAdapter:
3333
"""
3434
Obtain a node in the tree from its path.
@@ -40,7 +40,6 @@ async def get_entry(
4040
"""
4141
path_parts = [segment for segment in path.split("/") if segment]
4242
entry = root_tree
43-
# access_policy = getattr(request.app.state, "access_policy", None)
4443
# If the entry/adapter can take a session state, pass it in.
4544
# The entry/adapter may return itself or a different object.
4645
if hasattr(entry, "with_session_state") and session_state:

tiled/server/router.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2021,14 +2021,11 @@ async def patch_metadata(
20212021
settings=settings,
20222022
)
20232023

2024-
if request.app.state.access_policy is not None and hasattr(
2024+
if policy := request.app.state.access_policy and hasattr(
20252025
request.app.state.access_policy, "modify_node"
20262026
):
20272027
try:
2028-
(
2029-
access_blob_modified,
2030-
access_blob,
2031-
) = await request.app.state.access_policy.modify_node(
2028+
(access_blob_modified, access_blob) = await policy.modify_node(
20322029
entry, principal, authn_access_tags, authn_scopes, access_blob
20332030
)
20342031
except ValueError as e:
@@ -2100,14 +2097,11 @@ async def put_metadata(
21002097
settings=settings,
21012098
)
21022099

2103-
if request.app.state.access_policy is not None and hasattr(
2100+
if policy := request.app.state.access_policy and hasattr(
21042101
request.app.state.access_policy, "modify_node"
21052102
):
21062103
try:
2107-
(
2108-
access_blob_modified,
2109-
access_blob,
2110-
) = await request.app.state.access_policy.modify_node(
2104+
(access_blob_modified, access_blob) = await policy.modify_node(
21112105
entry, principal, authn_access_tags, authn_scopes, access_blob
21122106
)
21132107
except ValueError as e:

tiled/server/utils.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import contextlib
22
import time
33
from collections.abc import Generator
4-
from typing import Any, Literal, Mapping, Optional, Sequence
4+
from typing import Any, Literal, Mapping, Optional, Sequence, Set
55

66
from fastapi import Request, WebSocket
77
from starlette.types import Scope
88

99
from ..access_control.access_policies import NO_ACCESS
10+
from ..access_control.protocols import AccessPolicy
1011
from ..adapters.mapping import MapAdapter
11-
from ..adapters.protocols import AccessPolicy
1212
from ..server.schemas import Principal
1313
from ..type_aliases import Scopes
1414

@@ -89,7 +89,7 @@ async def filter_for_access(
8989
entry,
9090
access_policy: Optional[AccessPolicy],
9191
principal: Principal,
92-
authn_access_tags,
92+
authn_access_tags: Optional[Set[str]],
9393
authn_scopes: Scopes,
9494
scopes: Sequence[str],
9595
metrics: dict[str, Any],

0 commit comments

Comments
 (0)