def test_reassemble(self, temp_dir, common_obj): web = web_obj(temp_dir, common_obj, "share", 3) web.settings.set("share", "autostop_sharing", False) url = "/download" with open(web.share_mode.download_filename, "rb") as f: contents = f.read() with web.app.test_client() as client: headers = Headers() headers.extend({"Range": "bytes=0-10"}) resp = client.get(url, headers=headers) assert resp.status_code == 206 content_range = resp.headers["Content-Range"] assert content_range == "bytes {}-{}/{}".format( 0, 10, web.share_mode.download_filesize) bytes_out = resp.data headers.update({"Range": "bytes=11-100000"}) resp = client.get(url, headers=headers) assert resp.status_code == 206 content_range = resp.headers["Content-Range"] assert content_range == "bytes {}-{}/{}".format( 11, web.share_mode.download_filesize - 1, web.share_mode.download_filesize, ) bytes_out += resp.data assert bytes_out == contents
def open(self, *args, **kwargs): if kwargs.get("json") is not None: with self.session_transaction() as sess: api_key_headers = Headers({"CSRF-Token": sess.get("nonce")}) headers = kwargs.pop("headers", Headers()) if isinstance(headers, dict): headers = Headers(headers) headers.extend(api_key_headers) kwargs["headers"] = headers return super(CTFdTestClient, self).open(*args, **kwargs)
def open(self, *args, **kwargs): api_key_headers = Headers({ 'X-CSRFToken': self.csrf_token }) headers = kwargs.pop('headers', Headers()) if type(headers) is not Headers: headers = Headers(headers) headers.extend(api_key_headers) kwargs['headers'] = headers return super().open(*args, **kwargs)
def get(self): """ .. :quickref: OIDC; :status 200: OK :status 401: Unauthorized :resheader X-Rucio-Auth-Token: The authentication token :resheader X-Rucio-Auth-Token-Expires: The time when the token expires """ headers = Headers() headers.set('Access-Control-Allow-Origin', request.environ.get('HTTP_ORIGIN')) headers.set('Access-Control-Allow-Headers', request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS')) headers.set('Access-Control-Allow-Methods', '*') headers.set('Access-Control-Allow-Credentials', 'true') headers.set('Content-Type', 'application/octet-stream') headers.set('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate') headers.add('Cache-Control', 'post-check=0, pre-check=0') headers.set('Pragma', 'no-cache') query_string = request.query_string.decode(encoding='utf-8') ip = request.headers.get('X-Forwarded-For', default=request.remote_addr) try: result = get_token_oidc(query_string, ip) except AccessDenied: return generate_http_error_flask(401, 'CannotAuthorize', 'Cannot authorize token request.', headers=headers) except RucioException as error: return generate_http_error_flask(500, error.__class__.__name__, error.args[0], headers=headers) except Exception as error: logging.exception("Internal Error") return str(error), 500, headers if not result: return generate_http_error_flask(401, 'CannotAuthorize', 'Cannot authorize token request.', headers=headers) if 'token' in result and 'webhome' not in result: headers.set('X-Rucio-Auth-Token', result['token'].token) headers.set('X-Rucio-Auth-Token-Expires', date_to_str(result['token'].expired_at)) return '', 200, headers elif 'webhome' in result: webhome = result['webhome'] if webhome is None: headers.extend(error_headers('CannotAuthenticate', 'Cannot find your OIDC identity linked to any Rucio account')) headers.set('Content-Type', 'text/html') return render_template('auth_crash.html', crashtype='unknown_identity'), 401, headers # domain setting is necessary so that the token gets distributed also to the webui server domain = '.'.join(urlparse.urlparse(webhome).netloc.split('.')[1:]) response = redirect(webhome, code=303) response.headers.extend(headers) response.set_cookie('x-rucio-auth-token', value=result['token'].token, domain=domain, path='/') response.set_cookie('rucio-auth-token-created-at', value=str(time.time()), domain=domain, path='/') return response else: return '', 400, headers
def open(self, *args, **kwargs): headers = kwargs.pop('headers', Headers()) # https://github.com/pallets/werkzeug/blob/master/src/werkzeug/test.py if headers is None: headers = Headers() elif not isinstance(headers, Headers): headers = Headers(headers) credentials = kwargs.pop('credentials', self._credentials) disable_auth = kwargs.pop('disable_auth', False) if not disable_auth: headers.extend(Headers({"Authorization": f"Basic {credentials}"})) kwargs['headers'] = headers return super().open(*args, **kwargs)
def test_if_unmodified_since(self, temp_dir, common_obj): web = web_obj(temp_dir, common_obj, "share", 3) web.settings.set("share", "autostop_sharing", False) url = "/download" with web.app.test_client() as client: headers = Headers() resp = client.get(url, headers=headers) assert resp.status_code == 200 last_mod = resp.headers["Last-Modified"] headers.extend({"If-Unmodified-Since": last_mod}) resp = client.get(url, headers=headers) assert resp.status_code == 304
def generate_http_error_flask(status_code, exc_cls, exc_msg, headers=None): """ utitily function to generate a complete HTTP error response. :param status_code: The HTTP status code to generate a response for. :param exc_cls: The name of the exception class to send with the response. :param exc_msg: The error message. :returns: a Flask HTTP response object. :param headers: any default headers to send along. """ data, prioheaders = _error_response(exc_cls, exc_msg) headers = Headers(headers) headers.extend(prioheaders) try: return Response(status=status_code, headers=headers, content_type=prioheaders['Content-Type'], response=render_json(**data)) except Exception: print(data) raise
def test_mismatched_etags(self, temp_dir, common_obj): """RFC 7233 Section 3.2 The "If-Range" header field allows a client to "short-circuit" the second request. Informally, its meaning is as follows: if the representation is unchanged, send me the part(s) that I am requesting in Range; otherwise, send me the entire representation. """ web = web_obj(temp_dir, common_obj, "share", 3) web.settings.set("share", "autostop_sharing", False) url = "/download" with open(web.share_mode.download_filename, "rb") as f: contents = f.read() with web.app.test_client() as client: headers = Headers() resp = client.get(url, headers=headers) assert resp.status_code == 200 headers.extend({"If-Range": "mismatched etag", "Range": "bytes=10-100"}) resp = client.get(url, headers=headers) assert resp.status_code == 200 assert resp.data == contents
def test_firefox_like_behavior(self, temp_dir, common_obj): web = web_obj(temp_dir, common_obj, "share", 3) web.settings.set("share", "autostop_sharing", False) url = "/download" with web.app.test_client() as client: headers = Headers() resp = client.get(url, headers=headers) assert resp.status_code == 200 # Firefox sends these with all range requests etag = resp.headers["ETag"] last_mod = resp.headers["Last-Modified"] # make a request that uses the full header set headers.extend({ "Range": "bytes=0-10", "If-Unmodified-Since": last_mod, "If-Range": etag, }) resp = client.get(url, headers=headers) assert resp.status_code == 206
def get(self): """ .. :quickref: OIDC; :status 200: OK :status 401: Unauthorized """ headers = Headers() headers.set('Access-Control-Allow-Origin', request.environ.get('HTTP_ORIGIN')) headers.set('Access-Control-Allow-Headers', request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS')) headers.set('Access-Control-Allow-Methods', '*') headers.set('Access-Control-Allow-Credentials', 'true') headers.set('Content-Type', 'text/html') headers.set('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate') headers.add('Cache-Control', 'post-check=0, pre-check=0') headers.set('Pragma', 'no-cache') query_string = request.query_string.decode(encoding='utf-8') ip = request.headers.get('X-Forwarded-For', default=request.remote_addr) try: result = get_token_oidc(query_string, ip) except AccessDenied: headers.extend(error_headers('CannotAuthenticate', 'Cannot authorize your access, please check your access credentials')) return render_template('auth_crash.html', crashtype='contact'), 401, headers except Exception as error: logging.exception("Internal Error") headers.extend(error_headers(error.__class__.__name__, str(error.args[0]))) return render_template('auth_crash.html', crashtype='internal_error'), 500, headers if not result: headers.extend(error_headers('CannotAuthenticate', 'Cannot finalize your token request, no authorization content returned from the auth server')) return render_template('auth_crash.html', crashtype='no_result'), 401, headers if 'fetchcode' in result: return render_template('auth_granted.html', authcode=result['fetchcode']), 200, headers elif 'polling' in result and result['polling'] is True: return render_template('auth_granted.html', authcode='allok'), 200, headers else: headers.extend(error_headers('InvalidRequest', 'Cannot recognize and process your request')) return render_template('auth_crash.html', crashtype='bad_request'), 400, headers
def get(self): """ .. :quickref: OIDC; :status 200: OK :status 303: Redirect :status 401: Unauthorized :resheader X-Rucio-Auth-Token: The authentication token """ headers = Headers() headers.set('Access-Control-Allow-Origin', request.environ.get('HTTP_ORIGIN')) headers.set('Access-Control-Allow-Headers', request.environ.get('HTTP_ACCESS_CONTROL_REQUEST_HEADERS')) headers.set('Access-Control-Allow-Methods', '*') headers.set('Access-Control-Allow-Credentials', 'true') # interaction with web browser - display response in html format headers.set('Content-Type', 'text/html') headers.set('Cache-Control', 'no-cache, no-store, max-age=0, must-revalidate') headers.add('Cache-Control', 'post-check=0, pre-check=0') headers.set('Pragma', 'no-cache') try: fetchtoken = (request.headers.get('X-Rucio-Client-Fetch-Token', default=None) == 'True') query_string = request.query_string.decode(encoding='utf-8') result = redirect_auth_oidc(query_string, fetchtoken) except AccessDenied: headers.extend(error_headers('CannotAuthenticate', 'Cannot authorize your access, please check your access credentials')) return render_template('auth_crash.html', crashtype='contact'), 401, headers except Exception as error: logging.exception("Internal Error") headers.extend(error_headers(error.__class__.__name__, str(error.args[0]))) return render_template('auth_crash.html', crashtype='internal_error'), 500, headers if not result: headers.extend(error_headers('CannotAuthenticate', 'Cannot finalize your token request, no authorization content returned from the auth server')) return render_template('auth_crash.html', crashtype='no_result'), 401, headers if fetchtoken: # this is only a case of returning the final token to the Rucio Client polling # or requesting token after copy-pasting the Rucio code from the web page page headers.set('Content-Type', 'application/octet-stream') headers.set('X-Rucio-Auth-Token', result) return '', 200, headers else: response = redirect(result, code=303) response.headers.extend(headers) return response