def get(self): code = self.get_argument('code') client = AsyncHTTPClient() # https://api.github.com/users/no13bus params = { 'client_id': githubapi['CLIENT_ID'], 'redirect_uri': githubapi['REDIRECT_URL'], 'client_secret': githubapi['CLIENT_SECRET'], 'code': code } url = url_concat("https://github.com/login/oauth/access_token", params) req = HTTPRequest(url=url, method="POST",headers={"Accept": "application/json"}, body='') res = yield client.fetch(req) resp_json = json.loads(res.body) token = resp_json['access_token'] req_url = url_concat("https://api.github.com/user", {'access_token': token}) req_user = HTTPRequest(url=req_url, method="GET") res_user = yield client.fetch(req_user) user_info = json.loads(res_user.body) username = user_info['login'] avatar_url = user_info['avatar_url'] user = yield self.db.user.find_one({'username': username}) if not user: user_id = yield self.db.user.insert({'username': username, 'token': token, 'avatar_url': avatar_url}) print user_id self.set_secure_cookie("token",token) self.set_secure_cookie("username",username) self.set_secure_cookie("avatar_url",avatar_url) self.redirect('/')
def post(self): self.set_secure_cookie("user", '', expires_days = -1) if self.get_argument("code", False): #print "Got code: %s url: %s" % (self.get_argument("code", False), self._url_) self.get_authenticated_user( redirect_uri=settings.canvas_page, client_id=settings.fb_appid, client_secret=settings.fb_secret, code=self.get_argument("code"), callback=self.async_callback( self.onAuth)) return # self.authorize_redirect(redirect_uri=self._url_, # client_id=settings.fb_appid, # extra_params={"scope": "publish_stream,offline_access"}) args = { "redirect_uri": settings.canvas_page, "client_id": settings.fb_appid, "scope": "publish_stream,offline_access" } print url_concat(self._OAUTH_AUTHORIZE_URL, args) self.write('<script> top.location.href = "' + url_concat(self._OAUTH_AUTHORIZE_URL, args) + '";</script>'); self.finish()
def fetch(url, method='GET', params=None, headers=None, cookies=None, data=None, streaming_callback=None, header_callback=None, connect_timeout=None, request_timeout=None): """Make an HTTP request and return a Future. This is mostly just a wrapper for tornado.httpclient, but adds support for sending cookies. Raises HTTPError and IOError. """ if headers is None: headers = {} if params is not None: url = httputil.url_concat(url, params) if cookies is not None: # abuse SimpleCookie to escape our cookies for us simple_cookies = http.cookies.SimpleCookie(cookies) headers['cookie'] = '; '.join(val.output(header='')[1:] for val in simple_cookies.values()) http_client = httpclient.AsyncHTTPClient() res = yield http_client.fetch(httpclient.HTTPRequest( httputil.url_concat(url, params), method=method, headers=httputil.HTTPHeaders(headers), body=data, streaming_callback=streaming_callback, header_callback=header_callback, connect_timeout=connect_timeout, request_timeout=request_timeout )) return res
def get(self, name, user_path): current_user = self.get_current_user() if current_user and current_user.name == name: # If people visit /user/:name directly on the Hub, # the redirects will just loop, because the proxy is bypassed. # Try to check for that and warn, # though the user-facing behavior is unchainged host_info = urlparse(self.request.full_url()) port = host_info.port if not port: port = 443 if host_info.scheme == 'https' else 80 if port != Server.from_url(self.proxy.public_url).port and port == self.hub.port: self.log.warning(""" Detected possible direct connection to Hub's private ip: %s, bypassing proxy. This will result in a redirect loop. Make sure to connect to the proxied public URL %s """, self.request.full_url(), self.proxy.public_url) # logged in as correct user, spawn the server if current_user.spawner: if current_user.spawn_pending or current_user.proxy_pending: # spawn has started, but not finished self.statsd.incr('redirects.user_spawn_pending', 1) html = self.render_template("spawn_pending.html", user=current_user) self.finish(html) return # spawn has supposedly finished, check on the status status = yield current_user.spawner.poll() if status is not None: if current_user.spawner.options_form: self.redirect(url_concat(url_path_join(self.hub.base_url, 'spawn'), {'next': self.request.uri})) return else: yield self.spawn_single_user(current_user) # set login cookie anew self.set_login_cookie(current_user) without_prefix = self.request.uri[len(self.hub.base_url):] target = url_path_join(self.base_url, without_prefix) if self.subdomain_host: target = current_user.host + target self.redirect(target) self.statsd.incr('redirects.user_after_login') elif current_user: # logged in as a different user, redirect self.statsd.incr('redirects.user_to_user', 1) target = url_path_join(current_user.url, user_path or '') self.redirect(target) else: # not logged in, clear any cookies and reload self.statsd.incr('redirects.user_to_login', 1) self.clear_login_cookie() self.redirect(url_concat( self.settings['login_url'], {'next': self.request.uri}, ))
def authenticate(self, handler, data=None): code = handler.get_argument("code", False) if not code: raise web.HTTPError(400, "OAUTH_CALLBACK_URL has been called without a token") http_client = AsyncHTTPClient() # Exchange the OAuth code for a Custom OAuth Access Token # API specifies a GET request yet requires URL parameters token_req_param = dict( client_id=self.client_id, client_secret=self.client_secret, grant_type=self.grant_type, redirect_uri=self.oauth_callback_url, code=code ) if not self.oauth_access_token_url: raise web.HTTPError(400, "OAUTH_ACCESS_TOKEN_URL is not defined") token_url = url_concat(self.oauth_access_token_url, token_req_param) token_req = HTTPRequest(url=token_url, method="GET", headers={"Accept": "application/json"}, validate_cert=True, ca_certs=self.client_cert_path ) resp = yield http_client.fetch(token_req) resp_json = self.parse_response(resp) profile_req_params = dict( access_token=resp_json['access_token'] ) # Retrieve user information with a valid token obtained from the previous # request if not self.oauth_profile_url: raise web.HTTPError(400, "OAUTH_PROFILE_URL is not defined") profile_url = url_concat(self.oauth_profile_url, profile_req_params) profile_req = HTTPRequest( url=profile_url, validate_cert=True, ca_certs=self.client_cert_path) # This request returns a JSON string resp = yield http_client.fetch(profile_req) resp_json = json.loads(resp.body.decode('utf8', 'replace')) user_id = resp_json['id'] self.log.info("OAuth user id: %s" % user_id) # Check is user is authorized to access to Stratio Intelligence if not self.is_allowed(resp_json): raise web.HTTPError(403, "User " + user_id + " is not allowed to access to Stratio Intelligence") # User id is returned to be registered into app data base return user_id
def get_ips_by_array_id(self,array_id): urlfilter={"filter":'storagesystem eq "%s"'%(array_id),"per_page":100} url = url_concat(SWARM_API_URL_IP,urlfilter) response_body= self.send_swarm_request(url,method="GET") ip_entries=json.loads(response_body)["entries"] ipids=map(lambda x: str(x["ipid"]),ip_entries) urlfilter={"filter":'id in (%s)'%(",".join(ipids))} url = url_concat(SWARM_API_URL_SINGLE_IP,urlfilter) response_body= self.send_swarm_request(url,method="GET") ips=json.loads(response_body)["entries"] return ips
def get_reserved_array_by_user_id(self,user_id): reservations=self.get_active_reservation_by_user_id(user_id) reservation_ids=map(lambda x: str(x["id"]),reservations) urlfilter={"filter":'reservation in (%s)'%(",".join(reservation_ids)),"per_page":100} url = url_concat(SWARM_API_URL_ARRAY_RESERVATION,urlfilter) response_body= self.send_swarm_request(url,method="GET") reservation_arrays=json.loads(response_body)["entries"] array_ids=map(lambda x:str(x["storagesystem"]),reservation_arrays) urlfilter={"filter":'id in (%s)'%(",".join(array_ids)),"per_page":100} url=url_concat(SWARM_API_URL_ARRAY,urlfilter) response_body= self.send_swarm_request(url,method="GET") reserved_arrays=json.loads(response_body)["entries"] return reserved_arrays
def request(self, url_path, method="GET", **kwargs): params = self.build_params(url_path, **kwargs) if not urlparse.urlparse(url_path).netloc: url = url_concat(self.build_url(url_path, **kwargs), params) else: url = url_concat(url_path, params) client = AsyncHTTPClient(force_instance=True) try: result = yield client.fetch(url, method=method, headers=self.build_headers()) raise Return(result) finally: client.close()
def get_access_token(self, code, callback, grant_type='code', redirect_uri=None): if grant_type == 'refresh_token': args = { 'grant_type': 'refresh_token', 'refresh_token': code, } elif redirect_uri: args = { 'grant_type': 'authorization_code', 'code': code, 'redirect_uri': redirect_uri, } else: logging.error('Renren Get Access Token Error. redirect_uri required') return args.update(self._oauth_consumer_token()) http = httpclient.AsyncHTTPClient() http.fetch(url_concat(self._OAUTH_ACCESS_TOKEN_URL, args), callback=(yield gen.Callback('_RenrenGraphMixin.get_access_token'))) response = yield gen.Wait('_RenrenGraphMixin.get_access_token') if response.error and not response.body: logging.warning("Error response %s fetching %s", response.error, response.request.url) callback(None) return callback(response) return
def watch(self, url_path, on_data, **kwargs): class WatchFuture(Future): def cancel(self): client.close() logging.debug("AsyncHTTPClient closed") def data_callback(data): on_data(json.loads(data)) params = self.build_params(url_path, **kwargs) url = url_concat(self.build_url(url_path, **kwargs), params) request = HTTPRequest( url=url, method="GET", headers=self.build_headers(), request_timeout=3600, streaming_callback=data_callback) client = AsyncHTTPClient(force_instance=True) future = WatchFuture() chain_future(client.fetch(request), future) return future
def toProfilesAPI(self, mid): u"""PROFILES APIでLINEServerにプロフィールを問い合わせ ※Contact Response ObjectのJSONデータが返却されてくる ※TODO:複数一括リクエストは未対応 """ # リクエストはGetでユーザーの識別子 (複数時はカンマ区切り)を渡す http_client = tornado.httpclient.HTTPClient() url = url_concat(self.PROFILES_API, {"mids": mid}) print(url) result = None try: response = http_client.fetch( url, method='GET', headers=self.REQUEST_HEADER, body=None ) json_dic = tornado.escape.json_decode(response.body) result = json_dic["contacts"] except http_client.HTTPError as e: # HTTPError is raised for non-200 responses print("Error: " + str(e)) except Exception as e: # Other errors print("Error: " + str(e)) http_client.close() return result
def _check_group_whitelist(self, username, user_id, is_admin, access_token): http_client = AsyncHTTPClient() headers = _api_headers(access_token) if is_admin: # For admins, /groups returns *all* groups. As a workaround # we check if we are a member of each group in the whitelist for group in map(url_escape, self.gitlab_group_whitelist): url = "%s/groups/%s/members/%d" % (GITLAB_API, group, user_id) req = HTTPRequest(url, method="GET", headers=headers) resp = yield http_client.fetch(req, raise_error=False) if resp.code == 200: return True # user _is_ in group else: # For regular users we get all the groups to which they have access # and check if any of these are in the whitelisted groups next_page = url_concat("%s/groups" % GITLAB_API, dict(all_available=True)) while next_page: req = HTTPRequest(next_page, method="GET", headers=headers) resp = yield http_client.fetch(req) resp_json = json.loads(resp.body.decode('utf8', 'replace')) next_page = next_page_from_links(resp) user_groups = set(entry["path"] for entry in resp_json) # check if any of the organizations seen thus far are in whitelist if len(self.gitlab_group_whitelist & user_groups) > 0: return True return False
def authorize_redirect( self, redirect_uri: str = None, client_id: str = None, client_secret: str = None, extra_params: Dict[str, Any] = None, scope: str = None, response_type: str = "code", ) -> None: """Redirects the user to obtain OAuth authorization for this service. Some providers require that you register a redirect URL with your application instead of passing one via this method. You should call this method to log the user in, and then call ``get_authenticated_user`` in the handler for your redirect URL to complete the authorization process. .. versionchanged:: 6.0 The ``callback`` argument and returned awaitable were removed; this is now an ordinary synchronous function. """ handler = cast(RequestHandler, self) args = {"response_type": response_type} if redirect_uri is not None: args["redirect_uri"] = redirect_uri if client_id is not None: args["client_id"] = client_id if extra_params: args.update(extra_params) if scope: args["scope"] = " ".join(scope) url = self._OAUTH_AUTHORIZE_URL # type: ignore handler.redirect(url_concat(url, args))
def _get_certivox_server_secret_share_dta(self, expires): path = 'serverSecret' url_params = url_concat('{0}{1}'.format(Keys.certivoxServer(), path), { 'app_id': self.app_id, 'expires': expires, 'signature': signMessage('{0}{1}{2}'.format(path, self.app_id, expires), self.app_key) }) log.debug('MIRACL server secret request: {0}'.format(url_params)) httpclient = tornado.httpclient.HTTPClient() try: response = httpclient.fetch(url_params, **fetchConfig(url_params)) except tornado.httpclient.HTTPError as e: log.error(e) raise SecretsError('Unable to get Server Secret from the MIRACL TA server') httpclient.close() try: data = json.loads(response.body) except ValueError as e: log.error(e) raise SecretsError('Invalid response from TA server') if 'serverSecret' not in data: raise SecretsError('serverSecret not in response from TA server') return data["serverSecret"]
async def get(self): self.statsd.incr('login.request') user = self.current_user if user: # set new login cookie # because single-user cookie may have been cleared or incorrect self.set_login_cookie(user) self.redirect(self.get_next_url(user), permanent=False) else: if self.authenticator.auto_login: auto_login_url = self.authenticator.login_url(self.hub.base_url) if auto_login_url == self.settings['login_url']: # auto_login without a custom login handler # means that auth info is already in the request # (e.g. REMOTE_USER header) user = await self.login_user() if user is None: # auto_login failed, just 403 raise web.HTTPError(403) else: self.redirect(self.get_next_url(user)) else: if self.get_argument('next', default=False): auto_login_url = url_concat( auto_login_url, {'next': self.get_next_url()} ) self.redirect(auto_login_url) return username = self.get_argument('username', default='') self.finish(self._render(username=username))
def post(self): form = Form(self.request.arguments, shop_schema) if not form.validate(): return self.render("distributor/shop.html", form=form, error="error") if form.url.value: form.url.value = form.url.value.lower() if not re.match(r"https?", form.url.value): form.url.value = "http://" + form.url.value shop_id = self.get_argument("id") distributor_shop = self.db.get("select * from distributor_shop where deleted =0 and id = %s", shop_id) distributor_id = distributor_shop.distributor_id self.db.execute( "update distributor_shop set name = %s,taobao_nick= %s,money_manager = %s,url = %s " "where id = %s", form.name.value.strip(), form.taobao_nick.value.strip(), form.money_manager.value, form.url.value, shop_id, ) self.redirect( url_concat( self.reverse_url("distributor.show_shop_list"), {"distributor_id": distributor_id, "id": shop_id} ) )
def post(self): form = Form(self.request.arguments, shop_schema) if not form.validate(): return self.render("distributor/shop.html", form=form, error="error") if form.url.value: form.url.value = form.url.value.lower() if not re.match(r"https?", form.url.value): form.url.value = "http://" + form.url.value distributor_id = self.get_argument("distributor-id") distributor = self.db.get("select name from distributor where id = %s", distributor_id) # 新建分销商铺 shop_id = self.db.execute_lastrowid( "insert into distributor_shop (distributor_id,name,taobao_nick,money_manager," "url,distributor_name,created_at,created_by) values (%s,%s,%s,%s,%s,%s,now(),%s)", distributor_id, form.name.value.strip(), form.taobao_nick.value.strip(), form.money_manager.value, form.url.value, distributor.name, self.current_user.name, ) self.redirect(url_concat(self.reverse_url("distributor.show_shop_list"), {"distributor_id": distributor_id}))
def test_login_redirect(app, running, next_url, location): cookies = yield app.login_user('river') user = app.users['river'] if location: location = ujoin(app.base_url, location) else: # use default url location = user.url url = 'login' if next_url: if '//' not in next_url: next_url = ujoin(app.base_url, next_url, '') url = url_concat(url, dict(next=next_url)) if running and not user.active: # ensure running yield user.spawn() elif user.active and not running: # ensure not running yield user.stop() r = yield get_page(url, app, cookies=cookies, allow_redirects=False) r.raise_for_status() assert r.status_code == 302 assert location == r.headers['Location']
def query(self, callback, query, *args, **kw): method = kw.get("method", "POST") result_format = kw.get("result_format", DEFAULT_FORMAT) content_type = DEFAULT_CONTENT_TYPE headers = { "Content-Type": content_type, } params = { "query": query, "format": result_format } url = self.endpoint_url if method == "GET": url = url_concat(url, params) body = None elif method == "POST": body = urllib.urlencode(params) request = HTTPRequest(url=url, method=method, headers=headers, body=body, auth_username=self.user, auth_password=self.password, auth_mode=self.auth_mode ) response = yield gen.Task(self.client.fetch, request) callback(response, *args, **kw)
def post(self): contract_id = self.get_argument('contract_id') agent_id = self.get_argument('agent_id') self.db.execute('update contract set deleted = 1 where id = %s', contract_id) self.redirect(url_concat(self.reverse_url('agent.contract'), {'agent_id': agent_id}))
def getData(self,url,method,data,cookie): try: client = HTTPClient() request = HTTPRequest( url, method=method, headers={ 'Cookie':cookie } ) if data and method=="GET": url = url_concat(url,data) url = url.replace("+","%20") request.url = url elif data and method=="POST": realData = {} for i in data: realData[i[0]] = i[1] data = urllib.urlencode(realData) request.body = data response = client.fetch(request) return json.loads(response.body) except Exception,e: # print str(e) #traceback.print_exc() return str(e)
def get(self, name): current_user = self.get_current_user() if current_user and current_user.name == name: # logged in, spawn the server if current_user.spawner: if current_user.spawn_pending: # spawn has started, but not finished html = self.render_template("spawn_pending.html", user=current_user) self.finish(html) return # spawn has supposedly finished, check on the status status = yield current_user.spawner.poll() if status is not None: if current_user.spawner.options_form: self.redirect(url_path_join(self.hub.server.base_url, 'spawn')) return else: yield self.spawn_single_user(current_user) # set login cookie anew self.set_login_cookie(current_user) without_prefix = self.request.uri[len(self.hub.server.base_url):] target = url_path_join(self.base_url, without_prefix) self.redirect(target) else: # not logged in to the right user, # clear any cookies and reload (will redirect to login) self.clear_login_cookie() self.redirect(url_concat( self.settings['login_url'], {'next': self.request.uri, }))
def watch(self, url_path, on_data, **kwargs): local_data = dict(buffer="") class WatchFuture(Future): def cancel(self): client.close() logging.debug("AsyncHTTPClient closed") def data_callback(data): split_data = data.split("\n") for index, fragment in enumerate(split_data): if index + 1 < len(split_data): on_data(json.loads(local_data["buffer"] + fragment)) local_data["buffer"] = "" else: local_data["buffer"] += fragment params = self.build_params(url_path, **kwargs) url = url_concat(self.build_url(url_path, **kwargs), params) request = HTTPRequest( url=url, method="GET", headers=self.build_headers(), request_timeout=3600, streaming_callback=data_callback) client = AsyncHTTPClient(force_instance=True) future = WatchFuture() chain_future(client.fetch(request), future) return future
async def get_submits(self): start, size = 0, 50 while True: url = httputil.url_concat(self.status_url, gen_status_params(self.account.nickname, start, size)) response = await self.fetch(url) res = json.loads(response.body.decode('utf-8')) status_data = res['aaData'] if len(status_data) == 0: break status_list = [] for row in status_data: run_time = row[5][:-3] if row[5] != '' else '-1' memory = row[6][:-3] if row[6] != '' else '-1' status = { 'type': DataType.Submit, 'account': self.account, 'status': submit.SubmitStatus.BROKEN, 'run_id': row[1], 'pro_id': row[2], 'result': row[3], 'lang': row[4], 'run_time': run_time, 'memory': memory, 'submit_time': row[8], 'code': None } status_list.append(status) logger.debug('{} {} Success to get {} new status'.format( self.TAG, self.account, len(status_list))) self.put_queue(status_list) start += size
def authorize_redirect(self, redirect_uri=None, client_id=None, client_secret=None, extra_params=None, callback=None, scope=None, response_type="code"): """Redirects the user to obtain OAuth authorization for this service. Some providers require that you register a redirect URL with your application instead of passing one via this method. You should call this method to log the user in, and then call ``get_authenticated_user`` in the handler for your redirect URL to complete the authorization process. .. versionchanged:: 3.1 Returns a `.Future` and takes an optional callback. These are not strictly necessary as this method is synchronous, but they are supplied for consistency with `OAuthMixin.authorize_redirect`. .. deprecated:: 5.1 The ``callback`` argument and returned awaitable will be removed in Tornado 6.0; this will be an ordinary synchronous function. """ args = { "redirect_uri": redirect_uri, "client_id": client_id, "response_type": response_type } if extra_params: args.update(extra_params) if scope: args['scope'] = ' '.join(scope) self.redirect( url_concat(self._OAUTH_AUTHORIZE_URL, args)) callback()
def get(self): url, method = TOGGL_API.time_entries today = datetime.datetime.today() end_date = today + datetime.timedelta(days=1) start_date = datetime.datetime.today() - datetime.timedelta(days=5) start_date = tz.localize( datetime.datetime(start_date.year, start_date.month, start_date.day) ).isoformat() end_date = tz.localize( datetime.datetime(end_date.year, end_date.month, end_date.day) ).isoformat() params = {"start_date": start_date, "end_date": end_date, } url = url_concat(url, params) res = yield tornado.httpclient.AsyncHTTPClient().fetch( request=url, method=method, auth_username=username, auth_password=password, ) time_entries = tornado.escape.json_decode(res.body) time_entries.reverse() redis_db["time_entries"] = redis_encode(time_entries) self.redirect("/") logging.info("entries params = %s\nlen = %s" % ( params, len(time_entries)))
def get(self): # we can append next to the redirect uri, so the user gets the # correct URL on login redirect_uri = url_concat(self.request.protocol + "://" + self.request.host + self.settings["github_callback_path"], {"next": self.get_argument('next', '/')}) # if we have a code, we have been authorized so we can log in if self.get_argument("code", False): user = yield self.get_authenticated_user( redirect_uri=redirect_uri, client_id=self.settings["github_client_id"], client_secret=self.settings["github_client_secret"], code=self.get_argument("code")) if user: log.info('logged in user from github: ' + str(user)) self.set_secure_cookie("user", json_encode(user)) else: self.clear_cookie("user") self.redirect(self.get_argument("next","/")) return # otherwise we need to request an authorization code self.authorize_redirect( redirect_uri=redirect_uri, client_id=self.settings["github_client_id"], extra_params={"scope": self.settings['github_scope'], "foo":1})
def getData(self,url,method,data,cookie): try: client = HTTPClient() request = HTTPRequest( url, method=method, headers={ 'Cookie':cookie } ) if data and method=="GET": data = json.loads(data) url = url_concat(url,data) request.url = url elif data and method=="POST": data = json.loads(data) print data data = urllib.urlencode(data) request.body = data # print request.url response = client.fetch(request) return response.body except Exception,e: # print str(e) return None
def authorize_redirect(self, redirect_uri=None, client_id=None, client_secret=None, extra_params=None, callback=None): """Redirects the user to obtain OAuth authorization for this service. Some providers require that you register a redirect URL with your application instead of passing one via this method. You should call this method to log the user in, and then call ``get_authenticated_user`` in the handler for your redirect URL to complete the authorization process. .. versionchanged:: 3.1 Returns a `.Future` and takes an optional callback. These are not strictly necessary as this method is synchronous, but they are supplied for consistency with `OAuthMixin.authorize_redirect`. """ args = { "redirect_uri": redirect_uri, "client_id": client_id } if extra_params: args.update(extra_params) self.redirect( url_concat(self._OAUTH_AUTHORIZE_URL, args)) callback()
def _generate_escaped_url(self, url, args): """Takes in a dictionary of arguments and returns a URL line. Sorts the arguments so that the returned string is predictable and in alphabetical order. Effectively wraps the tornado.httputil.url_concat method and properly strips out None values, as well as lowercases Bool values. Args: url: (Str) The URL to append the arguments to args: (Dict) Key/Value arguments. Values should be primitives. Returns: A URL encoded string like this: <url>?foo=bar&abc=xyz """ # Remove keys from the arguments where the value is None args = dict((k, v) for k, v in args.iteritems() if v) # Convert all Bool values to lowercase strings for key, value in args.iteritems(): if type(value) is bool: args[key] = str(value).lower() # Now generate the URL full_url = httputil.url_concat(url, sorted(args.items())) self.log.debug('Generated URL: %s' % full_url) return full_url
async def authenticate(self, handler, data=None): code = handler.get_argument(name="code") # TODO: Configure the curl_httpclient for tornado http_client = AsyncHTTPClient() params = dict(redirect_uri=self.get_callback_url(handler), code=code, grant_type='authorization_code') params.update(self.extra_params) if self.token_url: url = self.token_url else: raise ValueError( "Please set the OAUTH2_TOKEN_URL environment variable") headers = {"Accept": "application/json", "User-Agent": "JupyterHub"} if self.basic_auth: b64key = base64.b64encode( bytes("{}:{}".format(self.client_id, self.client_secret), "utf8")) headers.update( {"Authorization": "Basic {}".format(b64key.decode("utf8"))}) req = HTTPRequest( url, method="POST", headers=headers, validate_cert=self.tls_verify, body=urllib.parse.urlencode( params) # Body is required for a POST... ) resp = await http_client.fetch(req) resp_json = json.loads(resp.body.decode('utf8', 'replace')) access_token = resp_json['access_token'] refresh_token = resp_json.get('refresh_token', None) token_type = resp_json['token_type'] scope = resp_json.get('scope', '') if (isinstance(scope, str)): scope = scope.split(' ') # Determine who the logged in user is headers = { "Accept": "application/json", "User-Agent": "JupyterHub", "Authorization": "{} {}".format(token_type, access_token) } if self.userdata_url: url = url_concat(self.userdata_url, self.userdata_params) else: raise ValueError( "Please set the OAUTH2_USERDATA_URL environment variable") if self.userdata_token_method == "url": url = url_concat(self.userdata_url, dict(access_token=access_token)) req = HTTPRequest( url, method=self.userdata_method, headers=headers, validate_cert=self.tls_verify, ) resp = await http_client.fetch(req) resp_json = json.loads(resp.body.decode('utf8', 'replace')) if not resp_json.get(self.username_key): self.log.error("OAuth user contains no key %s: %s", self.username_key, resp_json) return return { 'name': resp_json.get(self.username_key), 'auth_state': { 'access_token': access_token, 'refresh_token': refresh_token, 'oauth_user': resp_json, 'scope': scope, } }
def authenticate(self, handler, data=None): code = handler.get_argument("code") # TODO: Configure the curl_httpclient for tornado http_client = AsyncHTTPClient() # Exchange the OAuth code for a GitLab Access Token # # See: https://github.com/gitlabhq/gitlabhq/blob/master/doc/api/oauth2.md # GitLab specifies a POST request yet requires URL parameters params = dict( client_id=self.client_id, client_secret=self.client_secret, code=code, grant_type="authorization_code", redirect_uri=self.get_callback_url(handler), ) validate_server_cert = self.validate_server_cert url = url_concat("%s/oauth/token" % GITLAB_HOST, params) req = HTTPRequest( url, method="POST", headers={"Accept": "application/json"}, validate_cert=validate_server_cert, body='' # Body is required for a POST... ) resp = yield http_client.fetch(req) resp_json = json.loads(resp.body.decode('utf8', 'replace')) access_token = resp_json['access_token'] # Determine who the logged in user is req = HTTPRequest("%s/user" % GITLAB_API, method="GET", validate_cert=validate_server_cert, headers=_api_headers(access_token)) resp = yield http_client.fetch(req) resp_json = json.loads(resp.body.decode('utf8', 'replace')) username = resp_json["username"] user_id = resp_json["id"] is_admin = resp_json.get("is_admin", False) # Check if user is a member of any whitelisted organizations. # This check is performed here, as it requires `access_token`. if self.gitlab_group_whitelist: user_in_group = yield self._check_group_whitelist( username, user_id, is_admin, access_token) if not user_in_group: self.log.warning("%s not in group whitelist", username) return None return { 'name': username, 'auth_state': { 'access_token': access_token, 'gitlab_user': resp_json, } }
def github_api_request(self, api_url, etag=None): client = AsyncHTTPClient() if self.auth: # Add auth params. After logging! api_url = url_concat(api_url, self.auth) headers = {} if etag: headers['If-None-Match'] = etag req = HTTPRequest(api_url, headers=headers, user_agent="BinderHub") try: resp = yield client.fetch(req) except HTTPError as e: if e.code == 304: resp = e.response elif (e.code == 403 and e.response and e.response.headers.get('x-ratelimit-remaining') == '0'): rate_limit = e.response.headers['x-ratelimit-limit'] reset_timestamp = int(e.response.headers['x-ratelimit-reset']) reset_seconds = int(reset_timestamp - time.time()) self.log.error( "GitHub Rate limit ({limit}) exceeded. Reset in {delta}.". format( limit=rate_limit, delta=timedelta(seconds=reset_seconds), )) # round expiry up to nearest 5 minutes minutes_until_reset = 5 * (1 + (reset_seconds // 60 // 5)) raise ValueError( "GitHub rate limit exceeded. Try again in %i minutes." % minutes_until_reset) # Status 422 is returned by the API when we try and resolve a non # existent reference elif e.code in (404, 422): return None else: raise # record and log github rate limit remaining = int(resp.headers['x-ratelimit-remaining']) rate_limit = int(resp.headers['x-ratelimit-limit']) reset_timestamp = int(resp.headers['x-ratelimit-reset']) # record with prometheus GITHUB_RATE_LIMIT.set(remaining) # log at different levels, depending on remaining fraction fraction = remaining / rate_limit if fraction < 0.2: log = self.log.warning elif fraction < 0.5: log = self.log.info else: log = self.log.debug # str(timedelta) looks like '00:32' delta = timedelta(seconds=int(reset_timestamp - time.time())) log("GitHub rate limit remaining {remaining}/{limit}. Reset in {delta}." .format( remaining=remaining, limit=rate_limit, delta=delta, )) return resp
def get(self, name, user_path): if not user_path: user_path = '/' current_user = self.get_current_user() if current_user and current_user.name == name: # if spawning fails for any reason, point users to /hub/home to retry self.extra_error_html = self.spawn_home_error # If people visit /user/:name directly on the Hub, # the redirects will just loop, because the proxy is bypassed. # Try to check for that and warn, # though the user-facing behavior is unchanged host_info = urlparse(self.request.full_url()) port = host_info.port if not port: port = 443 if host_info.scheme == 'https' else 80 if port != Server.from_url( self.proxy.public_url ).connect_port and port == self.hub.connect_port: self.log.warning( """ Detected possible direct connection to Hub's private ip: %s, bypassing proxy. This will result in a redirect loop. Make sure to connect to the proxied public URL %s """, self.request.full_url(), self.proxy.public_url) # logged in as correct user, check for pending spawn spawner = current_user.spawner # First, check for previous failure. if (not spawner.active and spawner._spawn_future and spawner._spawn_future.done() and spawner._spawn_future.exception()): # Condition: spawner not active and _spawn_future exists and contains an Exception # Implicit spawn on /user/:name is not allowed if the user's last spawn failed. # We should point the user to Home if the most recent spawn failed. exc = spawner._spawn_future.exception() self.log.error( "Preventing implicit spawn for %s because last spawn failed: %s", spawner._log_name, exc) # raise a copy because each time an Exception object is re-raised, its traceback grows raise copy.copy(exc).with_traceback(exc.__traceback__) # check for pending spawn if spawner.pending and spawner._spawn_future: # wait on the pending spawn self.log.debug("Waiting for %s pending %s", spawner._log_name, spawner.pending) try: yield gen.with_timeout( timedelta(seconds=self.slow_spawn_timeout), spawner._spawn_future) except gen.TimeoutError: self.log.info( "Pending spawn for %s didn't finish in %.1f seconds", spawner._log_name, self.slow_spawn_timeout) pass # we may have waited above, check pending again: if spawner.pending: self.log.info("%s is pending %s", spawner._log_name, spawner.pending) # spawn has started, but not finished self.statsd.incr('redirects.user_spawn_pending', 1) html = self.render_template("spawn_pending.html", user=current_user) self.finish(html) return # spawn has supposedly finished, check on the status if spawner.ready: status = yield spawner.poll() else: status = 0 # server is not running, trigger spawn if status is not None: if spawner.options_form: self.redirect( url_concat(url_path_join(self.hub.base_url, 'spawn'), {'next': self.request.uri})) return else: yield self.spawn_single_user(current_user) # spawn didn't finish, show pending page if spawner.pending: self.log.info("%s is pending %s", spawner._log_name, spawner.pending) # spawn has started, but not finished self.statsd.incr('redirects.user_spawn_pending', 1) html = self.render_template("spawn_pending.html", user=current_user) self.finish(html) return # We do exponential backoff here - since otherwise we can get stuck in a redirect loop! # This is important in many distributed proxy implementations - those are often eventually # consistent and can take upto a couple of seconds to actually apply throughout the cluster. try: redirects = int(self.get_argument('redirects', 0)) except ValueError: self.log.warning("Invalid redirects argument %r", self.get_argument('redirects')) redirects = 0 # check redirect limit to prevent browser-enforced limits. # In case of version mismatch, raise on only two redirects. if redirects >= self.settings.get('user_redirect_limit', 4) or ( redirects >= 2 and spawner._jupyterhub_version != __version__): # We stop if we've been redirected too many times. msg = "Redirect loop detected." if spawner._jupyterhub_version != __version__: msg += ( " Notebook has jupyterhub version {singleuser}, but the Hub expects {hub}." " Try installing jupyterhub=={hub} in the user environment" " if you continue to have problems.").format( singleuser=spawner._jupyterhub_version or 'unknown (likely < 0.8)', hub=__version__, ) raise web.HTTPError(500, msg) # set login cookie anew self.set_login_cookie(current_user) without_prefix = self.request.uri[len(self.hub.base_url):] target = url_path_join(self.base_url, without_prefix) if self.subdomain_host: target = current_user.host + target # record redirect count in query parameter if redirects: self.log.warning("Redirect loop detected on %s", self.request.uri) # add capped exponential backoff where cap is 10s yield gen.sleep(min(1 * (2**redirects), 10)) # rewrite target url with new `redirects` query value url_parts = urlparse(target) query_parts = parse_qs(url_parts.query) query_parts['redirects'] = redirects + 1 url_parts = url_parts._replace(query=urlencode(query_parts)) target = urlunparse(url_parts) else: target = url_concat(target, {'redirects': 1}) self.redirect(target) self.statsd.incr('redirects.user_after_login') elif current_user: # logged in as a different user, redirect self.statsd.incr('redirects.user_to_user', 1) target = url_path_join(current_user.url, user_path or '') self.redirect(target) else: # not logged in, clear any cookies and reload self.statsd.incr('redirects.user_to_login', 1) self.clear_login_cookie() self.redirect( url_concat( self.settings['login_url'], {'next': self.request.uri}, ))
async def generate_url( self, user: str, role: str, region: str = "us-east-1", user_role: bool = False, account_id: str = None, ) -> str: """Generate URL will get temporary credentials and craft a URL with those credentials.""" function = ( f"{__name__}.{self.__class__.__name__}.{sys._getframe().f_code.co_name}" ) log_data = { "function": function, "user": user, "role": role, "message": "Generating authenticated AWS console URL", } log.debug(log_data) credentials = await self.get_credentials( user, role, user_role=user_role, account_id=account_id, enforce_ip_restrictions=False, ) credentials_d = { "sessionId": credentials.get("Credentials", {}).get("AccessKeyId"), "sessionKey": credentials.get("Credentials", {}).get("SecretAccessKey"), "sessionToken": credentials.get("Credentials", {}).get("SessionToken"), } req_params = { "Action": "getSigninToken", "Session": bleach.clean(json.dumps(credentials_d)), "DurationSeconds": config.get("aws.session_duration", 3600), } http_client = AsyncHTTPClient(force_instance=True) url_with_params: str = url_concat( config.get("aws.federation_url", "https://signin.aws.amazon.com/federation"), req_params, ) r = await http_client.fetch(url_with_params, ssl_options=ssl.SSLContext()) token = json.loads(r.body) login_req_params = { "Action": "login", "Issuer": config.get("aws.issuer"), "Destination": ("{}".format( config.get( "aws.console_url", "https://{}.console.aws.amazon.com").format(region))), "SigninToken": bleach.clean(token.get("SigninToken")), "SessionDuration": config.get("aws.session_duration", 3600), } r2 = requests_sync.Request( "GET", config.get("aws.federation_url", "https://signin.aws.amazon.com/federation"), params=login_req_params, ) url = r2.prepare().url return url
def test_url_concat_multi_same_query_params(self): url = url_concat( "https://localhost/path?r=1&r=2", [('y', 'y')], ) self.assertEqual(url, "https://localhost/path?r=1&r=2&y=y")
def test_url_concat_with_frag(self): url = url_concat( "https://localhost/path#tab", [('y', 'y')], ) self.assertEqual(url, "https://localhost/path?y=y#tab")
def _login_url(self): return url_concat(self.oauth_authorization_url, { 'client_id': self.oauth_client_id, 'redirect_uri': self.oauth_redirect_uri, 'response_type': 'code', })
def get(self, name, user_path): current_user = self.get_current_user() if current_user and current_user.name == name: # If people visit /user/:name directly on the Hub, # the redirects will just loop, because the proxy is bypassed. # Try to check for that and warn, # though the user-facing behavior is unchainged host_info = urlparse(self.request.full_url()) port = host_info.port if not port: port = 443 if host_info.scheme == 'https' else 80 if port != Server.from_url( self.proxy.public_url).port and port == self.hub.port: self.log.warning( """ Detected possible direct connection to Hub's private ip: %s, bypassing proxy. This will result in a redirect loop. Make sure to connect to the proxied public URL %s """, self.request.full_url(), self.proxy.public_url) # logged in as correct user, spawn the server if current_user.spawner: if current_user.spawn_pending: # spawn has started, but not finished self.statsd.incr('redirects.user_spawn_pending', 1) html = self.render_template("spawn_pending.html", user=current_user) self.finish(html) return # spawn has supposedly finished, check on the status status = yield current_user.spawner.poll() if status is not None: if current_user.spawner.options_form: self.redirect( url_concat( url_path_join(self.hub.base_url, 'spawn'), {'next': self.request.uri})) return else: yield self.spawn_single_user(current_user) # set login cookie anew self.set_login_cookie(current_user) without_prefix = self.request.uri[len(self.hub.base_url):] target = url_path_join(self.base_url, without_prefix) if self.subdomain_host: target = current_user.host + target self.redirect(target) self.statsd.incr('redirects.user_after_login') elif current_user: # logged in as a different user, redirect self.statsd.incr('redirects.user_to_user', 1) target = url_path_join(current_user.url, user_path or '') self.redirect(target) else: # not logged in, clear any cookies and reload self.statsd.incr('redirects.user_to_login', 1) self.clear_login_cookie() self.redirect( url_concat( self.settings['login_url'], {'next': self.request.uri}, ))
def get_method_url(cls, method, params=None): url = 'https://api.telegram.org/bot' + cls.bot_key + '/' + method if params is not None: url = url_concat(url, params) return url
def delete(url, params=None, callback=None, **kwargs): url = url_concat(url, params) return session("DELETE", url, callback=None, **kwargs)
def get_messages_from_person(person_id, num): params = {"seed": person_id, "numMessages": num} return url_concat(ENDPOINT_URL_PREFIX + "get_messages_from_person", params)
def test_url_concat_trailing_q(self): url = url_concat( "https://localhost/path?", [('y', 'y'), ('z', 'z')], ) self.assertEqual(url, "https://localhost/path?y=y&z=z")
def test_url_concat_no_query_params(self): url = url_concat( "https://localhost/path", [('y', 'y'), ('z', 'z')], ) self.assertEqual(url, "https://localhost/path?y=y&z=z")
def test_url_concat_mult_params(self): url = url_concat( "https://localhost/path?a=1&b=2", [('y', 'y'), ('z', 'z')], ) self.assertEqual(url, "https://localhost/path?a=1&b=2&y=y&z=z")
def authenticate(self, handler, data=None): """We set up auth_state based on additional GitHub info if we receive it. """ code = handler.get_argument("code") # TODO: Configure the curl_httpclient for tornado http_client = AsyncHTTPClient() # Exchange the OAuth code for a GitHub Access Token # # See: https://developer.github.com/v3/oauth/ # GitHub specifies a POST request yet requires URL parameters params = dict( client_id=self.client_id, client_secret=self.client_secret, code=code ) url = url_concat("%s://%s/login/oauth/access_token" % (GITHUB_PROTOCOL, GITHUB_HOST), params) req = HTTPRequest(url, method="POST", headers={"Accept": "application/json"}, body='' # Body is required for a POST... ) resp = yield http_client.fetch(req) resp_json = json.loads(resp.body.decode('utf8', 'replace')) if 'access_token' in resp_json: access_token = resp_json['access_token'] elif 'error_description' in resp_json: raise HTTPError(403, "An access token was not returned: {}".format( resp_json['error_description'])) else: raise HTTPError(500, "Bad response: %s".format(resp)) # Determine who the logged in user is req = HTTPRequest("%s://%s/user" % (GITHUB_PROTOCOL, GITHUB_API), method="GET", headers=_api_headers(access_token) ) resp = yield http_client.fetch(req) resp_json = json.loads(resp.body.decode('utf8', 'replace')) username = resp_json["login"] # username is now the GitHub userid. if not username: return None # Check if user is a member of any whitelisted organizations. # This check is performed here, as it requires `access_token`. if self.github_organization_whitelist: for org in self.github_organization_whitelist: user_in_org = yield self._check_organization_whitelist(org, username, access_token) if user_in_org: break else: # User not found in member list for any organisation self.log.warning("User %s is not in org whitelist", username) return None userdict = {"name": username} # Now we set up auth_state userdict["auth_state"] = auth_state = {} # Save the access token and full GitHub reply (name, id, email) in auth state # These can be used for user provisioning in the Lab/Notebook environment. # e.g. # 1) stash the access token # 2) use the GitHub ID as the id # 3) set up name/email for .gitconfig auth_state['access_token'] = access_token # store the whole user model in auth_state.github_user auth_state['github_user'] = resp_json # A public email will return in the initial query (assuming default scope). # Private will not. return userdict
def test_url_concat_multi_same_params(self): url = url_concat( "https://localhost/path", [('y', 'y1'), ('y', 'y2')], ) self.assertEqual(url, "https://localhost/path?y=y1&y=y2")
def login_url(self, base_url): return url_concat(url_path_join(base_url, 'external-login'), {'redirect-to': self.external_login_url})
def test_url_concat_dict_params(self): url = url_concat( "https://localhost/path", dict(y='y'), ) self.assertEqual(url, "https://localhost/path?y=y")
def _paginate(self, data=None, data_generator=None, sort=None): arg_page = self._get_page() arg_limit = self._get_limit() headers = { 'X-Pagination-Page': arg_page, 'X-Pagination-Limit': arg_limit } first_page = arg_page if arg_page > 0 else 1 previous_page = None if arg_page <= 1 else arg_page - 1 if data_generator: results = list(data_generator())[:arg_limit] next_page = None if len(results) < arg_limit else arg_page + 1 last_page = None else: arg_sort = self._get_sort(default=sort) start = (arg_page - 1) * arg_limit end = start + arg_limit results = data if arg_sort: # Compare to earliest datetime instead of None def safe_compare(field, results): if field == 'airDate' and results[field] is None: return text_type(datetime.min) return results[field] try: for field, reverse in reversed(arg_sort): results = sorted(results, key=partial(safe_compare, field), reverse=reverse) except KeyError: return self._bad_request('Invalid sort query parameter') count = len(results) headers['X-Pagination-Count'] = count results = results[start:end] next_page = None if end > count else arg_page + 1 last_page = ((count - 1) // arg_limit) + 1 headers['X-Pagination-Total'] = last_page if last_page <= arg_page: last_page = None # Reconstruct the query parameters query_params = [] for arg, values in viewitems(self.request.query_arguments): if arg in ('page', 'limit'): continue if not isinstance(values, list): values = [values] query_params += [(arg, value) for value in values] bare_uri = url_concat(self.request.path, query_params) links = [] for rel, page in (('next', next_page), ('last', last_page), ('first', first_page), ('previous', previous_page)): if page is None: continue uri = url_concat(bare_uri, dict(page=page, limit=arg_limit)) link = '<{uri}>; rel="{rel}"'.format(uri=uri, rel=rel) links.append(link) self.set_header('Link', ', '.join(links)) return self._ok(data=results, headers=headers)
def get(self, name, user_path): current_user = self.get_current_user() if current_user and current_user.name == name: # If people visit /user/:name directly on the Hub, # the redirects will just loop, because the proxy is bypassed. # Try to check for that and warn, # though the user-facing behavior is unchainged host_info = urlparse(self.request.full_url()) port = host_info.port if not port: port = 443 if host_info.scheme == 'https' else 80 if port != Server.from_url( self.proxy.public_url ).connect_port and port == self.hub.connect_port: self.log.warning( """ Detected possible direct connection to Hub's private ip: %s, bypassing proxy. This will result in a redirect loop. Make sure to connect to the proxied public URL %s """, self.request.full_url(), self.proxy.public_url) # logged in as correct user, spawn the server spawner = current_user.spawner if spawner._spawn_pending or spawner._proxy_pending: # spawn has started, but not finished self.statsd.incr('redirects.user_spawn_pending', 1) html = self.render_template("spawn_pending.html", user=current_user) self.finish(html) return # spawn has supposedly finished, check on the status status = yield spawner.poll() if status is not None: if spawner.options_form: self.redirect( url_concat(url_path_join(self.hub.base_url, 'spawn'), {'next': self.request.uri})) return else: yield self.spawn_single_user(current_user) # We do exponential backoff here - since otherwise we can get stuck in a redirect loop! # This is important in many distributed proxy implementations - those are often eventually # consistent and can take upto a couple of seconds to actually apply throughout the cluster. try: redirects = int(self.get_argument('redirects', 0)) except ValueError: self.log.warning("Invalid redirects argument %r", self.get_argument('redirects')) redirects = 0 if redirects >= self.settings.get('user_redirect_limit', 5): # We stop if we've been redirected too many times. raise web.HTTPError(500, "Redirect loop detected.") # set login cookie anew self.set_login_cookie(current_user) without_prefix = self.request.uri[len(self.hub.base_url):] target = url_path_join(self.base_url, without_prefix) if self.subdomain_host: target = current_user.host + target # record redirect count in query parameter if redirects: self.log.warning("Redirect loop detected on %s", self.request.uri) # add capped exponential backoff where cap is 10s yield gen.sleep(min(1 * (2**redirects), 10)) # rewrite target url with new `redirects` query value url_parts = urlparse(target) query_parts = parse_qs(url_parts.query) query_parts['redirects'] = redirects + 1 url_parts = url_parts._replace(query=urlencode(query_parts)) target = urlunparse(url_parts) else: target = url_concat(target, {'redirects': 1}) self.redirect(target) self.statsd.incr('redirects.user_after_login') elif current_user: # logged in as a different user, redirect self.statsd.incr('redirects.user_to_user', 1) target = url_path_join(current_user.url, user_path or '') self.redirect(target) else: # not logged in, clear any cookies and reload self.statsd.incr('redirects.user_to_login', 1) self.clear_login_cookie() self.redirect( url_concat( self.settings['login_url'], {'next': self.request.uri}, ))
def test_url_concat_no_params(self): url = url_concat( "https://localhost/path?r=1&t=2", {}, ) self.assertEqual(url, "https://localhost/path?r=1&t=2")
def authenticate(self, handler, data=None): """We set up auth_state based on additional CILogon info if we receive it. """ code = handler.get_argument("code") # TODO: Configure the curl_httpclient for tornado http_client = AsyncHTTPClient() # Exchange the OAuth code for a CILogon Access Token # See: http://www.cilogon.org/oidc headers = { "Accept": "application/json", "User-Agent": "JupyterHub", } params = dict( client_id=self.client_id, client_secret=self.client_secret, redirect_uri=self.oauth_callback_url, code=code, grant_type='authorization_code', ) url = url_concat("https://%s/oauth2/token" % CILOGON_HOST, params) req = HTTPRequest(url, headers=headers, method="POST", body='' ) resp = yield http_client.fetch(req) token_response = json.loads(resp.body.decode('utf8', 'replace')) access_token = token_response['access_token'] self.log.info("Access token acquired.") # Determine who the logged in user is params = dict(access_token=access_token) req = HTTPRequest(url_concat("https://%s/oauth2/userinfo" % CILOGON_HOST, params), headers=headers ) resp = yield http_client.fetch(req) resp_json = json.loads(resp.body.decode('utf8', 'replace')) self.log.info("Userinfo response JSON: %s" % resp_json) username = resp_json.get(self.username_claim) if not username: self.log.error("Username claim %s not found in the response: %s", self.username_claim, sorted(resp_json.keys()) ) raise web.HTTPError(500, "Failed to get username from CILogon") if self.idp_whitelist: gotten_name, gotten_idp = username.split('@') if gotten_idp not in self.idp_whitelist: self.log.error( "Trying to login from not whitelisted domain %s", gotten_idp) raise web.HTTPError( 500, "Trying to login from not whitelisted domain") if len(self.idp_whitelist) == 1 and self.strip_idp_domain: username = gotten_name if self.comanage_group_whitelist: self.log.debug("comanage_group_whitelist %s" % self.comanage_group_whitelist) gotten_groups = resp_json.get(self.ismemberof_claim) self.log.info("Gotten groups from response: %s type: %s" % (gotten_groups, type(gotten_groups))) if gotten_groups is None: gotten_groups = [] allowed = False okgroup = None for goodgroup in self.comanage_group_whitelist: if goodgroup in gotten_groups: okgroup = goodgroup allowed = True if allowed: self.log.info("User authorized by membership in %s" % okgroup) else: raise web.HTTPError( 500, "User belongs to no authorized groups. Presented groups: %s" % gotten_groups) else: raise web.HTTPError( 500, "No groups whitelisted in configuration! Why use COManage?") userdict = {"name": username} # Now we set up auth_state userdict["auth_state"] = auth_state = {} # Save the token response and full CILogon reply in auth state # These can be used for user provisioning # in the Lab/Notebook environment. auth_state['token_response'] = token_response # store the whole user model in auth_state.cilogon_user # keep access_token as well, in case anyone was relying on it auth_state['access_token'] = access_token auth_state['cilogon_user'] = resp_json return userdict
def gen_link(self, page): return url_concat(self.path, dict(self.args, page=page))
def get(self): # issue a fake auth code and redirect to redirect_uri code = 'fake-authorization-code' self.redirect( url_concat(self.get_argument('redirect_uri'), dict(code=code)))
async def authenticate(self, handler, data=None): """We set up auth_state based on additional CILogon info if we receive it. """ code = handler.get_argument("code") # Exchange the OAuth code for a CILogon Access Token # See: http://www.cilogon.org/oidc headers = {"Accept": "application/json", "User-Agent": "JupyterHub"} params = dict( client_id=self.client_id, client_secret=self.client_secret, redirect_uri=self.oauth_callback_url, code=code, grant_type='authorization_code', ) url = url_concat(self.token_url, params) req = HTTPRequest(url, headers=headers, method="POST", body='') token_response = await self.fetch(req) access_token = token_response['access_token'] # Determine who the logged in user is params = dict(access_token=access_token) req = HTTPRequest( url_concat("https://%s/oauth2/userinfo" % self.cilogon_host, params), headers=headers, ) resp_json = await self.fetch(req) claimlist = [self.username_claim] if self.additional_username_claims: claimlist.extend(self.additional_username_claims) for claim in claimlist: username = resp_json.get(claim) if username: break if not username: if len(claimlist) < 2: self.log.error( "Username claim %s not found in response: %s", self.username_claim, sorted(resp_json.keys()), ) else: self.log.error( "No username claim from %r in response: %s", claimlist, sorted(resp_json.keys()), ) raise web.HTTPError(500, "Failed to get username from CILogon") if self.allowed_idps: gotten_name, gotten_idp = username.split('@') if gotten_idp not in self.allowed_idps: self.log.error("Trying to login from not allowed domain %s", gotten_idp) raise web.HTTPError( 500, "Trying to login from a domain not allowed") if len(self.allowed_idps) == 1 and self.strip_idp_domain: username = gotten_name userdict = {"name": username} # Now we set up auth_state userdict["auth_state"] = auth_state = {} # Save the token response and full CILogon reply in auth state # These can be used for user provisioning # in the Lab/Notebook environment. auth_state['token_response'] = token_response # store the whole user model in auth_state.cilogon_user # keep access_token as well, in case anyone was relying on it auth_state['access_token'] = access_token auth_state['cilogon_user'] = resp_json return userdict
def test_url_concat_encode_args(self): url = url_concat( "https://localhost/path", [('y', '/y'), ('z', 'z')], ) self.assertEqual(url, "https://localhost/path?y=%2Fy&z=z")
def get(self, user, repo, urlpath=None): url = '/v2/gh/{user}/{repo}/master'.format(user=user, repo=repo) if urlpath is not None and urlpath.strip('/'): url = url_concat(url, dict(urlpath=urlpath)) self.redirect(url)
def test_url_concat_q_with_no_trailing_amp(self): url = url_concat( "https://localhost/path?x", [('y', 'y'), ('z', 'z')], ) self.assertEqual(url, "https://localhost/path?x=&y=y&z=z")
def get(url, params=None, callback=None, **kwargs): url = url_concat(url, params) return session("GET", url, callback=None, **kwargs)