Thank you for the reply !
-
Ok, it is fine if I canât have multiple users on the same browser . But , why am I getting someone elseâs notebook when I launch my notebook , even when we are on different devices .
-
I can confirm from the logs that it is taking my userId from jwt token when I launch hub (b372) , but somewhere in between it is taking a different userId .I am not sure if this is due to some kind of caching during oauth or somewhere else.
-
As you mentioned , also attaching my custom authenticator for better understanding . Kindly tell if you need any other details .
Edit :
Leaving my custom authenticator here , as I am not able to edit my post for some reason ,
class CustomLoginHandler(BaseHandler):
"""
Authenticate users via the CAS protocol.
"""
async def get(self):
app_log = logging.getLogger("tornado.application")
token = self.get_argument("token", None)
has_service_token = token is not None
app_log.debug("Has service ticket? {0}".format(has_service_token))
# Redirect to get ticket if not presenting one
if not has_service_token:
url = self.authenticator.c_login_url
app_log.debug("Redirecting to Custom to get service token: {0}".format(url))
self.redirect(url)
return
user = await self.login_user()
next_url = self.get_next_url(user)
self.redirect(next_url)
def make_service_url(self):
"""
Make the service URL CAS will use to redirect the browser back to this service.
"""
cas_service_url = self.authenticator.c_service_url
if cas_service_url is None:
cas_service_url = self.request.protocol + "://" + self.request.host + self.request.uri
return cas_service_url
"""async def validate_jwt_token(self, token):
#Validate a CAS service ticket.
#Returns (is_valid, user, attribs).
#is_valid` - boolean
#`attribs` - set of attribute-value tuples.
app_log = logging.getLogger("tornado.application")
http_client = AsyncHTTPClient()
qs_dict = dict(token=token)
qs = urllib.parse.urlencode(qs_dict)
validate_url = self.authenticator.c_service_validate_url + "?" + qs
print("Validating Ticket:",validate_url)
response = None
app_log.debug("Validate URL: {0}".format(validate_url))
try:
response = await http_client.fetch(
validate_url,
method="GET")
jsondata = json.loads(response.body)
if jsondata["status"] == "success":
accessList = jsondata["data"]['accessList']
name = jsondata["data"]["displayName"]
uid = jsondata["data"]["userId"]
notebookConfig = jsondata["Config"]
return (True, accessList, name, uid, notebookConfig)
app_log.debug("Response was successful: {0}".format(response))
except Exception:
app_log.debug("Response was unsuccessful: {0}".format(response))
return (False, None, None, None, None)
return (False, None, None, None, None)
"""
class CustomAuthenticator(Authenticator):
from tornado import gen
"""
Validate a CAS service ticket and optionally check for the presence of an
authorization attribute.
"""
c_login_url = Unicode(
config=True,
help="""The CAS URL to redirect unauthenticated users to.""")
c_logout_url = Unicode(
config=True,
help="""The CAS URL for logging out an authenticated user.""")
c_client_ca_certs = Unicode(
allow_none=True,
default_value=None,
config=True,
help="""Path to CA certificates the CAS client will trust when validating a service ticket.""")
c_service_validate_url = Unicode(
config=True,
help="""The CAS endpoint for validating service tickets.""")
c_required_attribs = Set(
help="A set of attribute name and value tuples a user must have to be allowed access."
).tag(config=True)
def get_handlers(self, app):
return [
(r'/login', CustomLoginHandler),
(r'/logout', CustomLogoutHandler),
]
async def validate_jwt_token(self, token):
"""
Validate a CAS service ticket.
Returns (is_valid, user, attribs).
`is_valid` - boolean
`attribs` - set of attribute-value tuples.
"""
app_log = logging.getLogger("tornado.application")
http_client = AsyncHTTPClient()
qs_dict = dict(token=token)
qs = urllib.parse.urlencode(qs_dict)
print(f"QueryParams --> {qs}")
validate_url = self.c_service_validate_url + "?" + qs
print("Validating Ticket:", validate_url)
response = None
jsondata = None
app_log.debug("Validate URL: {0}".format(validate_url))
try:
response = await http_client.fetch(
validate_url,
method="GET")
jsondata = json.loads(response.body)
print(jsondata)
if jsondata["status"] == "success":
accessList = jsondata["data"]['accessList']
name = jsondata["data"]["displayName"]
uid = jsondata["data"]["userId"]
orgid = jsondata["data"]["orgId"]
email = jsondata["data"]["email"]
notebookConfig = jsondata["config"]
return (True, accessList, name, uid, orgid, email, notebookConfig)
print("Response was successful: {0}".format(response))
except Exception:
print("Response was unsuccessful: {0}".format(response))
return (False, None, None,None,None)
return (False, None, None, None, None)
@gen.coroutine
def pre_spawn_start(self, user, spawner):
auth_state = yield user.get_auth_state()
print("User Details: {}".format(user))
print("User key type: {}".format(type(user)))
print("Auth Check Pre Spawn", auth_state)
if not auth_state:
return
spawner.environment['CAUTH_TOKEN'] = auth_state["config"][0]["token"]
print(auth_state["config"])
spawner.profile_list = auth_state["config"]
spawner.http_timeout = 300
async def authenticate(self, handler,data=None):
token = handler.get_query_argument("token")
result = await self.validate_jwt_token(token=token, notebook_id=notebook_id)
print(f"Result ==> {result}")
is_valid, accessList, name, id, orgId, email, config = result
if not is_valid:
return
user = {
'name': id,
'auth_state': {'token': token, "config": config, 'displayName': name, 'orgId': orgId, 'email': email}
}
print("User Details to Spawner: {}".format(user))
return user