Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSRF Warning! State not equal in request and response. #390

Open
gg4u opened this issue May 20, 2022 · 3 comments
Open

CSRF Warning! State not equal in request and response. #390

gg4u opened this issue May 20, 2022 · 3 comments

Comments

@gg4u
Copy link

gg4u commented May 20, 2022

Screen Shot 2022-05-20 at 11 12 28 AM

I found this issue when trying to localtunneling for testing my local env. In local env, everything works ok.

But concerned in production for someone else spotted this too:
https://community.auth0.com/t/non-google-users-need-to-login-twice-due-to-csrf-error/77958

lepture/authlib#376

oauthlib.oauth2.rfc6749.errors.MismatchingStateError: (mismatching_state) CSRF Warning! State not equal in request and response.

I have redirect failing:

@techhouse-lk
Copy link

same here!!
authlib.integrations.base_client.errors.MismatchingStateError: mismatching_state: CSRF Warning! State not equal in request and response.

Did anyone find the issue?
Cleared all cookies and cache , checked with 1.0.0 , 22.1.1
Keycloak authentication on airflow -OpenID

This is my webserver_config.py on airflow .
Are there any errors in this python code

`
"""
webserver_config
Referencies
- https://flask-appbuilder.readthedocs.io/en/latest/security.html#authentication-oauth
"""
import os
import logging
import jwt
import ssl
import certifi
from flask import redirect, session
from flask_appbuilder import expose
from flask_appbuilder.security.manager import AUTH_OAUTH
from flask_appbuilder.security.views import AuthOAuthView
from airflow.www.security import AirflowSecurityManager
basedir = os.path.abspath(os.path.dirname(file))
log = logging.getLogger(name)
AUTH_TYPE = AUTH_OAUTH
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = "Public"
AUTH_ROLES_SYNC_AT_LOGIN = True
PERMANENT_SESSION_LIFETIME = 1800
AUTH_ROLES_MAPPING = {
"airflow_admin": ["Admin"],
"airflow_op": ["Op"],
"airflow_user": ["User"],
"airflow_viewer": ["Viewer"],
"airflow_public": ["Public"],
}
OAUTH_PROVIDERS = [
{
'name': 'keycloak',
'icon': 'fa-circle-o',
'token_key': 'access_token',
'remote_app': {
'client_id': 'airflow',
'client_secret': 'xxxxxxxxxxxxxxxxxxxx',
'client_kwargs': {
'scope': 'email profile'
},
'api_base_url': 'https://xxxxxxxxxxxxxx/auth/realms/testrealm/protocol/openid-connect/',
'request_token_url': None,
'access_token_url': 'https://xxxxxxxxxxxxxx/auth/realms/testrealm/protocol/openid-connect/token',
'authorize_url': 'https://xxxxxxxxxxxxxx/auth/realms/testrealm/protocol/openid-connect/auth',
},
},
]
class CustomAuthRemoteUserView(AuthOAuthView):
@expose("/logout/")
def logout(self):
"""Delete access token before logging out."""
return super().logout()

class CustomSecurityManager(AirflowSecurityManager):
authoauthview = CustomAuthRemoteUserView

def oauth_user_info(self, provider, response):
if provider == MY_PROVIDER:
token = response["access_token"]
me = jwt.decode(token, algorithms="RS256", verify=False)
# sample of resource_access
# {
# "resource_access": { "airflow": { "roles": ["airflow_admin"] }}
# }
groups = me["resource_access"]["airflow"]["roles"] # unsafe
# log.info("groups: {0}".format(groups))
if len(groups) < 1:
groups = ["airflow_public"]
else:
groups = [str for str in groups if "airflow" in str]
userinfo = {
"username": me.get("preferred_username"),
"email": me.get("email"),
"first_name": me.get("given_name"),
"last_name": me.get("family_name"),
"role_keys": groups
}
log.info("user info: {0}".format(userinfo))
return userinfo
else:
return {}

SECURITY_MANAGER_CLASS = CustomSecurityManager
APP_THEME = "simplex.css"`

@carlosvega
Copy link

Did you manage to solve this issue?

@Teraskull
Copy link

@carlosvega I managed to get a probably bad workaround for now:

from oauthlib.oauth2.rfc6749.errors import MismatchingStateError
from flask import redirect, url_for, jsonify
import app


@app.errorhandler(MismatchingStateError)
def mismatching_state(e):
    return redirect(url_for("google.login"))  # You could redirect to the Google login again, which resets the session state.
    # return jsonify({"error": "state_mismatch"}), 401  # Or you could handle this in any other way.

You can replicate the issue via calling the "/google/authorized" (or whatever URI is set for your Authorized redirect URI) more than once. You will get the MismatchingStateError.

With this handler, it will redirect once and not show the Werkzeug traceback.
Not proud, but I wasted too much time trying anything else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants