fix: require a matching Origin on consent and name the binding cookie per flow (SEC-17, SEC-19)
This commit is contained in:
1 parent
8be859243d
commit
782d416e46
5 files changed
+306
-19
No files matched your search
@@ -129,6 +129,16 @@ def same_resource(left: str, right: str) -> bool:
|
||||
return normalized[0] == normalized[1]
|
||||
|
||||
|
||||
def flow_tag(state: str) -> str:
|
||||
"""Eight hex characters derived from a Gitea ``state`` (names the browser-binding cookie).
|
||||
|
||||
Concurrent sign-ins in one browser each get their own cookie, so a second flow
|
||||
cannot overwrite the binding of the first. The tag is public (it is a hash
|
||||
prefix of a value that is in the callback URL anyway) and grants nothing.
|
||||
"""
|
||||
return token_hash(state)[:8]
|
||||
|
||||
|
||||
def s256(verifier: str) -> str:
|
||||
"""PKCE S256 challenge for ``verifier``."""
|
||||
digest = hashlib.sha256(verifier.encode("ascii")).digest()
|
||||
@@ -214,6 +224,8 @@ class ConsentDecision:
|
||||
|
||||
redirect: str = field(repr=False)
|
||||
binding_token: str | None = field(default=None, repr=False)
|
||||
#: Short public tag of the Gitea state, used to name this flow's binding cookie.
|
||||
flow_tag: str | None = None
|
||||
|
||||
|
||||
class GiteaOAuthProvider(
|
||||
@@ -438,7 +450,7 @@ class GiteaOAuthProvider(
|
||||
location = self._upstream.authorize_url(
|
||||
state=state, code_challenge=s256(pending.code_verifier)
|
||||
)
|
||||
return ConsentDecision(redirect=location, binding_token=binding)
|
||||
return ConsentDecision(redirect=location, binding_token=binding, flow_tag=flow_tag(state))
|
||||
|
||||
async def complete_callback(
|
||||
self, state: str, binding: str, code: str, error: str
|
||||
|
||||
Reference in new issue
Block a user