Skip to content

Commit

Permalink
fix service proxying
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidBuchanan314 committed Jan 22, 2025
1 parent ce168c0 commit 53ebf02
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 26 deletions.
3 changes: 2 additions & 1 deletion src/millipds/appview_proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ async def service_proxy(request: web.Request, service: Optional[str] = None):
service_route = db.config["bsky_appview_pfx"]

auth_headers = {
"Authorization": "Bearer " + build_service_auth_token(request, service_did, lxm, 60)
"Authorization": "Bearer "
+ build_service_auth_token(request, service_did, lxm, 60)
}
if request.method == "GET":
async with get_client(request).get(
Expand Down
22 changes: 13 additions & 9 deletions src/millipds/auth_bearer.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,9 @@ def symmetric_token_auth(

def auth_required(required_scopes: Set[str] = set(), revoke: bool = False):
def decorator(handler):
async def wrapper(request: web.Request):
async def wrapper(request: web.Request, *args, **kwargs):
if not request.get("authed_did"):
raise web.HTTPUnauthorized(
text=f"auth required"
)
raise web.HTTPUnauthorized(text=f"auth required")

authed_scopes = request.get("authed_scopes", set())
missing_scopes = required_scopes - authed_scopes
Expand All @@ -100,7 +98,7 @@ async def wrapper(request: web.Request):
),
)

return await handler(request)
return await handler(request, *args, **kwargs)

return wrapper

Expand Down Expand Up @@ -177,16 +175,22 @@ async def auth_middleware(request: web.Request, handler):

# everything checks out
request["authed_did"] = did
request["authed_scopes"] = set(payload.get("scope", "atproto").split(" "))
request["authed_scopes"] = set(
payload.get("scope", "atproto").split(" ")
)

return await handler(request)


# used for both service proxying, and getServiceAuth
def build_service_auth_token(request: web.Request, aud: str, lxm: str, duration: int) -> str:
def build_service_auth_token(
request: web.Request, aud: str, lxm: str, duration: int
) -> str:
if lxm.startswith("chat.bsky."):
if "transition:chat.bsky" not in request["authed_scopes"]:
raise web.HTTPUnauthorized(text=f"`transition:chat.bsky` scope required for lxm {lxm}")
raise web.HTTPUnauthorized(
text=f"`transition:chat.bsky` scope required for lxm {lxm}"
)

now = int(time.time())
signing_key = get_db(request).signing_key_pem_by_did(request["authed_did"])
Expand All @@ -199,7 +203,7 @@ def build_service_auth_token(request: web.Request, aud: str, lxm: str, duration:
"exp": now + duration,
"iat": now,
"jti": str(uuid.uuid4()),
"scope": " ".join(request.get("authed_scopes", {}))
"scope": " ".join(request.get("authed_scopes", {})),
},
signing_key,
algorithm=crypto.jwt_signature_alg_for_pem(signing_key),
Expand Down
17 changes: 6 additions & 11 deletions src/millipds/auth_oauth.py
Original file line number Diff line number Diff line change
Expand Up @@ -548,18 +548,13 @@ async def dpop_middlware(request: web.Request, handler):
)

if decoded.get("nonce") != DPOP_NONCE:
raise web.HTTPBadRequest(
body=json.dumps(
{
"error": "use_dpop_nonce",
"error_description": "Authorization server requires nonce in DPoP proof",
}
),
headers={
"DPoP-Nonce": DPOP_NONCE,
"Content-Type": "application/json",
}, # if we don't put it here, the client will never see it
res = util.atproto_json_http_error(
web.HTTPBadRequest,
"use_dpop_nonce",
"Authorization server requires nonce in DPoP proof",
)
res.headers["DPoP-Nonce"] = DPOP_NONCE
raise res

# TODO: check for jti reuse!!! (and revoke the one we're using here)

Expand Down
12 changes: 7 additions & 5 deletions src/millipds/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@
from . import crypto
from . import util
from .appview_proxy import service_proxy
from .auth_bearer import auth_required, build_service_auth_token, auth_middleware
from .auth_bearer import (
auth_required,
build_service_auth_token,
auth_middleware,
)
from .app_util import *
from .did import DIDResolver

Expand Down Expand Up @@ -209,7 +213,7 @@ def session_info(request: web.Request) -> dict:
"did": request["authed_did"],
# we specify a fake email and claim it's verified, because otherwise
# bsky.app would nag us to verify it
#"email": "[email protected]",
# "email": "[email protected]",
"emailConfirmed": True,
# "didDoc": {}, # iiuc this is only used for entryway usecase?
}
Expand Down Expand Up @@ -330,9 +334,7 @@ async def server_get_service_auth(request: web.Request):
# TODO: strict validation of aud and lxm?

return web.json_response(
{
"token": build_service_auth_token(request, aud, lxm, duration)
}
{"token": build_service_auth_token(request, aud, lxm, duration)}
)


Expand Down

0 comments on commit 53ebf02

Please sign in to comment.