jharmon96 opened a new issue, #20339:
URL: https://github.com/apache/superset/issues/20339
A clear and concise description of what the bug is.
#### How to reproduce the bug
Backchannel logout sent from Keycloak OIDC server is failing. Login/Logout
via the UI both work fine.
The intention is to implement a Single Sign Out solution, where a user
logging out of another client application will cause them to logout of
Superset.
At the moment, when a user signs out of another application, Keycloak is
configured to send a POST request to Superset with the goal being that the
request logs the user out.
I have added the following to my superset_config.py:
```python
from flask import redirect, request
from flask_appbuilder.security.manager import AUTH_OID
from superset.security import SupersetSecurityManager
from flask_oidc import OpenIDConnect
from flask_appbuilder.security.views import AuthOIDView
from flask_login import login_user
from urllib.parse import quote
from flask_appbuilder.views import ModelView, SimpleFormView, expose
import logging
class AuthOIDCView(AuthOIDView):
@expose('/login/', methods=['GET', 'POST'])
def login(self, flag=True):
sm = self.appbuilder.sm
oidc = sm.oid
@self.appbuilder.sm.oid.require_login
def handle_login():
user = sm.auth_user_oid(oidc.user_getfield('email'))
if user is None:
info = oidc.user_getinfo(['preferred_username',
'given_name', 'family_name', 'email'])
user = sm.add_user(info.get('preferred_username'),
info.get('given_name'), info.get('family_name'),
info.get('email'), sm.find_role('Gamma'))
login_user(user, remember=False)
return redirect(self.appbuilder.get_url_for_index)
return handle_login()
@expose('/logout/', methods=['GET', 'POST'])
def logout(self):
oidc = self.appbuilder.sm.oid
oidc.logout()
super(AuthOIDCView, self).logout()
redirect_url = request.url_root.strip('/') +
self.appbuilder.get_url_for_login
# return redirect(oidc.client_secrets.get('issuer') +
'/protocol/openid-connect/logout?post_logout_redirect_uri=' +
quote(redirect_url, safe=''))
return redirect(oidc.client_secrets.get('issuer') +
'/protocol/openid-connect/logout')
@expose('/backchannel-logout/', methods=['GET', 'POST'])
def backchannel_logout(self):
oidc = self.appbuilder.sm.oid
oidc.logout()
super(AuthOIDCView, self).logout()
redirect_url = request.url_root.strip('/') +
self.appbuilder.get_url_for_login
return redirect(oidc.client_secrets.get('issuer') +
'/protocol/openid-connect/logout')
class OIDCSecurityManager(SupersetSecurityManager):
authoidview = AuthOIDCView
def __init__(self,appbuilder):
super(OIDCSecurityManager, self).__init__(appbuilder)
if self.auth_type == AUTH_OID:
self.oid = OpenIDConnect(self.appbuilder.get_app)
# Trying different variations here to get this to work
WTF_CSRF_EXEMPT_LIST.append("backchannel_logout")
WTF_CSRF_EXEMPT_LIST.append("backchannel-logout")
WTF_CSRF_EXEMPT_LIST.append("superset.backchannel_ogout")
WTF_CSRF_EXEMPT_LIST.append("superset.backchannel-logout")
AUTH_TYPE = AUTH_OID
OIDC_CLIENT_SECRETS='client_secret.json'
OIDC_ID_TOKEN_COOKIE_SECURE = False
OIDC_REQUIRE_VERIFIED_EMAIL = False
OIDC_CLOCK_SKEW = 560
OIDC_VALID_ISSUERS = 'https://auth.{{ .Values.global.domain }}/realms/{{
.Values.global.customerName }}'
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = 'Gamma'
CUSTOM_SECURITY_MANAGER = OIDCSecurityManager
OIDC_INTROSPECTION_AUTH_METHOD = 'client_secret_post'
OIDC_TOKEN_TYPE_HINT = 'access_token'
```
### Expected results
I expect that the POST request made against '/backchannel-logout/' would not
require a CSRF token.
### Actual results
I get the following message in my Superset server logs:
```
2022-06-09 22:39:19,480:INFO:flask_wtf.csrf:The CSRF token is missing.
400 Bad Request: The CSRF token is missing.
2022-06-09 22:39:19,480:WARNING:superset.views.base:400 Bad Request: The
CSRF token is missing.
10.244.0.133 - - [09/Jun/2022:22:39:19 +0000] "POST /backchannel-logout/
HTTP/1.1" 302 220 "-" "Apache-HttpClient/4.5.13 (Java/11.0.15)"
```
#### Screenshots
N/A
### Environment
POST to '/backchannel-logout/' is being sent from a Keycloak server.
Latest Superset version
Python 3.8
### Additional context
Apologies if I am doing something dumb here, like simply getting the format
of my WTF_CSRF_EXEMPT_LIST record wrong. I've been trying to get this to work
for hours : /
Also, I realize that the code under `def backchannel_logout(self):` may not
work, but right now I'm just trying to get past this CSRF issue.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]