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

Endpoint /api/me/roles returns 401 "Not authorized" despite valid access token #25740

Open
larshelge opened this issue Oct 23, 2023 · 14 comments
Assignees

Comments

@larshelge
Copy link

larshelge commented Oct 23, 2023

I am running Superset 3.0.0 with Docker Compose. Trying to access the following API endpoint:

/api/me/roles

I have created an access token from /api/v1/security/login for a user with the Admin, Public and Gamma roles. I make a request for the mentioned API endpoint with the appropriate header.

Authorization: Bearer {access-token}
Accept: application/json

Various endpoints return 200 and a valid JSON payload, such as /api/v1/dashboard and /api/v1/chart. However, the
/api/me/roles endpoint returns 401 "Not authorized". This blocks the embedded dashboard feature. Could this be a bug, or am I doing something wrong? I sense there is something special with this endpoint and authentication as it relates to the currently authenticated user.

The /api/me/roles endpoint returns the roles when I log in through the UI and load the endpoint in a web browser.

Expected results

I expect the roles to be returned from the API with 200 OK status.

Actual results

The endpoint returns 401 "Not authorized" despite the access token seemingly being valid.

Environment

(please complete the following information):

  • Chrome latest.
  • Linux Ubuntu 22.04.
  • Superset 3.0.0 on Docker Compose in production mode

Flags

WTF_CSRF_ENABLED = False
TALISMAN_ENABLED = False
ENABLE_CORS = True
@cbuffevant
Copy link

Still happening in 3.0.1

@siddhartha8916
Copy link

siddhartha8916 commented Dec 30, 2023

You can try a fix around by hitting a get request to http://localhost:8088/login endpoint and sending the csrf_token obtained along with username and password as formData and then get the access token to request http://localhost:8088/api/v1/me/roles api

Issue addressed here #25876

@bryanjknight
Copy link

Still happening in 3.1.1, also blocking usage of embedded dashboards. Unfortunately the workaround above won't work because the embed SDK won't do that for me

@bryanjknight
Copy link

Digging into this more, it seems /api/v1/security/login does not set a session cookie; hence, the /api/v1/me and underlying calls fail b/c there's no session cookie

@EuphoriaCelestial
Copy link

EuphoriaCelestial commented Mar 19, 2024

Digging into this more, it seems /api/v1/security/login does not set a session cookie; hence, the /api/v1/me and underlying calls fail b/c there's no session cookie

I am facing the same issue
Normally, how can I get the session cookie? if /api/v1/security/login doesn't return it, is there any other way to login and get cookie? how did superset work if there is no session cookie?

@siddhartha8916
Copy link

Still happening in 3.1.1, also blocking usage of embedded dashboards. Unfortunately the workaround above won't work because the embed SDK won't do that for me

So superset only returns the dashboard available to that user according to the role defined

@bryanjknight
Copy link

bryanjknight commented Mar 19, 2024

Digging into this more, it seems /api/v1/security/login does not set a session cookie; hence, the /api/v1/me and underlying calls fail b/c there's no session cookie

I am facing the same issue Normally, how can I get the session cookie? if /api/v1/security/login doesn't return it, is there any other way to login and get cookie? how did superset work if there is no session cookie?

I had to do a hack (emphasis on hack: this is not production ready code, please review it b/c if done wrong it creates a security hole) to basically take a JWT, verify it, find the corresponding user, then login that user again. The result is a cookie getting set on response:

class CustomOAuthView(AuthOAuthView):

    @expose('/custom/session-by-jwt', methods=['GET'])
    def session_by_jwt(self, provider= None):
        # get the jwt in the request
        current_jwt = request.headers.get('Authorization').split(' ')[1]

        # decode the jwt to get the claims
        import jwt
        try:
            jwt_options = {
                'verify_signature': False, # TODO: get the public key from the jwks_uri to verify the signature
                'verify_exp': True,
                'verify_nbf': False,
                'verify_iat': True,
                'verify_aud': False
            }
            jwt_decoded = jwt.decode(jwt=str.encode(current_jwt), algorithms=['HS256'], options=jwt_options)

            # get the user from the jwt
            user = self.appbuilder.sm.find_user(email=jwt_decoded['sub'])

            # create a session cookie for the user
            login_user(user)
        except Exception as e:
            print(f"Exception: {e}")
            return "Invalid JWT"
        return "session_by_jwt"  

class CustomSsoSecurityManager(SupersetSecurityManager):

    authoauthview = CustomOAuthView

    def __init__(self, appbuilder):
        super(CustomSsoSecurityManager, self).__init__(appbuilder)

@EuphoriaCelestial
Copy link

EuphoriaCelestial commented Mar 20, 2024

Digging into this more, it seems /api/v1/security/login does not set a session cookie; hence, the /api/v1/me and underlying calls fail b/c there's no session cookie

I found out that if we set those flag in superset config:
SESSION_COOKIE_HTTPONLY = False
SESSION_COOKIE_SECURE = False

the /api/v1/security/login endpoint will return a cookie like this:
image

is this the right cookie? if so, how to use it? I tried to add it in postman but it doesn't work
image

image

@bryanjknight
Copy link

Ah, good find! Yeah, that's looks close, the one I have starts with a .. Digging into the superset_config.py in the main repo, I see this:

#
# Flask session cookie options
#
# See https://flask.palletsprojects.com/en/1.1.x/security/#set-cookie-options
# for details
#
SESSION_COOKIE_HTTPONLY = True  # Prevent cookie from being read by frontend JS?
SESSION_COOKIE_SECURE = False  # Prevent cookie from being transmitted over non-tls?
SESSION_COOKIE_SAMESITE: Literal["None", "Lax", "Strict"] | None = "Lax"
# Whether to use server side sessions from flask-session or Flask secure cookies
SESSION_SERVER_SIDE = False
# Example config using Redis as the backend for server side sessions
# from flask_session import RedisSessionInterface
#
# SESSION_SERVER_SIDE = True
# SESSION_USE_SIGNER = True
# SESSION_TYPE = "redis"
# SESSION_REDIS = Redis(host="localhost", port=6379, db=0)
#
# Other possible config options and backends:
# # https://flask-session.readthedocs.io/en/latest/config.html

Perhaps switch to server side sessions might help?

@EuphoriaCelestial
Copy link

EuphoriaCelestial commented Mar 21, 2024

Perhaps switch to server side sessions might help?

I tried, but still not working
Any other idea?

@YannGer
Copy link

YannGer commented Mar 25, 2024

Hi all,

same problem here. Do I have to rollback on version 2 or do you think this problem may be fixed in a rather short time ?

Thx !!

@mortenesbensen
Copy link

mortenesbensen commented May 23, 2024

Hi,

I'm also seeing this on Superset 3.1.0 when trying to embed dashboards using the embedded sdk. Any updates?

Thanks in advance

Turns out guest token I was using wasn't formatted correct in which case the Embedded SDK successfully creates the dashboard just to fail on the subsequent call to /roles

@jay-growflow
Copy link

@mortenesbensen when you say it "wasn't formatted correctly" what was the issue? I think we're running into this same issue now.

@Parzi68
Copy link

Parzi68 commented Nov 13, 2024

Hello,

I am new to Apache Superset and am working on integrating REST APIs for CRUD operations within my project. I understand that in order to interact with the Superset REST APIs, I need to obtain an API token. Could you please provide guidance on how to retrieve the API token either through the Superset UI or by sending HTTP requests?

For context, I have already configured Keycloak for authentication, and would appreciate any instructions or references to help me proceed.

Thank you for your assistance!

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