Skip to content

Commit 67d2ff5

Browse files
committed
[DOP-31004] Change Keycloak cookie settings location
1 parent 0c52f4e commit 67d2ff5

File tree

18 files changed

+225
-219
lines changed

18 files changed

+225
-219
lines changed

config.docker.yml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@ auth:
1919
# Keycloak Auth
2020
# provider: syncmaster.server.providers.auth.keycloak_provider.KeycloakAuthProvider
2121
# keycloak:
22-
# server_url: http://keycloak:8080
22+
# api_url: http://keycloak:8080/auth
2323
# realm_name: manually_created
2424
# client_id: manually_created
2525
# client_secret: generated_by_keycloak
26-
# redirect_uri: http://localhost:3000/auth/callback
26+
# ui_auth_callback_url: http://localhost:3000/auth/callback
2727
# scope: email
2828
# verify_ssl: False
29+
# cookie:
30+
# secret_key: generate_some_random_string
31+
# max_age: 86400
2932

3033

3134
ui:
@@ -37,11 +40,6 @@ ui:
3740
server:
3841
debug: true # !!! NEVER USE ON PRODUCTION !!!
3942

40-
session:
41-
enabled: true
42-
secret_key: generate_some_random_string
43-
max_age: 86400
44-
4543
cors:
4644
enabled: true
4745

config.yml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@ auth:
1919
# Keycloak Auth
2020
# provider: syncmaster.server.providers.auth.keycloak_provider.KeycloakAuthProvider
2121
# keycloak:
22-
# server_url: http://localhost:8080
22+
# api_url: http://localhost:8080/auth
2323
# realm_name: manually_created
2424
# client_id: manually_created
2525
# client_secret: generated_by_keycloak
26-
# redirect_uri: http://localhost:3000/auth/callback
26+
# ui_auth_callback_url: http://localhost:3000/auth/callback
2727
# scope: email
2828
# verify_ssl: False
29+
# cookie:
30+
# secret_key: generate_some_random_string
31+
# max_age: 86400
2932

3033

3134
ui:
@@ -37,11 +40,6 @@ ui:
3740
server:
3841
debug: true # !!! NEVER USE ON PRODUCTION !!!
3942

40-
session:
41-
enabled: true
42-
secret_key: generate_some_random_string
43-
max_age: 86400
44-
4543
cors:
4644
enabled: true
4745
allow_origins: [http://localhost:3000]
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
Move ``server.session`` middleware settings to ``auth`` block.
2+
Also rename some fields in ``auth.keycloak`` settings block.
3+
4+
Before:
5+
6+
.. code:: yaml
7+
8+
auth:
9+
provider: ...
10+
keycloak:
11+
server_url: ...
12+
redirect_url: ...
13+
14+
server:
15+
session:
16+
enabled: true
17+
secret_key: ...
18+
19+
Now:
20+
21+
.. code:: yaml
22+
23+
auth:
24+
provider:
25+
keycloak:
26+
api_url: ...
27+
ui_auth_callback_endpoint: ...
28+
cookie:
29+
secret_key:

docs/reference/server/auth/keycloak/local_installation.rst

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ Configure Redirect URI
7676

7777
Set URI to redirect from Keycloak login page for exchanging the code for an access token:
7878

79-
.. image:: images/keycloak-client-redirect_uri.png
79+
.. image:: images/keycloak-client-ui_auth_callback_endpoint.png
8080
:width: 400px
8181
:align: center
8282

@@ -86,7 +86,7 @@ Set URI to redirect from Keycloak login page for exchanging the code for an acce
8686
auth:
8787
keycloak:
8888
# Set here URL of SyncMaster UI page handling callback redirects
89-
redirect_uri: http://localhost:3000/auth/callback
89+
ui_auth_callback_endpoint: http://localhost:3000/auth/callback
9090
# ...
9191
9292
Configure the client secret
@@ -108,17 +108,17 @@ Now go to **Credentials** tab and generate a client secret:
108108
109109
Now you can use create users in this realm, check `Keycloak documentation <https://www.keycloak.org/docs/latest/server_admin/#assembly-managing-users_server_administration_guide>`_ on how to manage users creation.
110110

111-
Enable session middleware
112-
~~~~~~~~~~~~~~~~~~~~~~~~~
111+
Cookie encryption secret
112+
~~~~~~~~~~~~~~~~~~~~~~~~
113113

114-
Enable :ref:`SesionMiddleware <server-configuration-session>`, and generate random string to use for cookie encryption.
114+
Keycloak access & refresh tokens are stored in cookie with server-side encryption.
115+
So we need to generate random string to use as encryption key:
115116

116117
.. code-block:: yaml
117118
:caption: config.yml
118119
119-
server:
120-
session:
121-
enabled: true
120+
auth:
121+
cookie:
122122
secret_key: secret_key_for_session_cookie
123123
124124
Replace login page with Keycloak redirect button
@@ -132,8 +132,7 @@ Replace login page with Keycloak redirect button
132132
:caption: config.yml
133133
134134
ui:
135-
# required by KeycloakAuthProvider
136-
auth_provider: keycloakAuth
135+
auth_provider: keycloakAuthProvider
137136
138137
Final configuration
139138
~~~~~~~~~~~~~~~~~~~
@@ -147,23 +146,18 @@ After this you can use ``KeycloakAuthProvider`` in your application:
147146
provider: syncmaster.server.providers.auth.keycloak_provider.KeycloakAuthProvider
148147
keycloak:
149148
# Keycloak URL accessible from both SyncMaster server and from browser
150-
server_url: http://keycloak:8080
149+
api_url: http://keycloak:8080
151150
# Set here URL of SyncMaster UI page handling callback redirects
152-
redirect_uri: http://localhost:3000/auth/callback
151+
ui_auth_callback_endpoint: http://localhost:3000/auth/callback
153152
realm_name: fastapi_realm
154153
client_id: fastapi_client
155154
client_secret: 6x6gn8uJdWSBmP8FqbNRSoGdvaoaFeez
156155
scope: email
157156
verify_ssl: false
158-
159-
server:
160-
session:
161-
# required by KeycloakAuthProvider
162-
enabled: true
157+
cookie:
163158
secret_key: secret_key_for_session_cookie
164159
165160
ui:
166-
# required by KeycloakAuthProvider
167-
auth_provider: keycloakAuth
161+
auth_provider: keycloakAuthProvider
168162
# SyncMaster API URL, accessible from browser
169163
api_browser_url: http://localhost:8000

docs/reference/server/configuration/index.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ Configuration
1212
broker
1313
credentials
1414
logging
15-
session
1615
cors
1716
debug
1817
monitoring

docs/reference/server/configuration/session.rst

Lines changed: 0 additions & 8 deletions
This file was deleted.

syncmaster/server/middlewares/__init__.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
)
1010
from syncmaster.server.middlewares.openapi import apply_openapi_middleware
1111
from syncmaster.server.middlewares.request_id import apply_request_id_middleware
12-
from syncmaster.server.middlewares.session import apply_session_middleware
1312
from syncmaster.server.middlewares.static_files import apply_static_files
1413
from syncmaster.server.settings import ServerAppSettings as Settings
1514

@@ -25,6 +24,5 @@ def apply_middlewares(
2524
apply_request_id_middleware(application, settings.server.request_id)
2625
apply_openapi_middleware(application, settings.server.openapi)
2726
apply_static_files(application, settings.server.static_files)
28-
apply_session_middleware(application, settings.server.session)
2927

3028
return application

syncmaster/server/middlewares/session.py

Lines changed: 0 additions & 19 deletions
This file was deleted.

syncmaster/server/providers/auth/keycloak_provider.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from fastapi import Depends, FastAPI, Request
77
from jwcrypto.common import JWException
88
from keycloak import KeycloakOpenID, KeycloakOperationError
9+
from starlette.middleware.sessions import SessionMiddleware
910

1011
from syncmaster.db.models.user import User
1112
from syncmaster.exceptions import EntityNotFoundError
@@ -28,7 +29,7 @@ def __init__(
2829
self.settings = settings
2930
self._uow = unit_of_work
3031
self.keycloak_openid = KeycloakOpenID(
31-
server_url=self.settings.keycloak.server_url,
32+
server_url=str(self.settings.keycloak.api_url).rstrip("/") + "/", # noqa: WPS336
3233
client_id=self.settings.keycloak.client_id,
3334
realm_name=self.settings.keycloak.realm_name,
3435
client_secret_key=self.settings.keycloak.client_secret.get_secret_value(),
@@ -41,6 +42,17 @@ def setup(cls, app: FastAPI) -> FastAPI:
4142
log.info("Using %s provider with settings:\n%s", cls.__name__, settings)
4243
app.dependency_overrides[AuthProvider] = cls
4344
app.dependency_overrides[KeycloakAuthProviderSettings] = lambda: settings
45+
46+
app.add_middleware(
47+
SessionMiddleware,
48+
secret_key=settings.cookie.secret_key.get_secret_value(),
49+
session_cookie=settings.cookie.cookie_name,
50+
max_age=settings.cookie.max_age,
51+
path=settings.cookie.path,
52+
same_site=settings.cookie.same_site,
53+
https_only=settings.cookie.https_only,
54+
domain=settings.cookie.domain,
55+
)
4456
return app
4557

4658
async def get_token_password_grant(
@@ -67,7 +79,7 @@ async def get_token_authorization_code_grant(
6779
return await self.keycloak_openid.a_token(
6880
grant_type="authorization_code",
6981
code=code,
70-
redirect_uri=self.settings.keycloak.redirect_uri,
82+
redirect_uri=self.settings.keycloak.ui_auth_callback_endpoint,
7183
)
7284
except KeycloakOperationError as e:
7385
raise AuthorizationError("Failed to get token") from e
@@ -135,7 +147,7 @@ async def get_current_user(self, access_token: str | None, request: Request) ->
135147

136148
async def redirect_to_auth(self) -> NoReturn:
137149
auth_url = await self.keycloak_openid.a_auth_url(
138-
redirect_uri=self.settings.keycloak.redirect_uri,
150+
redirect_uri=self.settings.keycloak.ui_auth_callback_endpoint,
139151
scope=self.settings.keycloak.scope,
140152
)
141153
raise RedirectException(redirect_url=auth_url)

syncmaster/server/providers/auth/oauth2_gateway_provider.py

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,34 @@
44
from typing import Annotated, Any
55

66
from fastapi import Depends, FastAPI, Request
7+
from keycloak import KeycloakOpenID, KeycloakOperationError
78

89
from syncmaster.db.models import User
910
from syncmaster.exceptions import EntityNotFoundError
1011
from syncmaster.exceptions.auth import AuthorizationError
1112
from syncmaster.server.dependencies import Stub
1213
from syncmaster.server.providers.auth.base_provider import AuthProvider
13-
from syncmaster.server.providers.auth.keycloak_provider import (
14-
KeycloakAuthProvider,
15-
KeycloakOperationError,
16-
)
1714
from syncmaster.server.services.unit_of_work import UnitOfWork
1815
from syncmaster.server.settings.auth.oauth2_gateway import OAuth2GatewayProviderSettings
1916

2017
log = logging.getLogger(__name__)
2118

2219

23-
class OAuth2GatewayProvider(KeycloakAuthProvider):
20+
class OAuth2GatewayProvider(AuthProvider):
2421
def __init__( # noqa: WPS612
2522
self,
2623
settings: Annotated[OAuth2GatewayProviderSettings, Depends(Stub(OAuth2GatewayProviderSettings))],
2724
unit_of_work: Annotated[UnitOfWork, Depends()],
2825
) -> None:
29-
super().__init__(settings, unit_of_work) # type: ignore[arg-type]
26+
self.settings = settings
27+
self._uow = unit_of_work
28+
self.keycloak_openid = KeycloakOpenID(
29+
server_url=str(self.settings.keycloak.api_url).rstrip("/") + "/", # noqa: WPS336
30+
client_id=self.settings.keycloak.client_id,
31+
realm_name=self.settings.keycloak.realm_name,
32+
client_secret_key=self.settings.keycloak.client_secret.get_secret_value(),
33+
verify=self.settings.keycloak.verify_ssl,
34+
)
3035

3136
@classmethod
3237
def setup(cls, app: FastAPI) -> FastAPI:
@@ -81,6 +86,19 @@ async def get_current_user( # noqa: WPS231, WPS217, WPS238
8186
)
8287
return user
8388

89+
async def get_token_password_grant(
90+
self,
91+
grant_type: str | None = None,
92+
login: str | None = None,
93+
password: str | None = None,
94+
scopes: list[str] | None = None,
95+
client_id: str | None = None,
96+
client_secret: str | None = None,
97+
) -> dict[str, Any]:
98+
raise NotImplementedError(
99+
f"Password grant is not supported by {self.__class__.__name__}.", # noqa: WPS237
100+
)
101+
84102
async def get_token_authorization_code_grant(
85103
self,
86104
code: str,

0 commit comments

Comments
 (0)