forked from dragonflydb/dragonfly
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: authorize the http connection to call commands (dragonflydb#2863)
fix: authorize the http connection to call DF commands The assumption is that basic-auth already covers the authentication part. And thanks to @sunneydev for finding the bug and providing the tests. The tests actually uncovered another bug where we may parse partial http requests. This one is handled by romange/helio#243 Signed-off-by: Roman Gershman <[email protected]>
- Loading branch information
Showing
5 changed files
with
121 additions
and
92 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,77 +1,129 @@ | ||
import aiohttp | ||
from . import dfly_args | ||
from .instance import DflyInstance | ||
|
||
|
||
async def test_password(df_factory): | ||
with df_factory.create(port=1112, requirepass="XXX") as server: | ||
async with aiohttp.ClientSession() as session: | ||
resp = await session.get(f"http://localhost:{server.port}/") | ||
assert resp.status == 401 | ||
async with aiohttp.ClientSession( | ||
auth=aiohttp.BasicAuth("default", "wrongpassword") | ||
) as session: | ||
resp = await session.get(f"http://localhost:{server.port}/") | ||
assert resp.status == 401 | ||
async with aiohttp.ClientSession(auth=aiohttp.BasicAuth("default", "XXX")) as session: | ||
resp = await session.get(f"http://localhost:{server.port}/") | ||
assert resp.status == 200 | ||
def get_http_session(*args): | ||
if args: | ||
return aiohttp.ClientSession(auth=aiohttp.BasicAuth(*args)) | ||
return aiohttp.ClientSession() | ||
|
||
|
||
async def test_skip_metrics(df_factory): | ||
with df_factory.create(port=1112, admin_port=1113, requirepass="XXX") as server: | ||
async with aiohttp.ClientSession(auth=aiohttp.BasicAuth("whoops", "whoops")) as session: | ||
resp = await session.get(f"http://localhost:{server.port}/metrics") | ||
assert resp.status == 200 | ||
async with aiohttp.ClientSession(auth=aiohttp.BasicAuth("whoops", "whoops")) as session: | ||
resp = await session.get(f"http://localhost:{server.admin_port}/metrics") | ||
assert resp.status == 200 | ||
@dfly_args({"proactor_threads": "1", "requirepass": "XXX"}) | ||
async def test_password(df_server: DflyInstance): | ||
async with get_http_session() as session: | ||
resp = await session.get(f"http://localhost:{df_server.port}/") | ||
assert resp.status == 401 | ||
async with get_http_session("default", "wrongpassword") as session: | ||
resp = await session.get(f"http://localhost:{df_server.port}/") | ||
assert resp.status == 401 | ||
async with get_http_session("default", "XXX") as session: | ||
resp = await session.get(f"http://localhost:{df_server.port}/") | ||
assert resp.status == 200 | ||
|
||
|
||
async def test_no_password_main_port(df_factory): | ||
with df_factory.create( | ||
port=1112, | ||
) as server: | ||
async with aiohttp.ClientSession(auth=aiohttp.BasicAuth("default", "XXX")) as session: | ||
resp = await session.get(f"http://localhost:{server.port}/") | ||
assert resp.status == 200 | ||
async with aiohttp.ClientSession(auth=aiohttp.BasicAuth("random")) as session: | ||
resp = await session.get(f"http://localhost:{server.port}/") | ||
assert resp.status == 200 | ||
async with aiohttp.ClientSession() as session: | ||
resp = await session.get(f"http://localhost:{server.port}/") | ||
assert resp.status == 200 | ||
@dfly_args({"proactor_threads": "1", "requirepass": "XXX", "admin_port": 1113}) | ||
async def test_skip_metrics(df_server: DflyInstance): | ||
async with get_http_session("whoops", "whoops") as session: | ||
resp = await session.get(f"http://localhost:{df_server.port}/metrics") | ||
assert resp.status == 200 | ||
async with get_http_session("whoops", "whoops") as session: | ||
resp = await session.get(f"http://localhost:{df_server.admin_port}/metrics") | ||
assert resp.status == 200 | ||
|
||
|
||
async def test_no_password_main_port(df_server: DflyInstance): | ||
async with get_http_session("default", "XXX") as session: | ||
resp = await session.get(f"http://localhost:{df_server.port}/") | ||
assert resp.status == 200 | ||
async with get_http_session("random") as session: | ||
resp = await session.get(f"http://localhost:{df_server.port}/") | ||
assert resp.status == 200 | ||
async with get_http_session() as session: | ||
resp = await session.get(f"http://localhost:{df_server.port}/") | ||
assert resp.status == 200 | ||
|
||
|
||
@dfly_args( | ||
{ | ||
"proactor_threads": "1", | ||
"requirepass": "XXX", | ||
"admin_port": 1113, | ||
"primary_port_http_enabled": True, | ||
"admin_nopass": True, | ||
} | ||
) | ||
async def test_no_password_on_admin(df_server: DflyInstance): | ||
async with get_http_session("default", "XXX") as session: | ||
resp = await session.get(f"http://localhost:{df_server.admin_port}/") | ||
assert resp.status == 200 | ||
async with get_http_session("random") as session: | ||
resp = await session.get(f"http://localhost:{df_server.admin_port}/") | ||
assert resp.status == 200 | ||
async with get_http_session() as session: | ||
resp = await session.get(f"http://localhost:{df_server.admin_port}/") | ||
assert resp.status == 200 | ||
|
||
async def test_no_password_on_admin(df_factory): | ||
with df_factory.create( | ||
port=1112, | ||
admin_port=1113, | ||
requirepass="XXX", | ||
primary_port_http_enabled=True, | ||
admin_nopass=True, | ||
) as server: | ||
async with aiohttp.ClientSession(auth=aiohttp.BasicAuth("default", "XXX")) as session: | ||
resp = await session.get(f"http://localhost:{server.admin_port}/") | ||
|
||
@dfly_args({"proactor_threads": "1", "requirepass": "XXX", "admin_port": 1113}) | ||
async def test_password_on_admin(df_server: DflyInstance): | ||
async with get_http_session("default", "badpass") as session: | ||
resp = await session.get(f"http://localhost:{df_server.admin_port}/") | ||
assert resp.status == 401 | ||
async with get_http_session() as session: | ||
resp = await session.get(f"http://localhost:{df_server.admin_port}/") | ||
assert resp.status == 401 | ||
async with get_http_session("default", "XXX") as session: | ||
resp = await session.get(f"http://localhost:{df_server.admin_port}/") | ||
assert resp.status == 200 | ||
|
||
|
||
@dfly_args({"proactor_threads": "1", "expose_http_api": "true"}) | ||
async def test_no_password_on_http_api(df_server: DflyInstance): | ||
async with get_http_session("default", "XXX") as session: | ||
resp = await session.post(f"http://localhost:{df_server.port}/api", json=["ping"]) | ||
assert resp.status == 200 | ||
async with get_http_session("random") as session: | ||
resp = await session.post(f"http://localhost:{df_server.port}/api", json=["ping"]) | ||
assert resp.status == 200 | ||
async with get_http_session() as session: | ||
resp = await session.post(f"http://localhost:{df_server.port}/api", json=["ping"]) | ||
assert resp.status == 200 | ||
|
||
|
||
@dfly_args({"proactor_threads": "1", "expose_http_api": "true"}) | ||
async def test_http_api(df_server: DflyInstance): | ||
client = df_server.client() | ||
async with get_http_session() as session: | ||
body = '["set", "foo", "МайяХилли", "ex", "100"]' | ||
async with session.post(f"http://localhost:{df_server.port}/api", data=body) as resp: | ||
assert resp.status == 200 | ||
async with aiohttp.ClientSession(auth=aiohttp.BasicAuth("random")) as session: | ||
resp = await session.get(f"http://localhost:{server.admin_port}/") | ||
text = await resp.text() | ||
assert text.strip() == '{"result":"OK"}' | ||
|
||
body = '["get", "foo"]' | ||
async with session.post(f"http://localhost:{df_server.port}/api", data=body) as resp: | ||
assert resp.status == 200 | ||
async with aiohttp.ClientSession() as session: | ||
resp = await session.get(f"http://localhost:{server.admin_port}/") | ||
text = await resp.text() | ||
assert text.strip() == '{"result":"МайяХилли"}' | ||
|
||
body = '["foo", "bar"]' | ||
async with session.post(f"http://localhost:{df_server.port}/api", data=body) as resp: | ||
assert resp.status == 200 | ||
text = await resp.text() | ||
assert text.strip() == '{"error": "unknown command `FOO`"}' | ||
|
||
assert await client.ttl("foo") > 0 | ||
|
||
async def test_password_on_admin(df_factory): | ||
with df_factory.create( | ||
port=1112, | ||
admin_port=1113, | ||
requirepass="XXX", | ||
) as server: | ||
async with aiohttp.ClientSession(auth=aiohttp.BasicAuth("default", "badpass")) as session: | ||
resp = await session.get(f"http://localhost:{server.admin_port}/") | ||
assert resp.status == 401 | ||
async with aiohttp.ClientSession() as session: | ||
resp = await session.get(f"http://localhost:{server.admin_port}/") | ||
assert resp.status == 401 | ||
async with aiohttp.ClientSession(auth=aiohttp.BasicAuth("default", "XXX")) as session: | ||
resp = await session.get(f"http://localhost:{server.admin_port}/") | ||
assert resp.status == 200 | ||
|
||
@dfly_args({"proactor_threads": "1", "expose_http_api": "true", "requirepass": "XXX"}) | ||
async def test_password_on_http_api(df_server: DflyInstance): | ||
async with get_http_session("default", "badpass") as session: | ||
resp = await session.post(f"http://localhost:{df_server.port}/api", json=["ping"]) | ||
assert resp.status == 401 | ||
async with get_http_session() as session: | ||
resp = await session.post(f"http://localhost:{df_server.port}/api", json=["ping"]) | ||
assert resp.status == 401 | ||
async with get_http_session("default", "XXX") as session: | ||
resp = await session.post(f"http://localhost:{df_server.port}/api", json=["ping"]) | ||
assert resp.status == 200 |