Record the sub claims as an external_id

This commit is contained in:
Quentin Gliech 2022-09-13 16:13:20 +02:00 committed by Patrick Cloke
parent 7628dbf4e9
commit f9cd549f64

View File

@ -68,6 +68,8 @@ class OAuthDelegatedAuth(BaseAuth):
"private_key_jwt": PrivateKeyJWTWithKid(), "private_key_jwt": PrivateKeyJWTWithKid(),
} }
EXTERNAL_ID_PROVIDER = "oauth-delegated"
def __init__(self, hs: "HomeServer"): def __init__(self, hs: "HomeServer"):
super().__init__(hs) super().__init__(hs)
@ -170,6 +172,18 @@ class OAuthDelegatedAuth(BaseAuth):
"Invalid access token", "Invalid access token",
) )
# Match via the sub claim
sub: Optional[str] = introspection_result.get("sub")
if sub is None:
raise AuthError(500, "Invalid sub claim in the introspection result")
user_id_str = await self.store.get_user_by_external_id(
OAuthDelegatedAuth.EXTERNAL_ID_PROVIDER, sub
)
if user_id_str is None:
# If we could not find a user via the external_id, it either does not exist,
# or the external_id was never recorded
# TODO: claim mapping should be configurable # TODO: claim mapping should be configurable
username: Optional[str] = introspection_result.get("username") username: Optional[str] = introspection_result.get("username")
if username is None or not isinstance(username, str): if username is None or not isinstance(username, str):
@ -177,6 +191,23 @@ class OAuthDelegatedAuth(BaseAuth):
500, 500,
"Invalid username claim in the introspection result", "Invalid username claim in the introspection result",
) )
user_id = UserID(username, self._hostname)
# First try to find a user from the username claim
user_info = await self.store.get_userinfo_by_id(user_id=user_id.to_string())
if user_info is None:
# If the user does not exist, we should create it on the fly
# TODO: we could use SCIM to provision users ahead of time and listen
# for SCIM SET events if those ever become standard:
# https://datatracker.ietf.org/doc/html/draft-hunt-scim-notify-00
await self.store.register_user(user_id=user_id.to_string())
# And record the sub as external_id
await self.store.record_user_external_id(
OAuthDelegatedAuth.EXTERNAL_ID_PROVIDER, sub, user_id.to_string()
)
else:
user_id = UserID.from_string(user_id_str)
# Let's look at the scope # Let's look at the scope
scope: List[str] = scope_to_list(introspection_result.get("scope", "")) scope: List[str] = scope_to_list(introspection_result.get("scope", ""))
@ -188,22 +219,6 @@ class OAuthDelegatedAuth(BaseAuth):
if len(parts) == 5: if len(parts) == 5:
device_id = parts[4] device_id = parts[4]
user_id = UserID(username, self._hostname)
user_info = await self.store.get_userinfo_by_id(user_id=user_id.to_string())
# If the user does not exist, we should create it on the fly
# TODO: we could use SCIM to provision users ahead of time and listen
# for SCIM SET events if those ever become standard:
# https://datatracker.ietf.org/doc/html/draft-hunt-scim-notify-00
if not user_info:
await self.store.register_user(user_id=user_id.to_string())
user_info = await self.store.get_userinfo_by_id(user_id=user_id.to_string())
if not user_info:
raise AuthError(
500,
"Could not create user on the fly",
)
if device_id: if device_id:
# Create the device on the fly if it does not exist # Create the device on the fly if it does not exist
try: try: