Esempio n. 1
0
def test_images_options_newer_proxy(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    path = "/images/" + signed_ticket.id

    # Note: the daemon does not report GET since the ticket is write only, and
    # it supports only "zero" (simulating old daemon).
    daemon_allow = {"OPTIONS", "PUT", "PATCH"}
    daemon_features = {"zero"}

    daemon_options = {"features": list(daemon_features)}
    daemon_body = json.dumps(daemon_options).encode("ascii")
    daemon_headers = {"Content-Type": "application/json",
                      "Content-Length": "%d" % len(daemon_body),
                      "Allow": ','.join(daemon_allow)}

    with requests_mock.Mocker() as m:
        m.options(requests_mock.ANY,
                  status_code=200,
                  text=daemon_body,
                  headers=daemon_headers)
        res = http.request(proxy_server, "OPTIONS", path)

    # Validate the request.
    assert m.called
    assert m.last_request.path == path
    conn_timeout, read_timeout = m.last_request.timeout
    assert conn_timeout == proxy_server.imaged_connection_timeout_sec
    assert read_timeout == proxy_server.imaged_read_timeout_sec

    # Validate the response.
    assert res.status == 200
    assert set(res.getheader("Allow").split(",")) == daemon_allow
    assert set(json.loads(res.read())["features"]) == daemon_features
Esempio n. 2
0
def test_images_patch_error(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    response_code = 403
    response_body = b"daemon response"
    response_headers = {"Content-Type": "text/plain"}

    with requests_mock.Mocker() as m:
        # Don't check anything, match errors are useless.
        m.patch(
            requests_mock.ANY,
            status_code=response_code,
            text=response_body)
        # Send a request to the proxy.
        res = http.patch(
            proxy_server,
            "/images/" + signed_ticket.id,
            {"op": "zero", "size": 1024})

    # Validate response to proxy client.
    assert res.status == response_code
    # Note: requests adds charset=UTF-8 on RHEL 7.
    assert response_headers["Content-Type"] in res.getheader("Content-Type")
    error = res.read()
    assert response_body in error
Esempio n. 3
0
def test_delete(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)
    resp = http.request(
        proxy_server, "DELETE", "/tickets/%s" % signed_ticket.id)
    assert resp.status == http_client.NO_CONTENT
    with pytest.raises(auth.NoSuchTicket):
        auth.get_ticket(signed_ticket.id)
Esempio n. 4
0
def test_images_cors_options(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    request_headers = images_request_headers(signed_ticket.data)
    path = "/images/" + signed_ticket.id

    daemon_options = {"features": ["zero"]}
    daemon_body = json.dumps(daemon_options).encode("ascii")
    daemon_headers = {"Content-Type": "application/json",
                      "Content-Length": "%d" % len(daemon_body),
                      "Allow": "GET,PUT,PATCH,OPTIONS"}

    with requests_mock.Mocker() as m:
        m.options(requests_mock.ANY,
                  status_code=200,
                  text=daemon_body,
                  headers=daemon_headers)
        res = http.request(proxy_server,
                           "OPTIONS",
                           path,
                           headers=request_headers)
        assert m.called

    allowed_headers = split_header(res.getheader("access-control-allow-headers"))
    expected_headers = {"cache-control", "pragma", "authorization", "content-type",
                        "content-length", "content-range", "range", "session-id"}

    assert res.status == 200
    assert allowed_headers == expected_headers
    assert res.getheader("access-control-allow-origin") == "*"
    assert res.getheader("access-control-max-age") == "300"
Esempio n. 5
0
def test_images_patch(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    path = "/images/" + signed_ticket.id
    msg = {"op": "zero", "offset": 0, "size": 1024, "flush": False}
    headers = {"User-Header": "user value"}

    with requests_mock.Mocker() as m:
        # Don't check anything, match errors are useless.
        m.patch(requests_mock.ANY, status_code=200)
        # Send a request to the proxy.
        res = http.patch(proxy_server, path, msg, headers=headers)

    # Validate proxy request to daemon.
    assert m.last_request.path == path
    assert m.last_request.headers["Content-Type"] == "application/json"
    assert m.last_request.headers["User-Header"] == "user value"
    body = json.dumps(msg).encode("utf-8")
    assert m.last_request.headers["Content-Length"] == str(len(body))
    assert m.last_request.body.read() == body

    conn_timeout, read_timeout = m.last_request.timeout
    assert conn_timeout == proxy_server.imaged_connection_timeout_sec
    # PATCH cannot use a read timeout.
    assert read_timeout is None

    # Validate response to proxy client.
    assert res.status == 200
    assert res.getheader("content-length") == "0"
Esempio n. 6
0
def test_delete(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)
    resp = http.request(proxy_server, "DELETE",
                        "/tickets/%s" % signed_ticket.id)
    assert resp.status == http_client.NO_CONTENT
    with pytest.raises(auth.NoSuchTicket):
        auth.get_ticket(signed_ticket.id)
Esempio n. 7
0
def test_images_patch(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    path = "/images/" + signed_ticket.id
    msg = {"op": "zero", "offset": 0, "size": 1024, "flush": False}
    headers = {"User-Header": "user value"}

    with requests_mock.Mocker() as m:
        # Don't check anything, match errors are useless.
        m.patch(requests_mock.ANY, status_code=200)
        # Send a request to the proxy.
        res = http.patch(proxy_server, path, msg, headers=headers)

    # Validate proxy request to daemon.
    assert m.last_request.path == path
    assert m.last_request.headers["Content-Type"] == "application/json"
    assert m.last_request.headers["User-Header"] == "user value"
    body = json.dumps(msg).encode("utf-8")
    assert m.last_request.headers["Content-Length"] == str(len(body))
    assert m.last_request.body.read() == body

    conn_timeout, read_timeout = m.last_request.timeout
    assert conn_timeout == proxy_server.imaged_connection_timeout_sec
    # PATCH cannot use a read timeout.
    assert read_timeout is None

    # Validate response to proxy client.
    assert res.status == 200
    assert res.getheader("content-length") == "0"
Esempio n. 8
0
def test_images_options_newer_daemon(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    path = "/images/" + signed_ticket.id

    proxy_allow = {"OPTIONS", "GET", "PUT", "PATCH"}
    proxy_features = {"zero", "flush"}

    # Note: this future daemon supports "POST" and "trim".
    daemon_allow = {"OPTIONS", "GET", "PUT", "PATCH", "POST"}
    daemon_features = {"zero", "flush", "trim"}

    daemon_options = {"features": list(daemon_features)}
    daemon_body = json.dumps(daemon_options).encode("ascii")
    daemon_headers = {
        "Content-Type": "application/json",
        "Content-Length": "%d" % len(daemon_body),
        "Allow": ','.join(daemon_allow)
    }

    with requests_mock.Mocker() as m:
        m.options(requests_mock.ANY,
                  status_code=200,
                  text=daemon_body,
                  headers=daemon_headers)
        res = http.request(proxy_server, "OPTIONS", path)

    # Validate the request.
    assert m.called
    assert m.last_request.path == path

    # Validate the request.
    assert res.status == 200
    assert set(res.getheader("Allow").split(",")) == proxy_allow
    assert set(json.loads(res.read())["features"]) == proxy_features
Esempio n. 9
0
def test_authorize_ticket_installed_invalid_authorization_header(
        proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)
    request = Request({"Authorization": "invalid"})
    handler = RequestHandler(request)
    handler.decorated_method(signed_ticket.id)
    assert handler.ticket == auth.get_ticket(signed_ticket.id)
    assert handler.calls == [signed_ticket.id]
Esempio n. 10
0
def test_authorize_ticket_installed_invalid_authorization_header(proxy_server,
                                                                 signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)
    request = Request({"Authorization": "invalid"})
    handler = RequestHandler(request)
    handler.decorated_method(signed_ticket.id)
    assert handler.ticket == auth.get_ticket(signed_ticket.id)
    assert handler.calls == [signed_ticket.id]
Esempio n. 11
0
def test_authorize_ticket_expired_ignore_authorization_header(
        proxy_server, signed_ticket, monkeypatch):
    auth.add_signed_ticket(signed_ticket.data)
    handler = RequestHandler(None)
    monkeypatch.setattr(time, 'time', lambda: EXP + 1)
    with pytest.raises(exc.HTTPUnauthorized):
        handler.decorated_method(signed_ticket.id)
    assert handler.calls == []
    assert handler.ticket is None
Esempio n. 12
0
def test_authorize_ticket_expired(proxy_server, signed_ticket, monkeypatch):
    auth.add_signed_ticket(signed_ticket.data)
    handler = RequestHandler(Request())
    monkeypatch.setattr(time, 'time', lambda: EXP+1)
    with pytest.raises(exc.HTTPUnauthorized):
        handler.decorated_method(signed_ticket.id)
    assert handler.calls == []
    assert handler.ticket is None
    # Ticket expired but we don't remove it
    auth.get_ticket(signed_ticket.id)
Esempio n. 13
0
def test_authorize_ticket_expired(proxy_server, signed_ticket, monkeypatch):
    auth.add_signed_ticket(signed_ticket.data)
    handler = RequestHandler(Request())
    monkeypatch.setattr(time, 'time', lambda: EXP + 1)
    with pytest.raises(exc.HTTPUnauthorized):
        handler.decorated_method(signed_ticket.id)
    assert handler.calls == []
    assert handler.ticket is None
    # Ticket expired but we don't remove it
    auth.get_ticket(signed_ticket.id)
Esempio n. 14
0
def test_authorize_ticket_expired_ignore_authorization_header(proxy_server,
                                                              signed_ticket,
                                                              monkeypatch):
    auth.add_signed_ticket(signed_ticket.data)
    handler = RequestHandler(None)
    monkeypatch.setattr(time, 'time', lambda: EXP+1)
    with pytest.raises(exc.HTTPUnauthorized):
        handler.decorated_method(signed_ticket.id)
    assert handler.calls == []
    assert handler.ticket is None
Esempio n. 15
0
def test_images_put_flush(proxy_server, signed_ticket, flush):
    auth.add_signed_ticket(signed_ticket.data)

    path = "/images/" + signed_ticket.id + "?flush=" + flush + "&ignored=1"

    with requests_mock.Mocker() as m:
        # Don't check anything, match errors are useless.
        m.put(requests_mock.ANY, status_code=200)
        # Send a request to the proxy.
        res = http.request(proxy_server, "PUT", path, body="data")

    # Validate proxy request to daemon.
    url = urlparse(m.last_request.url)
    assert url.path == "/images/" + signed_ticket.id
    assert url.query == "flush=" + flush
Esempio n. 16
0
def test_images_put_flush(proxy_server, signed_ticket, flush):
    auth.add_signed_ticket(signed_ticket.data)

    path = "/images/" + signed_ticket.id + "?flush=" + flush + "&ignored=1"

    with requests_mock.Mocker() as m:
        # Don't check anything, match errors are useless.
        m.put(requests_mock.ANY, status_code=200)
        # Send a request to the proxy.
        res = http.request(proxy_server, "PUT", path, body="data")

    # Validate proxy request to daemon.
    url = urlparse(m.last_request.url)
    assert url.path == "/images/" + signed_ticket.id
    assert url.query == "flush=" + flush
Esempio n. 17
0
def test_images_put_imaged_without_content_range(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    body = "hello"
    client_headers = {
        "Accept-Ranges": "bytes",
    }
    path = "/images/" + signed_ticket.id

    with requests_mock.Mocker() as m:
        m.put(signed_ticket.url + path,
              status_code=200,
              text=None)
        res = http.request(proxy_server, "PUT", path, body=body,
                           headers=client_headers)
        assert m.called
    assert res.status == 200
    assert res.getheader("content-length") == "0"
Esempio n. 18
0
def test_images_put_imaged_without_content_range(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    body = "hello"
    client_headers = {
        "Accept-Ranges": "bytes",
    }
    path = "/images/" + signed_ticket.id

    with requests_mock.Mocker() as m:
        m.put(signed_ticket.url + path, status_code=200, text=None)
        res = http.request(proxy_server,
                           "PUT",
                           path,
                           body=body,
                           headers=client_headers)
        assert m.called
    assert res.status == 200
    assert res.getheader("content-length") == "0"
Esempio n. 19
0
def test_images_options_newer_daemon(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    path = "/images/" + signed_ticket.id

    proxy_allow = {"OPTIONS", "GET", "PUT", "PATCH"}
    proxy_features = {"zero", "flush"}

    # Note: this future daemon supports "POST" and "trim".
    daemon_allow = {"OPTIONS", "GET", "PUT", "PATCH", "POST"}
    daemon_features = {"zero", "flush", "trim"}

    # New daemon support unix socket - proxy must not report this since it does
    # not support unix socket now.
    daemon_options = {"features": list(daemon_features),
                      "unix_socket": "\0org.ovirt.imageio"}
    daemon_body = json.dumps(daemon_options).encode("ascii")
    daemon_headers = {"Content-Type": "application/json",
                      "Content-Length": "%d" % len(daemon_body),
                      "Allow": ','.join(daemon_allow)}

    with requests_mock.Mocker() as m:
        m.options(requests_mock.ANY,
                  status_code=200,
                  text=daemon_body,
                  headers=daemon_headers)
        res = http.request( proxy_server, "OPTIONS", path)

    # Validate the request.
    assert m.called
    assert m.last_request.path == path

    # Validate the request.
    assert res.status == 200
    assert set(res.getheader("Allow").split(",")) == proxy_allow

    proxy_options = json.loads(res.read())
    assert set(proxy_options["features"]) == proxy_features
    assert "unix_socket" not in proxy_options
Esempio n. 20
0
def test_images_get_imaged_with_installed_ticket(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    body = "hello"
    request_headers = {
        "Accept-Ranges": "bytes",
    }
    response_headers = {
        "Content-Length": "5",
    }
    path = "/images/" + signed_ticket.id

    with requests_mock.Mocker() as m:
        m.get(signed_ticket.url + path,
              status_code=200,
              text=body,
              headers=response_headers)
        res = http.request(proxy_server, "GET", path, headers=request_headers)
        assert m.called
    assert res.status == 200
    assert res.read() == "hello"
    assert res.getheader("content-length") == "5"
Esempio n. 21
0
def test_images_get_imaged_with_installed_ticket(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    body = "hello"
    request_headers = {
        "Accept-Ranges": "bytes",
    }
    response_headers = {
        "Content-Length": "5",
    }
    path = "/images/" + signed_ticket.id

    with requests_mock.Mocker() as m:
        m.get(signed_ticket.url + path,
              status_code=200,
              text=body,
              headers=response_headers)
        res = http.request(proxy_server, "GET", path, headers=request_headers)
        assert m.called
    assert res.status == 200
    assert res.read() == "hello"
    assert res.getheader("content-length") == "5"
Esempio n. 22
0
def test_images_options_old_daemon_without_options(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    path = "/images/" + signed_ticket.id

    # Note: the daemon does not allow OPTIONS.
    assumed_daemon_allow = {"OPTIONS", "GET", "PUT"}
    assumed_daemon_features = []

    with requests_mock.Mocker() as m:
        m.options(requests_mock.ANY,
                  status_code=405,
                  content=b'{"detail": "Invalid method OPTIONS"}')
        res = http.request(proxy_server, "OPTIONS", path)

    # Validate the request.
    assert m.called
    assert m.last_request.path == path

    # Validate the response.
    assert res.status == 200
    assert set(res.getheader("Allow").split(",")) == assumed_daemon_allow
    assert json.loads(res.read())["features"] == assumed_daemon_features
Esempio n. 23
0
def test_images_patch_error(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    response_code = 403
    response_body = b"daemon response"
    response_headers = {"Content-Type": "text/plain"}

    with requests_mock.Mocker() as m:
        # Don't check anything, match errors are useless.
        m.patch(requests_mock.ANY,
                status_code=response_code,
                text=response_body)
        # Send a request to the proxy.
        res = http.patch(proxy_server, "/images/" + signed_ticket.id, {
            "op": "zero",
            "size": 1024
        })

    # Validate response to proxy client.
    assert res.status == response_code
    # Note: requests adds charset=UTF-8 on RHEL 7.
    assert response_headers["Content-Type"] in res.getheader("Content-Type")
    error = res.read()
    assert response_body in error
Esempio n. 24
0
def test_images_options_newer_proxy(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    path = "/images/" + signed_ticket.id

    # Note: the daemon does not report GET since the ticket is write only, and
    # it supports only "zero" (simulating old daemon).
    daemon_allow = {"OPTIONS", "PUT", "PATCH"}
    daemon_features = {"zero"}

    daemon_options = {"features": list(daemon_features)}
    daemon_body = json.dumps(daemon_options).encode("ascii")
    daemon_headers = {
        "Content-Type": "application/json",
        "Content-Length": "%d" % len(daemon_body),
        "Allow": ','.join(daemon_allow)
    }

    with requests_mock.Mocker() as m:
        m.options(requests_mock.ANY,
                  status_code=200,
                  text=daemon_body,
                  headers=daemon_headers)
        res = http.request(proxy_server, "OPTIONS", path)

    # Validate the request.
    assert m.called
    assert m.last_request.path == path
    conn_timeout, read_timeout = m.last_request.timeout
    assert conn_timeout == proxy_server.imaged_connection_timeout_sec
    assert read_timeout == proxy_server.imaged_read_timeout_sec

    # Validate the response.
    assert res.status == 200
    assert set(res.getheader("Allow").split(",")) == daemon_allow
    assert set(json.loads(res.read())["features"]) == daemon_features
Esempio n. 25
0
def test_images_options_old_daemon_without_options(proxy_server,
                                                   signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    path = "/images/" + signed_ticket.id

    # Note: the daemon does not allow OPTIONS.
    assumed_daemon_allow = {"OPTIONS", "GET", "PUT"}
    assumed_daemon_features = []

    with requests_mock.Mocker() as m:
        m.options(requests_mock.ANY,
                  status_code=405,
                  content=b'{"detail": "Invalid method OPTIONS"}')
        res = http.request(proxy_server, "OPTIONS", path)

    # Validate the request.
    assert m.called
    assert m.last_request.path == path

    # Validate the response.
    assert res.status == 200
    assert set(res.getheader("Allow").split(",")) == assumed_daemon_allow
    assert json.loads(res.read())["features"] == assumed_daemon_features
Esempio n. 26
0
def test_images_cors_options(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)

    request_headers = images_request_headers(signed_ticket.data)
    path = "/images/" + signed_ticket.id

    daemon_options = {"features": ["zero"]}
    daemon_body = json.dumps(daemon_options).encode("ascii")
    daemon_headers = {
        "Content-Type": "application/json",
        "Content-Length": "%d" % len(daemon_body),
        "Allow": "GET,PUT,PATCH,OPTIONS"
    }

    with requests_mock.Mocker() as m:
        m.options(requests_mock.ANY,
                  status_code=200,
                  text=daemon_body,
                  headers=daemon_headers)
        res = http.request(proxy_server,
                           "OPTIONS",
                           path,
                           headers=request_headers)
        assert m.called

    allowed_headers = split_header(
        res.getheader("access-control-allow-headers"))
    expected_headers = {
        "cache-control", "pragma", "authorization", "content-type",
        "content-length", "content-range", "range", "session-id"
    }

    assert res.status == 200
    assert allowed_headers == expected_headers
    assert res.getheader("access-control-allow-origin") == "*"
    assert res.getheader("access-control-max-age") == "300"
Esempio n. 27
0
def test_authorize_ticket_installed(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)
    handler = RequestHandler(Request())
    handler.decorated_method(signed_ticket.id)
    assert handler.ticket == auth.get_ticket(signed_ticket.id)
    assert handler.calls == [signed_ticket.id]
Esempio n. 28
0
def test_authorize_ticket_installed(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)
    handler = RequestHandler(Request())
    handler.decorated_method(signed_ticket.id)
    assert handler.ticket == auth.get_ticket(signed_ticket.id)
    assert handler.calls == [signed_ticket.id]
Esempio n. 29
0
def test_images_patch_no_content(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)
    res = http.request(proxy_server, "PATCH", "/images/" + signed_ticket.id)
    assert res.status == 400
Esempio n. 30
0
def test_images_patch_no_content(proxy_server, signed_ticket):
    auth.add_signed_ticket(signed_ticket.data)
    res = http.request(proxy_server, "PATCH", "/images/" + signed_ticket.id)
    assert res.status == 400