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

Superset 3.0 not able to login, cookies are being set as secure even though the site is http. #25374

Closed
ramki88 opened this issue Sep 22, 2023 · 11 comments

Comments

@ramki88
Copy link

ramki88 commented Sep 22, 2023

After upgrading to 3.0, in the dev environment which is an insecure (http), the cookie being set is with secure flag hence the login is going into a loop

Set-Cookie: session=eyJjc3JmX3Rva2VuIjoiOTUyZDJkMjYzZDRkZmZlNzNkMDIzZDk4ZWI5MGZhOGNjYmNlZmFkNyIsImxvY2FsZSI6ImVuIn0.ZQ3JwA.YIUWOopDX4nK6tdetcejqHfoeQo; Secure; HttpOnly; Path=/; SameSite=Lax

How to reproduce the bug

  1. Deploy 3.0.0 image in a kubernetes env
  2. Expose the service on nodeport
  3. Proceed to nodeip:nodeport/login
  4. See error

Expected results

In case of insecure site the cookie should be set without secure flag

Screenshots

image

Environment

  • browser type and version: MS EDGE Version 118.0.2088.11 (Official build) Beta(arm64)
  • superset version: 3.0.0

Additional context

Note: With kubectl port-forward to the service and accessing superset via localhost:port does not set the cookie with secure flag

@sfirke
Copy link
Member

sfirke commented Sep 22, 2023

If you set SESSION_COOKIE_SECURE = False in your config does that fix it?

I appreciate you posting this. I wrote about what I think is the same thing here: #24579 (comment)

I don't think it's okay for the default instructions for setup to fail. But what do you think is the way to change the default config such that it doesn't encourage the user to stick with unsafe practices? For instance Superset now requires a SECRET_KEY to be set in order to run, because too many people were using the default value in production instances.

I don't know that it's feasible to set up https by default as part of docker-compose quick start. Is there a better option than defaulting SESSION_COOKIE_SECURE = False? And what kind of risk does that setting introduce if someone left it that way in production?

@ramki88
Copy link
Author

ramki88 commented Sep 23, 2023

@sfirke, thanks for pointing to the right direction. Setting SESSION_COOKIE_SECURE = False did not fix it. But TALISMAN_ENABLED=False fixed the issue as mentioned in #24579. Agree with you on the point that implications of these settings are unknown. As per #24262 TALISMAN_ENABLED is being enabled by default but does not talk about cookie-scope, not sure if there is a default behaviour to make cookies secure if enabled.

@ramki88
Copy link
Author

ramki88 commented Sep 26, 2023

Looks like talisman defaults session_cookie_secure to True. Adding this to superset_config solved the issue without TALISMAN_ENABLED=False

TALISMAN_CONFIG = {
    "content_security_policy": {
        "default-src": ["'self'"],
        "img-src": ["'self'", "data:"],
        "worker-src": ["'self'", "blob:"],
        "connect-src": [
            "'self'",
            "https://api.mapbox.com",
            "https://events.mapbox.com",
        ],
        "object-src": "'none'",
        "style-src": ["'self'", "'unsafe-inline'"],
        "script-src": ["'self'", "'strict-dynamic'"],
    },
    "content_security_policy_nonce_in": ["script-src"],
    "force_https": False,
    "session_cookie_secure": False
}

@ramki88 ramki88 closed this as completed Sep 26, 2023
@sfirke
Copy link
Member

sfirke commented Sep 26, 2023

That is great sleuthing, thanks @ramki88 for reporting back what worked for you 🙏

@loretoparisi
Copy link

loretoparisi commented Mar 5, 2024

@ramki88 @sfirke I have tried

# CSRF COOKIE
CSRF_COOKIE_HTTPONLY = False
# not required when running in reverse-proxy mode.
WTF_CSRF_ENABLED = False
# Add endpoints that need to be exempt from CSRF protection
WTF_CSRF_EXEMPT_LIST = [ "localhost" ]
# A CSRF token that expires in 1 year
WTF_CSRF_TIME_LIMIT = 60 * 60 * 24 * 365 

TALISMAN_ENABLED = False
TALISMAN_CONFIG = {
    "content_security_policy": {
        "default-src": ["'self'"],
        "img-src": ["'self'", "data:"],
        "worker-src": ["'self'", "blob:"],
        "connect-src": [
            "'self'",
            "https://api.mapbox.com",
            "https://events.mapbox.com",
        ],
        "object-src": "'none'",
        "style-src": ["'self'", "'unsafe-inline'"],
        "script-src": ["'self'", "'strict-dynamic'"],
    },
    "content_security_policy_nonce_in": ["script-src"],
    "force_https": False,
    "session_cookie_secure": False
}

with

#  (default: "Lax") Prevents the browser from sending this cookie along with cross-site requests.
SESSION_COOKIE_SAMESITE = None

#  (default: False): Controls if cookies should be set with the HttpOnly flag.
SESSION_COOKIE_HTTPONLY = False

#  (default: False) Browsers will only send cookies with requests over HTTPS if the cookie is marked “secure”. 
# The application must be served over HTTPS for this to make sense.
SESSION_COOKIE_SECURE = False

but when I try to get the guest Token via API (cURL copied from the swagger playground example code)

curl -X 'POST' \
  'http://localhost:8088/api/v1/security/guest_token/' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer xxxxxxxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '{
  "resources": [
    {
      "id": "xxxx-xxx-xxx-xx-xxxxxxxx",
      "type": "dashboard"
    }
  ],
  "rls": [
  ],
  "user": {
    "first_name": "guest-user",
    "last_name": "guest-user",
    "username": "guest-user"
  }
}'

I get a 403 Forbidden:

{
  "message": "Forbidden"
}

when using the playground directly it works. In fact it does not use the 'Authorization: Bearer xxxxxxxxxxxxxx' but in practice it is using a session cookie. In fact I can reproduce this in pure JavaScript:

const body = {
    "resources": [
        {
            "id": "xxxxx,
            "type": "dashboard"
        }
    ],
    "rls": [],
    "user": {
        "first_name": "guest-user",
        "last_name": "guest-user",
        "username": "guest-user"
    }
};

const headers = {
    "Content-Type": "application/json",
    "Authorization": `Bearer ${access_token}`, // not working
    //"Cookie": `session=.${session_cookie}`, // it is working!
};

console.log(body, headers);

const res = await fetch("http://localhost:8088/api/v1/security/guest_token/", {
    "headers": headers,
    "body": JSON.stringify(body),
    "method": "POST"
});
console.log(await res.json())

Using Cookie: header it works perfecty and I get back the token, while using the Bearer I'm getting the 403.

@sfirke
Copy link
Member

sfirke commented Mar 5, 2024

@loretoparisi Sorry I can't help, you understand this stuff way better than I do based on your details. If you're stuck on something, or have ideas for improvement, maybe post in the Superset Slack chat or GitHub Discussions? I don't think this old issue will get a lot of views.

@loretoparisi
Copy link

@sfirke it makes sense, thank you, posted here!

@EuphoriaCelestial
Copy link

EuphoriaCelestial commented Mar 22, 2024

const headers = {
"Content-Type": "application/json",
"Authorization": Bearer ${access_token}, // not working
//"Cookie": session=.${session_cookie}, // it is working!
};

@loretoparisi why do you have to add . before cookie value? sometimes my session value already contain . at the beginning, do I still need to add it?

@aartisethi05
Copy link

aartisethi05 commented Jul 24, 2024

How to get session_cookie?
On login to superset API , it returns access token as response , on retrieving cookies from response headers , its value is null. Could you please tell from where can I retrieve session_cookie to use in guest_token API. @loretoparisi @EuphoriaCelestial
Or is there any configuration for superset to get cookies in headers?

@EuphoriaCelestial
Copy link

How to get session_cookie? On login to superset API , it returns access token as response , on retrieving cookies from response headers , its value is null. Could you please tell from where can I retrieve session_cookie to use in guest_token API. @loretoparisi @EuphoriaCelestial Or is there any configuration for superset to get cookies in headers?

if you are using postman, you can get it from cookies tab in response

@aartisethi05
Copy link

From postman I am able to get it but when I embed it in Nestjs code ,it won’t work and returns null as cookies.

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

5 participants