ragna icon indicating copy to clipboard operation
ragna copied to clipboard

Login endpoint issue when launching Ragna on JupyterHub(NEbari)

Open dharhas opened this issue 1 year ago • 13 comments

Bug description

When I launch "ragna ui" from the command line on JupyterHub/Nebari with say:

BOKEH_ALLOW_WS_ORIGIN=nebari.quansight.dev ragna ui

Ragna is deployed with JupyterHub Server Proxy to the url:

https://nebari.quansight.dev/user/[email protected]/proxy/31477/

This works but the the login page gets redirected to

https://nebari.quansight.dev/auth and shows a 404.

gets redirected to

https://nebari.quansight.dev/auth

manually changing the auth url to https://nebari.quansight.dev/user/[email protected]/proxy/31477/auth

lets me login and then I can use ragna.

How to reproduce the bug?

launch a terminal on Jupyterhub/ragna and launch ragna ui

Versions and dependencies used

ragna - 0.1.3 python - 3.11.7 os - linux

Anything else?

No response

dharhas avatar Jan 16 '24 14:01 dharhas

I see that we are missing forward slashes for the auth and logout endpoints:

https://github.com/Quansight/ragna/blob/38f75f6d88e74f72c030ef50045315b81eb203aa/ragna/deploy/_ui/app.py#L109-L115

@pierrotsmnrd Do you remember if this was intentional?

I'm not saying that this is the issue here, but this the only thing that caught my eye while looking into it.

pmeier avatar Jan 16 '24 15:01 pmeier

It was not intentional. I don't know if this has an impact or not. worth trying.

pierrotsmnrd avatar Jan 16 '24 15:01 pierrotsmnrd

@aktech confirmed that #276 indeed fixed the issue. However, we have for more instances of hardcoded paths for the login mechanism:

  • https://github.com/Quansight/ragna/blob/ea9ffeb526098c0d31c001bee2c69bbb84eb999d/ragna/deploy/_ui/app.py#L66
  • https://github.com/Quansight/ragna/blob/ea9ffeb526098c0d31c001bee2c69bbb84eb999d/ragna/deploy/_ui/app.py#L76
  • https://github.com/Quansight/ragna/blob/ea9ffeb526098c0d31c001bee2c69bbb84eb999d/ragna/deploy/_ui/app.py#L92
  • https://github.com/Quansight/ragna/blob/ea9ffeb526098c0d31c001bee2c69bbb84eb999d/ragna/deploy/_ui/logout_page.py#L22

They also need be relative. This most likely has to happen in JS.

pmeier avatar Jan 17 '24 11:01 pmeier

@aktech This is solved with the PRs you have send, correct?

pmeier avatar Mar 18 '24 08:03 pmeier

I have not tested it yet. I am testing is right now.

aktech avatar Mar 26 '24 09:03 aktech

The login endpoint issue is fixed (which is what this issue is about), I am able to login via the proxy url, which takes me to the /auth.

After login the UI will look for http://127.0.0.1:31476/document (when you upload a doc), which can be fixed with creating ui and api separately, something along these lines: https://github.com/nebari-dev/jhub-apps/discussions/147 I'll give that a try to confirm if that works (I am fairly confident it should).

aktech avatar Mar 26 '24 10:03 aktech

I just tried running two separate processes explicitly one for API and another for UI

ragna api
ragna ui --no-open-browser --no-start-api

With this ragna.toml:

# change to match your directory and same for all others below
local_root = "/home/[email protected]/.cache/ragna"
authentication = "ragna.deploy.RagnaDemoAuthentication"
document = "ragna.core.LocalDocument"
source_storages = [
    "ragna.source_storages.RagnaDemoSourceStorage",
]
assistants = [
    "ragna.assistants.RagnaDemoAssistant",
]

[api]
hostname = "127.0.0.1"
port = "31476"

# change this url to match the url of the created ragna api app url
url = "https://nebari.quansight.dev/user/[email protected]/proxy/31476"
origins = ["https://nebari.quansight.dev"]
database_url = "sqlite:////home/[email protected]/.cache/ragna/ragna.db"

[ui]
hostname = "127.0.0.1"
port = 31477
origins = [
    "http://127.0.0.1:31477",
]

Below is the error (as API is not accessible to UI without authentication and it does a 302 redirect to hub authentication)

Error Traceback
$ ragna ui --no-open-browser --no-start-api
Launching server at http://127.0.0.1:31477
Uncaught exception GET / (127.0.0.1)
HTTPServerRequest(protocol='http', host='nebari.quansight.dev', method='GET', uri='/', version='HTTP/1.1', remote_ip='127.0.0.1')
Traceback (most recent call last):
  File "/home/conda/[email protected]/de7fbfe4-1711448219-624-ragna-only/lib/python3.11/site-packages/tornado/web.py", line 1790, in _execute
    result = await result
             ^^^^^^^^^^^^
  File "/home/conda/[email protected]/de7fbfe4-1711448219-624-ragna-only/lib/python3.11/site-packages/panel/io/server.py", line 588, in get
    session = await self.get_session()
              ^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/conda/[email protected]/de7fbfe4-1711448219-624-ragna-only/lib/python3.11/site-packages/panel/io/server.py", line 477, in get_session
    session = await super().get_session()
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/conda/[email protected]/de7fbfe4-1711448219-624-ragna-only/lib/python3.11/site-packages/bokeh/server/views/session_handler.py", line 145, in get_session
    session = await self.application_context.create_session_if_needed(session_id, self.request, token)
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/conda/[email protected]/de7fbfe4-1711448219-624-ragna-only/lib/python3.11/site-packages/bokeh/server/contexts.py", line 240, in create_session_if_needed
    self._application.initialize_document(doc)
  File "/home/conda/[email protected]/de7fbfe4-1711448219-624-ragna-only/lib/python3.11/site-packages/panel/io/server.py", line 413, in initialize_document
    super().initialize_document(doc)
  File "/home/conda/[email protected]/de7fbfe4-1711448219-624-ragna-only/lib/python3.11/site-packages/bokeh/application/application.py", line 190, in initialize_document
    h.modify_document(doc)
  File "/home/conda/[email protected]/de7fbfe4-1711448219-624-ragna-only/lib/python3.11/site-packages/bokeh/application/handlers/function.py", line 140, in modify_document
    self._func(doc)
  File "/home/conda/[email protected]/de7fbfe4-1711448219-624-ragna-only/lib/python3.11/site-packages/panel/io/server.py", line 152, in _eval_panel
    panel = panel()
            ^^^^^^^
  File "/home/conda/[email protected]/de7fbfe4-1711448219-624-ragna-only/lib/python3.11/site-packages/ragna/deploy/_ui/app.py", line 73, in index_page
    api_wrapper = ApiWrapper(
                  ^^^^^^^^^^^
  File "/home/conda/[email protected]/de7fbfe4-1711448219-624-ragna-only/lib/python3.11/site-packages/ragna/deploy/_ui/api_wrapper.py", line 39, in __init__
    raise e
  File "/home/conda/[email protected]/de7fbfe4-1711448219-624-ragna-only/lib/python3.11/site-packages/ragna/deploy/_ui/api_wrapper.py", line 32, in __init__
    ).raise_for_status()
      ^^^^^^^^^^^^^^^^^^
  File "/home/conda/[email protected]/de7fbfe4-1711448219-624-ragna-only/lib/python3.11/site-packages/httpx/_models.py", line 761, in raise_for_status
    raise HTTPStatusError(message, request=request, response=self)
httpx.HTTPStatusError: Redirect response '302 Found' for url 'https://nebari.quansight.dev/user/[email protected]/proxy/31476/components'
Redirect location: '/hub/api/oauth2/authorize?client_id=jupyterhub-user-akumar%2540quansight.com&redirect_uri=%2Fuser%2Fakumar%40quansight.com%2Foauth_callback&response_type=code&state=<SANITIZED>'

It didn't work as the API deployed via jupyter server proxy is supposed to be publicly accessible as the UI calls the API internally instead of on the browser as explained in here: https://github.com/nebari-dev/jhub-apps/discussions/147#discussion-6331219 (TLDR: UI hits the hub authentication before the API authentication).

I didn't see a way to expose the API publicly in the Jupyter Server Proxy @dharhas do you know if that's possible?

aktech avatar Mar 27 '24 09:03 aktech

@aktech we don't want the API to be publicly accessible right? it should still be behind auth but the hope would be that internally launched tools should be able to see each other.

pinging @krassowski in case he has any ideas.

dharhas avatar Mar 27 '24 13:03 dharhas

@aktech we don't want the API to be publicly accessible right? it should still be behind auth but the hope would be that internally launched tools should be able to see each other.

Yes, there are two levels of authentication here:

  • JupyterHub level
  • Ragna level

We only want to get rid of the first one, the second one will still exist, which means the API won't be public.

aktech avatar Mar 27 '24 13:03 aktech

I think it is not possible to selectively disable auth in jupyter-server-proxy. One could hack it around by monkeypatching the tornado internals but I would not go that way as this is a security critical component we don't want to accidentally break.

If that was launched from jhub-apps you could presumably pass the JupyterHub auth token/cookie in the request to pass through the JupyterHub-level auth, right? Or is there a conflict because both Ragna and JupyterHub name the tokens the same way?

krassowski avatar Mar 27 '24 14:03 krassowski

In a sense, this looks like ragna should be a service with a service token (so that we are not passing the user auth token).

krassowski avatar Mar 27 '24 14:03 krassowski

Maybe the jhub-apps can launch the ragna backend as a 'service' and then the ragna frontend can be a regular app?

dharhas avatar Mar 28 '24 18:03 dharhas

A more general question is how does a user deploy rest api's that they want other apps on the platform to be able to use.

dharhas avatar Mar 28 '24 18:03 dharhas