Пример #1
0
    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
Пример #2
0
 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)
Пример #3
0
 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)
Пример #4
0
    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
Пример #5
0
 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)
Пример #6
0
    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
Пример #7
0
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
Пример #8
0
    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
Пример #9
0
    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
Пример #10
0
    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
Пример #11
0
    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