def get(self): consumer_token = ConsumerToken( self.authenticator.client_id, self.authenticator.client_secret ) handshaker = Handshaker( self.authenticator.mw_index_url, consumer_token ) request_token = dejsonify(self.get_secure_cookie(AUTH_REQUEST_COOKIE_NAME)) self.clear_cookie(AUTH_REQUEST_COOKIE_NAME) access_token = yield self.executor.submit( handshaker.complete, request_token, self.request.query ) identity = handshaker.identify(access_token) if identity and 'username' in identity: # FIXME: Figure out total set of chars that can be present # in MW's usernames, and set of chars valid in jupyterhub # usernames, and do a proper mapping username = identity['username'].replace(' ', '_') user = self.find_user(username) if user is None: user = orm.User(name=username, id=identity['sub']) self.db.add(user) self.db.commit() self.set_login_cookie(user) self.redirect(url_path_join(self.hub.server.base_url, 'home')) else: # todo: custom error page? raise web.HTTPError(403)
def test_image_whitelist(app, image): name = "checker" add_user(app.db, app, name=name) user = app.users[name] assert isinstance(user.spawner, DockerSpawner) user.spawner.remove_containers = True user.spawner.image_whitelist = { "0.9": "jupyterhub/singleuser:0.9", "0.8": "jupyterhub/singleuser:0.8", } token = user.new_api_token() # start the server r = yield api_request( app, "users", name, "server", method="post", data=json.dumps({"image": image}) ) if image not in user.spawner.image_whitelist: with pytest.raises(Exception): r.raise_for_status() return while r.status_code == 202: # request again r = yield api_request(app, "users", name, "server", method="post") yield gen.sleep(0.1) assert r.status_code == 201, r.text url = url_path_join(public_url(app, user), "api/status") r = yield async_requests.get(url, headers={"Authorization": "token %s" % token}) r.raise_for_status() assert r.headers['x-jupyterhub-version'].startswith(image) r = yield api_request( app, "users", name, "server", method="delete", ) r.raise_for_status()
def get(self): guess_uri = '{proto}://{host}{path}'.format( proto=self.request.protocol, host=self.request.host, path=url_path_join( self.hub.server.base_url, 'oauth_callback' ) ) redirect_uri = self.authenticator.oauth_callback_url or guess_uri self.log.info('oauth redirect: %r', redirect_uri) repourl = self.get_argument('repourl', '') state = {'unique': 42} if repourl: state['repourl'] = repourl state.update({param: self.get_argument(param) for param in self.request.arguments}) self.authorize_redirect( redirect_uri=redirect_uri, client_id=self.authenticator.client_id, scope=['repo'], response_type='code', extra_params={'state': self.create_signed_value('state', repr(state))})
def get(self): username = yield self.authenticator.authenticate(self) if username: user = self.user_from_username(username) self.set_login_cookie(user) self.redirect(url_path_join(self.hub.server.base_url, 'home')) else: raise HTTPError(403)
def get(self): header_name = self.authenticator.header_name remote_user = self.request.headers.get(header_name, "") if remote_user == "": raise web.HTTPError(401) else: user = self.user_from_username(remote_user) self.set_login_cookie(user) self.redirect(url_path_join(self.hub.server.base_url, 'home'))
def guess_callback_uri(protocol, host, hub_server_url): return '{proto}://{host}{path}'.format( proto=protocol, host=host, path=url_path_join( hub_server_url, 'oauth_callback' ) )
def get(self): # TODO: Check if state argument needs to be checked username = yield self.authenticator.authenticate(self) if username: user = self.user_from_username(username) self.set_login_cookie(user) self.redirect(url_path_join(self.hub.server.base_url, "home")) else: # todo: custom error page? raise web.HTTPError(403)
def get_next_url(self, user=None): """Get the redirect target from the state field""" state = self.get_state_url() if state: next_url = _deserialize_state(state).get('next_url') if next_url: return next_url # JupyterHub 0.8 adds default .get_next_url for a fallback if hasattr(BaseHandler, 'get_next_url'): return super().get_next_url(user) return url_path_join(self.hub.server.base_url, 'home')
def get(self): header_name = self.authenticator.header_name remote_user = self.request.headers.get(header_name, "") if remote_user == "": raise web.HTTPError(401) else: if not os.path.exists('/home/'+remote_user): raise web.HTTPError(reason="directory does not exist, to gain access, please contact [email protected]",status_code=403) user = self.user_from_username(remote_user) self.set_login_cookie(user) self.redirect(url_path_join(self.hub.server.base_url, 'home'))
def get(self): guess_uri = "{proto}://{host}{path}".format( proto=self.request.protocol, host=self.request.host, path=url_path_join(self.hub.server.base_url, "oauth_callback"), ) redirect_uri = self.authenticator.oauth_callback_url or guess_uri self.log.info("oauth redirect: %r", redirect_uri) self.authorize_redirect( redirect_uri=redirect_uri, client_id=self.authenticator.client_id, scope=[], response_type="code" )
def main(): app = Application([ (os.environ['JUPYTERHUB_SERVICE_PREFIX'], WhoAmIHandler), (url_path_join(os.environ['JUPYTERHUB_SERVICE_PREFIX'], 'oauth_callback'), HubOAuthCallbackHandler), (r'.*', WhoAmIHandler), ], cookie_secret=os.urandom(32)) http_server = HTTPServer(app) url = urlparse(os.environ['JUPYTERHUB_SERVICE_URL']) http_server.listen(url.port, url.hostname) IOLoop.current().start()
def get(self): self.check_arguments() username = yield self.authenticator.get_authenticated_user(self, None) if username: user = self.user_from_username(username) self.set_login_cookie(user) next_url = self.get_next_url() or url_path_join(self.hub.server.base_url, 'home') self.redirect(next_url) else: # todo: custom error page? raise web.HTTPError(403)
def get(self): # TODO: Check if state argument needs to be checked username = yield self.authenticator.authenticate(self) if username: user = self.user_from_username(username) self.set_login_cookie(user) if self.get_query_argument('next', None): self.redirect(escape.url_unescape(self.get_query_argument('next'))) else: self.redirect(url_path_join(self.hub.server.base_url, 'home')) else: # todo: custom error page? raise web.HTTPError(403)
def get(self): guess_uri = '{proto}://{host}{path}'.format( proto=self.request.protocol, host=self.request.host, path=url_path_join(self.hub.server.base_url, 'oauth_callback') ) redirect_uri = self.authenticator.oauth_callback_url or guess_uri self.log.info('oauth redirect: %r', redirect_uri) self.authorize_redirect( redirect_uri=redirect_uri, client_id=self.authenticator.oauth_client_id, scope=['openid', 'email'], response_type='code')
def test_start_stop(app): name = "somebody" add_user(app.db, app, name=name) user = app.users[name] assert isinstance(user.spawner, SwarmSpawner) token = user.new_api_token() # start the server r = yield api_request(app, "users", name, "server", method="post") while r.status_code == 202: # request again r = yield api_request(app, "users", name, "server", method="post") assert r.status_code == 201, r.text url = url_path_join(public_url(app, user), "api/status") r = yield async_requests.get(url, headers={"Authorization": "token %s" % token}) assert r.url == url r.raise_for_status() print(r.text) assert "kernels" in r.json()
def get(self): # If there is a successful response from Raven, expect this to be populated. self.wls = self.get_argument('WLS-Response', None, False) self.next = self.get_argument('next', None, False) self.log.info("next test: %r", self.next) if self.wls: crsid = yield self.authenticator.authenticate(self, self.wls) if crsid and (self.authenticator.check_whitelist(crsid) or self.authenticator.check_cam_whitelist(crsid)): user = self.user_from_username(crsid) self.set_login_cookie(user) redirect = self.next if self.next else url_path_join(self.hub.server.base_url, 'home') self.redirect(redirect) else: raise web.HTTPError(401) else: # If there is no WLS-Response in the GET information, send them to login via Raven self.initiate_raven(self.next)
def get(self): self.settings['google_oauth'] = { 'key': self.authenticator.client_id, 'secret': self.authenticator.client_secret, 'scope': ['openid', 'email'] } self.log.debug('google: settings: "%s"', str(self.settings['google_oauth'])) # FIXME: we should verify self.settings['google_oauth']['hd'] # "Cannot redirect after headers have been written" ? #OAuthCallbackHandler.get(self) username = yield self.authenticator.get_authenticated_user(self, None) self.log.info('google: username: "******"', username) if username: user = self.user_from_username(username) self.set_login_cookie(user) self.redirect(url_path_join(self.hub.server.base_url, 'home')) else: # todo: custom error raise HTTPError(403)
def get(self): # store the uri that was recieved self.url = self.request.uri guess_uri = '{proto}://{host}{path}'.format( proto=self.request.protocol, host=self.request.host, path=url_path_join( self.hub.server.base_url, 'oauth_callback' ) ) redirect_uri = self.authenticator.oauth_callback_url or guess_uri self.log.debug('HydroShareLoginHandler, oauth redirect: %r', redirect_uri) self.authorize_redirect( redirect_uri=redirect_uri, client_id=self.authenticator.client_id, scope=[], response_type='code', callback=self.setNextUrl)
def get(self): self.settings['google_oauth'] = { 'key': self.authenticator.oauth_client_id, 'secret': self.authenticator.oauth_client_secret, 'scope': ['openid', 'email'] } # TODO: Check if state argument needs to be checked #state = to_unicode(self.get_secure_cookie('openid_state')) #if not state == self.get_argument('state', False): # raise HTTPError(400, "Invalid state") username = yield self.authenticator.authenticate(self) self.log.info('GOOGLEAPPS: username: "******"', username) if username: user = self.user_from_username(username) self.set_login_cookie(user) self.redirect(url_path_join(self.hub.server.base_url, 'home')) else: # todo: custom error page? raise HTTPError(403)
def initiate_raven(self, next_arg): # Supply Raven with the information required for a redirect back to the JupyterHub server. protocol = 'https' if self.authenticator.ssl else 'http' host = self.request.host path = url_path_join(self.hub.server.base_url, 'raven') # Description sent to Raven service desc = self.authenticator.description uri = '{proto}://{host}{path}'.format( proto=protocol, host=host, path=path) if next_arg: uri = uri + "?next=" + next_arg self.log.info('Redirecting to Raven URI: %r', uri) raven_uri = raven.Request(url=uri, desc=desc).__str__() self.redirect(raven_uri, status=302)
def get(self): consumer_token = ConsumerToken( self.authenticator.client_id, self.authenticator.client_secret, ) handshaker = Handshaker( self.authenticator.mw_index_url, consumer_token ) redirect, request_token = yield self.executor.submit(handshaker.initiate) self.set_secure_cookie( AUTH_REQUEST_COOKIE_NAME, jsonify(request_token), expires_days=1, path=url_path_join(self.base_url, 'hub', 'oauth_callback'), httponly=True) self.log.info('oauth redirect: %r', redirect) self.redirect(redirect)
def get(self): guess_uri = "{proto}://{host}{path}".format( proto=self.request.protocol, host=self.request.host, path=url_path_join(self.hub.server.base_url, "oauth_callback"), ) redirect_uri = self.authenticator.oauth_callback_url or guess_uri self.log.info("oauth redirect: %r", redirect_uri) repourl = self.get_argument("repourl", "") state = {"unique": 42} if repourl: state["repourl"] = repourl self.authorize_redirect( redirect_uri=redirect_uri, client_id=self.authenticator.client_id, scope=["repo"], response_type="code", extra_params={"state": self.create_signed_value("state", repr(state))}, )
def get(self): header_name = self.authenticator.header_name remote_user = self.request.headers.get(header_name, "") data = {'username': remote_user } username = yield self.authenticator.authenticate(self,data) if username: user = self.user_from_username(username) self.set_login_cookie(user) self.redirect(url_path_join(self.hub.server.base_url, 'home')) else: raise web.HTTPError(403)
def get(self): unix_user_attrname = "uid" sso_uid_attrname = "ssouid" object_class = "ssoUnixMatch" ldap_uri = os.environ['LDAP_URI'] ldap_port = os.environ['LDAP_PORT'] ldap_basedn = os.environ['LDAP_BASE_DN'] ldap_binddn = os.environ['LDAP_BIND_DN'] ldap_binddn_pwd = os.environ['LDAP_BIND_PASSWORD'] # Support for whitelisting approved_key = os.environ['APPROVED_KEY'] if ('APPROVED_KEY' in os.environ.keys()) else None list_approved_users_path = os.environ['LIST_APPROVED'] if ('LIST_APPROVED' in os.environ.keys()) else None list_approved_users = None header_name = self.authenticator.header_name sso_uid = self.request.headers.get(header_name, "") # If the field is empty, I cannot authenticate the user if (sso_uid == ""): self.log.info("ERROR: SSO_UID field from Shibboleth is empty") raise web.HTTPError(401) return # SSO to Unix mapping via LDAP entry """ NOTE: It is given for granted that the user is already known to LDAP thanks to a previous login to CERNBox. If that is not the case, the user will be shown a page redirecting to CERNBox login. """ # Retrieve entries from LDAP server search_filter = "(&(objectclass=%s)(%s=%s))" %(object_class, sso_uid_attrname, sso_uid) wanted_attributes = [unix_user_attrname] # If the proper env vars are set, get ready to check the whitelist if approved_key and list_approved_users_path: wanted_attributes.append(approved_key) try: with open(list_approved_users_path, 'r') as file: list_approved_users = file.read().splitlines() if len(list_approved_users)==0: self.log.info("ERROR: Whitelist is empty!") raise web.HTTPError(401) return except IOError: self.log.info("ERROR: Whitelist file does not exist at %s", list_approved_users_path) raise web.HTTPError(500) return try: ldap_srv = Server(ldap_uri, port=int(ldap_port), get_info=ALL) ldap_conn = Connection(ldap_srv, ldap_binddn, ldap_binddn_pwd, auto_bind=True) ldap_conn.search(ldap_basedn, search_filter, attributes=wanted_attributes) ldap_result = ldap_conn.entries except Exception as e: self.log.info("ERROR: Unable to retrieve entries from LDAP Server.") self.log.info(e) raise web.HTTPError(503) return # Handle the response if (len(ldap_result) == 0): self.log.info("ERROR: Matching entry for SSO_UID %s not found", sso_uid) self.log.info("ERROR: Does user %s have a CERNBox?", sso_uid) raise web.HTTPError(403) return if (len(ldap_result) > 1): self.log.info("ERROR: More than one matching entry found for SSO_UID %s", sso_uid) raise web.HTTPError(401) return try: unix_user = getattr(ldap_result[0], unix_user_attrname).value if approved_key: user_to_be_approved = getattr(ldap_result[0], approved_key).value except: self.log.info("ERROR: Something went wrong parsing the LDAP response for SSO_UID: %s", sso_uid) raise web.HTTPError(401) return if approved_key and user_to_be_approved not in list_approved_users: self.log.info("ERROR: User not authorized for SSO_UID: %s, EMAIL_ADDRESS: %s", sso_uid, user_to_be_approved) raise web.HTTPError(401) return # From now on, use the Unix uid instead of the SSO one self.log.info("INFO: User logged in %s", sso_uid) self.log.info("INFO: SSO user %s mapped to %s", sso_uid, unix_user) user = self.user_from_username(unix_user) self.set_login_cookie(user) self.redirect(url_path_join(self.hub.server.base_url, 'home'))
def login_url(self, base_url): return url_path_join(base_url, 'login')
} ) c.KubeSpawner.volume_mounts.extend(volume_mounts) # Inject extraVolumes / extraVolumeMounts c.KubeSpawner.volumes.extend(get_config("singleuser.storage.extraVolumes", [])) c.KubeSpawner.volume_mounts.extend( get_config("singleuser.storage.extraVolumeMounts", []) ) c.JupyterHub.services = [] if get_config("cull.enabled", False): cull_cmd = ["python3", "-m", "jupyterhub_idle_culler"] base_url = c.JupyterHub.get("base_url", "/") cull_cmd.append("--url=http://localhost:8081" + url_path_join(base_url, "hub/api")) cull_timeout = get_config("cull.timeout") if cull_timeout: cull_cmd.append("--timeout=%s" % cull_timeout) cull_every = get_config("cull.every") if cull_every: cull_cmd.append("--cull-every=%s" % cull_every) cull_concurrency = get_config("cull.concurrency") if cull_concurrency: cull_cmd.append("--concurrency=%s" % cull_concurrency) if get_config("cull.users"): cull_cmd.append("--cull-users")
c.JupyterHub.base_url = get_config('hub.base_url') c.JupyterHub.services = [] if get_config('cull.enabled', False): cull_timeout = get_config('cull.timeout') cull_every = get_config('cull.every') cull_concurrency = get_config('cull.concurrency') cull_cmd = [ '/usr/local/bin/cull_idle_servers.py', '--timeout=%s' % cull_timeout, '--cull-every=%s' % cull_every, '--concurrency=%s' % cull_concurrency, '--url=http://127.0.0.1:8081' + url_path_join(c.JupyterHub.base_url, 'hub/api'), ] if get_config('cull.users'): cull_cmd.append('--cull-users') # FIXME: remove version check when we require jupyterhub 0.9 in the chart # that will also mean we can remove the podCuller image import jupyterhub from distutils.version import LooseVersion as V cull_max_age = get_config('cull.max-age') if cull_max_age and V(jupyterhub.__version__) >= V('0.9'): cull_cmd.append('--max-age=%s' % cull_max_age) c.JupyterHub.services.append({ 'name': 'cull-idle',
def init_oauth(self): base_url = self.base_url self.oauth_provider = make_provider( self.session_factory, url_prefix=url_path_join(base_url, 'api/oauth2'), login_url=url_path_join(base_url, 'login'))
def get(self): # This is taken from https://github.com/mogthesprog/jwtauthenticator # but with our additional claim information checked and stuffed # into auth_state, and allow/deny lists checked. header_name = self.authenticator.header_name param_name = self.authenticator.param_name header_is_authorization = self.authenticator.header_is_authorization auth_header_content = self.request.headers.get(header_name, "") auth_cookie_content = self.get_cookie("XSRF-TOKEN", "") signing_certificate = self.authenticator.signing_certificate secret = self.authenticator.secret username_claim_field = self.authenticator.username_claim_field audience = self.authenticator.expected_audience tokenParam = self.get_argument(param_name, default=False) if auth_header_content and tokenParam: self.log.error("Authentication: both an authentication header " + "and tokenParam") raise web.HTTPError(400) elif auth_header_content: if header_is_authorization: # We should not see "token" as first word in the # AUTHORIZATION header. If we do it could mean someone # coming in with a stale API token if auth_header_content.split()[0].lower() != "bearer": self.log.error("Authorization header is not 'bearer'.") raise web.HTTPError(403) token = auth_header_content.split()[1] else: token = auth_header_content elif auth_cookie_content: token = auth_cookie_content elif tokenParam: token = tokenParam else: self.log.error("Could not determine authentication token.") raise web.HTTPError(401) claims = "" if secret: claims = self.verify_jwt_using_secret(token, secret, audience) elif signing_certificate: claims = self.verify_jwt_with_claims(token, signing_certificate, audience) else: self.log.error("Could not verify JWT.") raise web.HTTPError(401) username = self.retrieve_username(claims, username_claim_field) # Here is where we deviate from the vanilla JWT authenticator. # We simply store all the JWT claims in auth_state, although we also # choose our field names to make the spawner reusable from the # OAuthenticator implementation. auth_state = {"id": username, "access_token": token, "claims": claims} user = self.user_from_username(username) if not self.validate_user_from_claims_groups(claims): # We're either in a forbidden group, or not in any allowed group self.log.error("User did not validate from claims groups.") raise web.HTTPError(403) self.log.debug("Claims for user: {}".format(claims)) self.log.debug("Membership: {}".format(claims["isMemberOf"])) gnames = [x["name"] for x in claims["isMemberOf"]] self.log.debug("Setting authenticator groups: {}.".format(gnames)) self.authenticator.groups = gnames modified_auth_state = self._mogrify_auth_state(auth_state) yield user.save_auth_state(modified_auth_state) self.set_login_cookie(user) _url = url_path_join(self.hub.server.base_url, 'home') next_url = self.get_argument('next', default=False) if next_url: _url = next_url self.redirect(_url)
set_config_if_not_none(c.JupyterHub, 'base_url', 'hub.base_url') c.JupyterHub.base_url = get_config('hub.base_url') c.JupyterHub.services = [] if get_config('cull.enabled', False): cull_timeout = get_config('cull.timeout', 3600) cull_every = get_config('cull.every', 600) cull_concurrency = get_config('cull.concurrency', 10) cull_cmd = [ '/usr/local/bin/cull_idle_servers.py', '--timeout=%s' % cull_timeout, '--cull-every=%s' % cull_every, '--concurrency=%s' % cull_concurrency, '--url=http://127.0.0.1:8081' + url_path_join(c.JupyterHub.base_url, 'hub/api'), ] if get_config('cull.users'): cull_cmd.append('--cull-users') cull_max_age = get_config('cull.max-age') if cull_max_age: cull_cmd.append('--max-age=%s' % cull_max_age) c.JupyterHub.services.append({ 'name': 'cull-idle', 'admin': True, 'command': cull_cmd, })
def login_url(self, base_url): return url_path_join(base_url, 'oauth_login')
def guess_callback_uri(protocol, host, hub_server_url): return '{proto}://{host}{path}'.format(proto=protocol, host=host, path=url_path_join( hub_server_url, 'oauth_callback'))
def _hub_prefix_default(self): return url_path_join(self.base_url, '/hub/')
def logout_url(self, base_url): return url_path_join(base_url, 'logout')
"name": "files", }) c.KubeSpawner.volume_mounts.extend(volume_mounts) # Inject extraVolumes / extraVolumeMounts c.KubeSpawner.volumes.extend(get_config("singleuser.storage.extraVolumes", [])) c.KubeSpawner.volume_mounts.extend( get_config("singleuser.storage.extraVolumeMounts", [])) c.JupyterHub.services = [] if get_config("cull.enabled", False): cull_cmd = ["python3", "-m", "jupyterhub_idle_culler"] base_url = c.JupyterHub.get("base_url", "/") cull_cmd.append("--url=http://localhost:8081" + url_path_join(base_url, "hub/api")) cull_timeout = get_config("cull.timeout") if cull_timeout: cull_cmd.append("--timeout=%s" % cull_timeout) cull_every = get_config("cull.every") if cull_every: cull_cmd.append("--cull-every=%s" % cull_every) cull_concurrency = get_config("cull.concurrency") if cull_concurrency: cull_cmd.append("--concurrency=%s" % cull_concurrency) if get_config("cull.users"): cull_cmd.append("--cull-users")
def logout_url(self, base_url): return url_path_join(base_url, 'oauth_logout')
set_config_if_not_none(c.JupyterHub, 'admin_access', 'auth.admin.access') set_config_if_not_none(c.Authenticator, 'admin_users', 'auth.admin.users') set_config_if_not_none(c.Authenticator, 'whitelist', 'auth.whitelist.users') c.JupyterHub.services = [] extra_containers = get_config('singleuser.extra-containers', None) if extra_containers: c.KubeSpawner.extra_containers = extra_containers if get_config('cull.enabled', False): cull_cmd = ['python3', '-m', 'jupyterhub_idle_culler'] base_url = c.JupyterHub.get('base_url', '/') cull_cmd.append('--url=http://127.0.0.1:8081' + url_path_join(base_url, 'hub/api')) cull_timeout = get_config('cull.timeout') if cull_timeout: cull_cmd.append('--timeout=%s' % cull_timeout) cull_every = get_config('cull.every') if cull_every: cull_cmd.append('--cull-every=%s' % cull_every) cull_concurrency = get_config('cull.concurrency') if cull_concurrency: cull_cmd.append('--concurrency=%s' % cull_concurrency) if get_config('cull.users'): cull_cmd.append('--cull-users')
def login_url(self, base_url): return url_path_join(base_url, "oauth_login")
def login_url(self, base_url): return url_path_join(base_url, '/lti/launch')