Skip to content

Commit 748e13d

Browse files
fetch current user credential only once
1 parent d0c8c7e commit 748e13d

File tree

3 files changed

+40
-6
lines changed

3 files changed

+40
-6
lines changed

binderhub/base.py

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,13 @@
22

33
import json
44
from ipaddress import ip_address
5+
import os
56

67
from http.client import responses
78
from tornado import web
89
from tornado.log import app_log
10+
from tornado.httpclient import AsyncHTTPClient, HTTPRequest, HTTPError
11+
912
from jupyterhub.services.auth import HubOAuthenticated, HubOAuth
1013

1114
from . import __version__ as binder_version
@@ -19,6 +22,7 @@ def initialize(self):
1922
super().initialize()
2023
if self.settings['auth_enabled']:
2124
self.hub_auth = HubOAuth.instance(config=self.settings['traitlets_config'])
25+
self.current_user_model = None
2226

2327
def prepare(self):
2428
super().prepare()
@@ -71,16 +75,46 @@ def get_spec_from_request(self, prefix):
7175
spec = self.request.path[idx + len(prefix) + 1:]
7276
return spec
7377

74-
def get_provider(self, provider_prefix, spec):
78+
async def get_provider(self, provider_prefix, spec):
7579
"""Construct a provider object"""
7680
providers = self.settings['repo_providers']
7781
if provider_prefix not in providers:
7882
raise web.HTTPError(404, "No provider found for prefix %s" % provider_prefix)
7983

84+
async def api_request(url, *args, **kwargs):
85+
headers = kwargs.setdefault('headers', {})
86+
headers.update({'Authorization': 'token %s' % self.hub_auth.api_token})
87+
hub_api_url = os.getenv('JUPYTERHUB_API_URL', '') or self.hub_auth.api_url
88+
request_url = hub_api_url + url
89+
req = HTTPRequest(request_url, *args, **kwargs)
90+
91+
try:
92+
return await AsyncHTTPClient().fetch(req)
93+
except HTTPError as e:
94+
app_log.error("Error accessing Hub API (using %s): %s", request_url, e)
95+
96+
async def get_current_user_model():
97+
"""Get the current user model.
98+
The user auth_state is only accessible to admin users.
99+
"""
100+
if not self.settings['auth_enabled']:
101+
return None
102+
103+
if self.current_user_model is None:
104+
username = self.get_current_user()['name']
105+
resp = await api_request(
106+
f'/users/{username}',
107+
method='GET',
108+
)
109+
self.current_user_model = json.loads(resp.body.decode('utf-8'))
110+
111+
return self.current_user_model
112+
80113
return providers[provider_prefix](
81-
config=self.settings['traitlets_config'],
82-
spec=spec,
83-
handler=self)
114+
config=self.settings['traitlets_config'],
115+
spec=spec,
116+
user_model=await get_current_user_model()
117+
)
84118

85119
def get_badge_base_url(self):
86120
badge_base_url = self.settings['badge_base_url']

binderhub/builder.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ async def get(self, provider_prefix, _unescaped_spec):
229229

230230
# get a provider object that encapsulates the provider and the spec
231231
try:
232-
provider = self.get_provider(provider_prefix, spec=spec)
232+
provider = await self.get_provider(provider_prefix, spec=spec)
233233
except Exception as e:
234234
app_log.exception("Failed to get provider for %s", key)
235235
await self.fail(str(e))

binderhub/main.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ async def get(self, provider_prefix, _unescaped_spec):
4747
spec = self.get_spec_from_request(prefix)
4848
spec = spec.rstrip("/")
4949
try:
50-
self.get_provider(provider_prefix, spec=spec)
50+
await self.get_provider(provider_prefix, spec=spec)
5151
except HTTPError:
5252
raise
5353
except Exception as e:

0 commit comments

Comments
 (0)