Skip to content

Commit ef38031

Browse files
committed
[DOP-23122] Use async methods of Keycloak client
1 parent 162b0a0 commit ef38031

File tree

4 files changed

+43
-18
lines changed

4 files changed

+43
-18
lines changed

syncmaster/server/providers/auth/base_provider.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def __init__(
5252
...
5353

5454
@abstractmethod
55-
async def get_current_user(self, access_token: Any, *args, **kwargs) -> User:
55+
async def get_current_user(self, access_token: str | None, **kwargs) -> User:
5656
"""
5757
This method should return currently logged in user.
5858

syncmaster/server/providers/auth/dummy_provider.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def setup(cls, app: FastAPI) -> FastAPI:
3737
app.dependency_overrides[DummyAuthProviderSettings] = lambda: settings
3838
return app
3939

40-
async def get_current_user(self, access_token: str, *args, **kwargs) -> User:
40+
async def get_current_user(self, access_token: str | None, **kwargs) -> User:
4141
if not access_token:
4242
raise AuthorizationError("Missing auth credentials")
4343

syncmaster/server/providers/auth/keycloak_provider.py

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from fastapi import Depends, FastAPI, Request
77
from keycloak import KeycloakOpenID
88

9+
from syncmaster.db.models import User
910
from syncmaster.exceptions import EntityNotFoundError
1011
from syncmaster.exceptions.auth import AuthorizationError
1112
from syncmaster.exceptions.redirect import RedirectException
@@ -63,7 +64,7 @@ async def get_token_authorization_code_grant(
6364
) -> dict[str, Any]:
6465
try:
6566
redirect_uri = redirect_uri or self.settings.keycloak.redirect_uri
66-
token = self.keycloak_openid.token(
67+
token = await self.keycloak_openid.a_token(
6768
grant_type="authorization_code",
6869
code=code,
6970
redirect_uri=redirect_uri,
@@ -72,10 +73,8 @@ async def get_token_authorization_code_grant(
7273
except Exception as e:
7374
raise AuthorizationError("Failed to get token") from e
7475

75-
async def get_current_user(self, access_token: str, *args, **kwargs) -> Any:
76+
async def get_current_user(self, access_token: str | None, **kwargs) -> User:
7677
request: Request = kwargs["request"]
77-
refresh_token = request.session.get("refresh_token")
78-
7978
if not access_token:
8079
log.debug("No access token found in session.")
8180
self.redirect_to_auth(request.url.path)
@@ -86,8 +85,9 @@ async def get_current_user(self, access_token: str, *args, **kwargs) -> Any:
8685
token_info = self.keycloak_openid.decode_token(token=access_token)
8786
except Exception as e:
8887
log.info("Access token is invalid or expired: %s", e)
89-
token_info = None
88+
token_info = {}
9089

90+
refresh_token = request.session.get("refresh_token")
9191
if not token_info and refresh_token:
9292
log.debug("Access token invalid. Attempting to refresh.")
9393

@@ -99,9 +99,7 @@ async def get_current_user(self, access_token: str, *args, **kwargs) -> Any:
9999
request.session["access_token"] = new_access_token
100100
request.session["refresh_token"] = new_refresh_token
101101

102-
token_info = self.keycloak_openid.decode_token(
103-
token=new_access_token,
104-
)
102+
token_info = self.keycloak_openid.decode_token(token=new_access_token)
105103
log.debug("Access token refreshed and decoded successfully.")
106104
except Exception as e:
107105
log.debug("Failed to refresh access token: %s", e)
@@ -110,19 +108,19 @@ async def get_current_user(self, access_token: str, *args, **kwargs) -> Any:
110108
# these names are hardcoded in keycloak:
111109
# https://github.com/keycloak/keycloak/blob/3ca3a4ad349b4d457f6829eaf2ae05f1e01408be/core/src/main/java/org/keycloak/representations/IDToken.java
112110
user_id = token_info.get("sub")
111+
if not user_id:
112+
raise AuthorizationError("Invalid token payload")
113+
113114
login = token_info.get("preferred_username")
114115
email = token_info.get("email")
115116
first_name = token_info.get("given_name")
116117
middle_name = token_info.get("middle_name")
117118
last_name = token_info.get("family_name")
118119

119-
if not user_id:
120-
raise AuthorizationError("Invalid token payload")
121-
122-
async with self._uow:
123-
try:
124-
user = await self._uow.user.read_by_username(login)
125-
except EntityNotFoundError:
120+
try:
121+
user = await self._uow.user.read_by_username(login)
122+
except EntityNotFoundError:
123+
async with self._uow:
126124
user = await self._uow.user.create(
127125
username=login,
128126
email=email,
@@ -134,7 +132,7 @@ async def get_current_user(self, access_token: str, *args, **kwargs) -> Any:
134132
return user
135133

136134
async def refresh_access_token(self, refresh_token: str) -> dict[str, Any]:
137-
new_tokens = self.keycloak_openid.refresh_token(refresh_token)
135+
new_tokens = await self.keycloak_openid.a_refresh_token(refresh_token)
138136
return new_tokens
139137

140138
def redirect_to_auth(self, path: str) -> None:
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# SPDX-FileCopyrightText: 2023-2024 MTS PJSC
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
from pydantic import BaseModel, Field, ImportString
5+
6+
7+
class AuthSettings(BaseModel):
8+
"""Authorization-related settings.
9+
10+
Here you can set auth provider class.
11+
12+
Examples
13+
--------
14+
15+
.. code-block:: bash
16+
17+
SYNCMASTER__AUTH__PROVIDER=syncmaster.server.providers.auth.dummy_provider.DummyAuthProvider
18+
"""
19+
20+
provider: ImportString = Field( # type: ignore[assignment]
21+
default="syncmaster.server.providers.auth.dummy_provider.DummyAuthProvider",
22+
description="Full name of auth provider class",
23+
validate_default=True,
24+
)
25+
26+
class Config:
27+
extra = "allow"

0 commit comments

Comments
 (0)