Skip to content

Commit 2586214

Browse files
committed
Revert "rm asset signing logic"
This reverts commit 9ce9cad.
1 parent 9ce9cad commit 2586214

File tree

3 files changed

+69
-1
lines changed

3 files changed

+69
-1
lines changed

src/stac_auth_proxy/app.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from starlette_cramjam.middleware import CompressionMiddleware
1414

1515
from .config import Settings
16-
from .handlers import HealthzHandler, ReverseProxyHandler
16+
from .handlers import HealthzHandler, ReverseProxyHandler, S3AssetSigner
1717
from .middleware import (
1818
AddProcessTimeHeaderMiddleware,
1919
ApplyCql2FilterMiddleware,
@@ -60,6 +60,14 @@ async def lifespan(app: FastAPI):
6060
prefix=settings.healthz_prefix,
6161
)
6262

63+
if settings.signer_endpoint:
64+
# TODO: Warn/error if endpoint is public
65+
app.add_api_route(
66+
settings.signer_endpoint,
67+
S3AssetSigner(bucket_pattern=settings.signer_asset_expression).endpoint,
68+
methods=["POST"],
69+
)
70+
6371
app.add_api_route(
6472
"/{path:path}",
6573
ReverseProxyHandler(upstream=str(settings.upstream_url)).proxy_request,
@@ -71,6 +79,8 @@ async def lifespan(app: FastAPI):
7179
#
7280
app.add_middleware(
7381
AuthenticationExtensionMiddleware,
82+
signing_endpoint=settings.signer_endpoint,
83+
signed_asset_expression=settings.signer_asset_expression,
7484
default_public=settings.default_public,
7585
public_endpoints=settings.public_endpoints,
7686
private_endpoints=settings.private_endpoints,

src/stac_auth_proxy/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,9 @@ class Settings(BaseSettings):
4444
healthz_prefix: str = Field(pattern=_PREFIX_PATTERN, default="/healthz")
4545
openapi_spec_endpoint: Optional[str] = Field(pattern=_PREFIX_PATTERN, default=None)
4646

47+
signer_endpoint: Optional[str] = Field(pattern=_PREFIX_PATTERN, default=None)
48+
signer_asset_expression: str = Field(default=r"^s3://.*$")
49+
4750
# Auth
4851
default_public: bool = False
4952
public_endpoints: EndpointMethodsNoScope = {

src/stac_auth_proxy/middleware/AuthenticationExtensionMiddleware.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,15 @@ class AuthenticationExtensionMiddleware(JsonResponseMiddleware):
2525

2626
app: ASGIApp
2727

28+
signing_endpoint: Optional[str]
29+
signed_asset_expression: str
30+
2831
default_public: bool
2932
private_endpoints: EndpointMethods
3033
public_endpoints: EndpointMethods
3134

3235
oidc_config_url: Optional[HttpUrl] = None
36+
signing_scheme_name: str = "signed_url_auth"
3337
auth_scheme_name: str = "oauth"
3438
auth_scheme: dict[str, Any] = field(default_factory=dict)
3539
extension_url: str = (
@@ -84,9 +88,60 @@ def transform_json(self, doc: dict[str, Any]) -> dict[str, Any]:
8488
scheme_loc = doc["properties"] if "properties" in doc else doc
8589
schemes = scheme_loc.setdefault("auth:schemes", {})
8690
schemes[self.auth_scheme_name] = self.auth_scheme
91+
if self.signing_endpoint:
92+
schemes[self.signing_scheme_name] = {
93+
"type": "signedUrl",
94+
"description": "Requires an authentication API",
95+
"flows": {
96+
"authorizationCode": {
97+
"authorizationApi": self.signing_endpoint,
98+
"method": "POST",
99+
"parameters": {
100+
"bucket": {
101+
"in": "body",
102+
"required": True,
103+
"description": "asset bucket",
104+
"schema": {
105+
"type": "string",
106+
"examples": "example-bucket",
107+
},
108+
},
109+
"key": {
110+
"in": "body",
111+
"required": True,
112+
"description": "asset key",
113+
"schema": {
114+
"type": "string",
115+
"examples": "path/to/example/asset.xyz",
116+
},
117+
},
118+
},
119+
"responseField": "signed_url",
120+
}
121+
},
122+
}
87123

88124
# auth:refs
89125
# ---
126+
# Annotate assets with "auth:refs": [signing_scheme]
127+
if self.signing_endpoint:
128+
assets = chain(
129+
# Item
130+
doc.get("assets", {}).values(),
131+
# Items/Search
132+
(
133+
asset
134+
for item in doc.get("features", [])
135+
for asset in item.get("assets", {}).values()
136+
),
137+
)
138+
for asset in assets:
139+
if "href" not in asset:
140+
logger.warning("Asset %s has no href", asset)
141+
continue
142+
if re.match(self.signed_asset_expression, asset["href"]):
143+
asset.setdefault("auth:refs", []).append(self.signing_scheme_name)
144+
90145
# Annotate links with "auth:refs": [auth_scheme]
91146
links = chain(
92147
# Item/Collection

0 commit comments

Comments
 (0)