-
-
Notifications
You must be signed in to change notification settings - Fork 525
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
Enable serving admin site at custom and secure url #3179
Comments
Another reason for enabling a custom admin url is a multipage app where each page is running independently in a separate pod. If I want to enable admin page for all pages/ pods this will be quite difficult to manage wrt. routing/ ingress on kubernetes. It would be nice to use urls like |
I also think the ability to restrict access to the admin page is very important. A password-protected page would be welcome. A parameter to set a custom URL would also be nice, but as a complement rather than alternative in my opinion. |
Managed to restrict access by using a custom tornado LoginHandler. Put the allowed paths of every user in the (secure) cookies, and in the So, now a given user can access /app1, /app2, ... |
Would you mind sharing a bit more on what your |
This is the important part:
You'll also have to write your custom Then, you should be able reach the admin endpoint, whereas ordinary users won't be able to. |
+1 for allowing for custom URL. Another solution I found to handle authorization for any route (including /admin) without using cookies, let me know the thoughts - from bokeh.server.urls import per_app_patterns
from panel.io.server import DocHandler as PanelDocHandler
from tornado.web import HTTPError, authenticated
def _check_authorization(curr_user, req_path):
"""
Implement authorization logic for req_path page for
curr_user and raise HTTPError(403) as needed
"""
pass
class DocHandler(PanelDocHandler):
@authenticated
async def get(self, *args, **kwargs):
curr_user = self.get_current_user().decode("utf-8")
req_path = self.request.path.lower()
_check_authorization(curr_user, req_path)
return await super().get(self, *args, **kwargs)
per_app_patterns[0] = (r"/?", DocHandler) Proposal - I think we should extend support in authorization callbacks (Somewhere here) for allow passing separate callbacks for each route/page OR additional parameter |
This commit adds a single parameter used in the `config.authorize_callback` that allows the user supplied method to check if an app user is authorized to view the requested app at the given path. Resolves holoviz#3179
I think the PR may be sufficient, but we will see what the maintainers think. To replicate the scenario, I created two apps (all code is below). Each app is independent (although I mostly used the example code from the documentation's multipage app). The panel serve app1.py app2.py --basic-auth credentials.json --cookie-secret my_super_safe_cookie_secret This will restrict access based on the user name and the paths the user is allowed to visit. useruser-access.webmadminadmin-access.webmCode# app1.py
from pathlib import Path
import panel as pn
import param
from auth import check_user_authorization
pn.extension()
pn.config.authorize_callback = check_user_authorization
class App1(param.Parameterized):
a = param.Integer(default=2, bounds=(0, 10))
b = param.Integer(default=3, bounds=(0, 10))
def view(self):
return pn.pane.HTML(f"<p>a={self.a} b={self.b}</p>")
def panel(self):
return pn.Row(self.param, self.view).servable()
app1 = App1()
app1.panel() # app2.py
from pathlib import Path
import panel as pn
import param
from auth import check_user_authorization
pn.extension()
pn.config.authorize_callback = check_user_authorization
class App2(param.Parameterized):
c = param.Integer(default=6, bounds=(0, None))
exp = param.Number(default=0.1, bounds=(0, 3))
def view(self):
out = self.c**self.exp
return pn.Column(out)
def panel(self):
return pn.Row(self.param, self.view).servable()
app2 = App2()
app2.panel() # auth.py
from typing import Any
from urllib import parse as urlparse
authorized_user_paths = {
"admin": ["/app1", "/app2"],
"user": ["/app1"],
}
def check_user_authorization(user_info: dict[str, Any], request_path: str) -> bool:
current_user = user_info["user"]
if current_user in list(authorized_user_paths.keys()):
path = urlparse.urlparse(request_path).path
if path in authorized_user_paths[current_user]:
return True
return False
{
"user": "user",
"admin": "admin"
} |
@MarcSkovMadsen PR #5447 will work to change the name of the admin page. It does not change the fact that if a user logs in to the panel app, they can still access the admin page. So with a login you can try the branch out using panel serve app1.py app2.py --basic-auth credentials.json --cookie-secret my_super_safe_cookie_secret \
--admin --admin-endpoint="/random-id" and you will be redirected to a 404 if you go to |
The new admin page looks really, really nice.
But as far as I can see everybody can access it if enabled. I would like to be able to restrict access.
For example via a username and password. Or alternatively at a custom "token" url by specifying something like
--admin=879B996862F69D8561D1B369F7E44
and then the admin page is available at/879B996862F69D8561D1B369F7E44
.My use case would be for example awesome-panel.org where I finally could start getting some insights :-)
The text was updated successfully, but these errors were encountered: