豆豆友情提示:这是一个非官方 GitHub 代理镜像,主要用于网络测试或访问加速。请勿在此进行登录、注册或处理任何敏感信息。进行这些操作请务必访问官方网站 github.com。 Raw 内容也通过此代理提供。
Skip to content

Commit 5efecee

Browse files
committed
Delete keycloak session and Django session if user is self logging out
1 parent 613347d commit 5efecee

File tree

3 files changed

+37
-14
lines changed

3 files changed

+37
-14
lines changed

assets/app/vue/views/MailView/views/SecuritySettingsView/components/AccountActivity.vue

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,10 @@ const signOut = async (id: string) => {
2424
if (window.confirm(t('views.mail.views.securitySettings.signOutConfirmation'))) {
2525
try {
2626
await signOutSession(id);
27-
window.location.href = '/';
27+
28+
// Reload to refresh the data
29+
// and auto-redirect to home in case the user signed themselves out
30+
window.location.reload();
2831
} catch (error) {
2932
console.log(error);
3033
errorMessage.value = t('views.mail.views.securitySettings.errorSigningOutSession', { error: error });

src/thunderbird_accounts/authentication/api.py

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import logging
2+
13
from rest_framework.decorators import api_view, authentication_classes
24
from rest_framework.authentication import SessionAuthentication
35
from rest_framework.exceptions import NotAuthenticated, ValidationError
46
from rest_framework.request import Request
57
from rest_framework.response import Response
68

9+
from thunderbird_accounts.authentication.middleware import AccountsOIDCBackend
710
from thunderbird_accounts.authentication.serializers import UserProfileSerializer
811
from thunderbird_accounts.authentication.clients import KeycloakClient
912

@@ -25,19 +28,10 @@ def get_active_sessions(request: Request):
2528
keycloak_client = KeycloakClient()
2629
sessions = keycloak_client.get_active_sessions(request.user.oidc_id)
2730

28-
# Print all keys from request.session
29-
print(request.session.keys())
30-
print(request.session.items())
31-
print(request.session.values())
32-
print(request.session.get('session_id'))
33-
print(request.session.get('session_key'))
34-
print(request.session.get('session_data'))
35-
print(request.session.get('session_expiry'))
36-
print(request.session.get('session_created'))
37-
print(request.session.get('session_updated'))
3831
return Response(sessions)
3932
except Exception as e:
40-
raise ValidationError(f'Error fetching active sessions: {e}')
33+
logging.exception(f'Error fetching active sessions: {e}')
34+
raise ValidationError('Error fetching active sessions')
4135

4236

4337
@api_view(['POST'])
@@ -51,8 +45,30 @@ def sign_out_session(request: Request):
5145
if not session_id:
5246
raise ValidationError('session_id is required')
5347

48+
oidc_id_token = request.session.get('oidc_id_token')
49+
50+
if not oidc_id_token:
51+
raise ValidationError('No oidc_id_token found in session')
52+
5453
try:
54+
# Sign out from the Keycloak session
5555
keycloak_client = KeycloakClient()
56-
return Response(keycloak_client.sign_out_session(session_id))
56+
keycloak_client.sign_out_session(session_id)
57+
58+
# Verify if the request's keycloak session_id matches the one in the ID token
59+
auth_backend = AccountsOIDCBackend()
60+
payload = auth_backend.verify_token(oidc_id_token)
61+
keycloak_session_id = payload.get('sid')
62+
63+
if not keycloak_session_id:
64+
raise ValidationError("'sid' claim not found in ID token. Did you enable back-channel logout in Keycloak?")
65+
66+
if keycloak_session_id == session_id:
67+
# If so, delete current session data and cookie from Django as well
68+
request.session.flush()
69+
70+
return Response({'success': True})
71+
5772
except Exception as e:
58-
raise ValidationError(f'Error signing out session: {e}')
73+
logging.exception(f'Error signing out session: {e}')
74+
raise ValidationError('Error signing out session')

src/thunderbird_accounts/settings.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,8 @@ def before_send(event: Event, hint: Hint) -> Event | None:
323323
OIDC_OP_JWKS_ENDPOINT = os.getenv('OIDC_URL_JWKS')
324324
OIDC_STORE_ACCESS_TOKEN = True # Needed to talk to jmap
325325
ALLOW_LOGOUT_GET_METHOD = True
326+
OIDC_STORE_ID_TOKEN = True # Needed to store the ID token in the session for session verification
327+
OIDC_USE_NONCE = False # Needed for .verify_token() check on the OIDC backend for session verification
326328

327329
def oidc_logout(request):
328330
return f'{os.getenv("OIDC_URL_LOGOUT")}?client_id={OIDC_RP_CLIENT_ID}'
@@ -346,6 +348,8 @@ def oidc_logout(request):
346348
OIDC_OP_TOKEN_ENDPOINT = None
347349
OIDC_OP_USER_ENDPOINT = None
348350
OIDC_OP_JWKS_ENDPOINT = None
351+
OIDC_STORE_ID_TOKEN = None
352+
OIDC_USE_NONCE = None
349353

350354
STALWART_BASE_JMAP_URL = os.getenv('STALWART_BASE_JMAP_URL')
351355
STALWART_BASE_API_URL = os.getenv('STALWART_BASE_API_URL')

0 commit comments

Comments
 (0)