Skip to content

Commit ec835fd

Browse files
moses946leplatrem
andauthored
Fix #377: Allow basic auth-scheme (#384)
* Allow basic auth-scheme * refactor: improve code readability and maintainability * Revert to BearerTokenAuth class for bearer token * 'make format' * 'make format' with latest ruff --------- Co-authored-by: Mathieu Leplatre <[email protected]>
1 parent f85e012 commit ec835fd

File tree

8 files changed

+42
-28
lines changed

8 files changed

+42
-28
lines changed

src/kinto_http/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
__all__ = (
2020
"BrowserOAuth",
21+
"TokenAuth",
2122
"BearerTokenAuth",
2223
"Endpoints",
2324
"Session",
@@ -31,11 +32,16 @@
3132
)
3233

3334

34-
class BearerTokenAuth(requests.auth.AuthBase):
35+
class TokenAuth(requests.auth.AuthBase):
3536
def __init__(self, token, type=None):
3637
self.token = token
3738
self.type = type or "Bearer"
3839

3940
def __call__(self, r):
41+
# Sets auth-scheme to either Bearer or Basic
4042
r.headers["Authorization"] = "{} {}".format(self.type, self.token)
4143
return r
44+
45+
46+
class BearerTokenAuth(TokenAuth):
47+
pass

src/kinto_http/cli_utils.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ def add_parser_options(
7575
parser.add_argument(
7676
"-a",
7777
"--auth",
78-
help="BasicAuth credentials: `token:my-secret` or " "Authorization header: `Bearer token`",
78+
help="BasicAuth credentials: `token:my-secret` or Authorization header: `Bearer token`",
7979
type=str,
8080
default=default_auth,
8181
action=AuthAction,
@@ -97,8 +97,7 @@ def add_parser_options(
9797

9898
parser.add_argument(
9999
"--retry-after",
100-
help="Delay in seconds between retries when requests fail. "
101-
"(default: provided by server)",
100+
help="Delay in seconds between retries when requests fail. (default: provided by server)",
102101
type=int,
103102
default=default_retry_after,
104103
)

src/kinto_http/replication.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,23 +42,22 @@ def get_arguments(): # pragma: nocover
4242

4343
parser.add_argument(
4444
"--origin-auth",
45-
help="The origin authentication credentials. "
46-
"Will use the same as the remote if omitted",
45+
help="The origin authentication credentials. Will use the same as the remote if omitted",
4746
action=cli_utils.AuthAction,
4847
default=None,
4948
)
5049

5150
parser.add_argument(
5251
"--origin-bucket",
5352
dest="origin_bucket",
54-
help="The name of the origin bucket. " "Will use the same as the remote if omitted",
53+
help="The name of the origin bucket. Will use the same as the remote if omitted",
5554
default=None,
5655
)
5756

5857
parser.add_argument(
5958
"--origin-collection",
6059
dest="origin_collection",
61-
help="The name of the origin collection. " "Will use the same as the remote if omitted",
60+
help="The name of the origin collection. Will use the same as the remote if omitted",
6261
default=None,
6362
)
6463
cli_utils.set_parser_server_options(parser)

src/kinto_http/session.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,13 @@ def create_session(server_url=None, auth=None, session=None, **kwargs):
4545
# eg, "Bearer ghruhgrwyhg"
4646
_type, token = auth.split(" ", 1)
4747
auth = kinto_http.BearerTokenAuth(token, type=_type)
48+
elif "basic" in auth.lower():
49+
_type, token = auth.split(" ", 1)
50+
auth = kinto_http.TokenAuth(token, type=_type)
4851
elif auth: # not empty
4952
raise ValueError(
5053
"Unsupported `auth` parameter value. Must be a tuple() or string "
51-
"in the form of `user:pass` or `Bearer xyz`"
54+
"in the form of `user:pass` or `Bearer xyz` or `Basic xyz`"
5255
)
5356

5457
if session is None:

tests/support.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ def get_user_id(server_url: str, credentials: Tuple[str, str]) -> str:
5151

5252
def assert_option_strings(parser, *option_strings_list):
5353
for option_strings in option_strings_list:
54-
assert any(
55-
[action.option_strings == option_strings for action in parser._actions]
56-
), f"{option_strings} not found"
54+
assert any([action.option_strings == option_strings for action in parser._actions]), (
55+
f"{option_strings} not found"
56+
)
5757

5858

5959
def build_response(data, headers=None):

tests/test_async_client.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@ def test_client_is_represented_properly_with_bucket_and_collection(async_client_
4343
client = async_client_setup.clone(
4444
server_url=SERVER_URL, bucket="homebrewing", collection="recipes"
4545
)
46-
expected_repr = f"<KintoAsyncClient {SERVER_URL}/" "buckets/homebrewing/collections/recipes>"
46+
expected_repr = f"<KintoAsyncClient {SERVER_URL}/buckets/homebrewing/collections/recipes>"
4747
assert str(client) == expected_repr
4848

4949

5050
def test_client_is_represented_properly_with_bucket(async_client_setup: Client):
5151
client = async_client_setup.clone(server_url=SERVER_URL, bucket="homebrewing")
52-
expected_repr = f"<KintoAsyncClient {SERVER_URL}/" "buckets/homebrewing>"
52+
expected_repr = f"<KintoAsyncClient {SERVER_URL}/buckets/homebrewing>"
5353
assert str(client) == expected_repr
5454

5555

@@ -843,7 +843,7 @@ async def test_records_timestamp_is_cached_per_collection(record_async_setup: Cl
843843
async def test_pagination_is_followed(record_async_setup: Client):
844844
client = record_async_setup
845845
# Mock the calls to request.
846-
link = "http://example.org/buckets/buck/collections/coll/records/" "?token=1234"
846+
link = "http://example.org/buckets/buck/collections/coll/records/?token=1234"
847847

848848
client.session.request.side_effect = [
849849
# First one returns a list of items with a pagination token.
@@ -871,7 +871,7 @@ async def test_pagination_is_followed(record_async_setup: Client):
871871
async def test_pagination_is_followed_generator(record_async_setup: Client):
872872
client = record_async_setup
873873
# Mock the calls to request.
874-
link = "http://example.org/buckets/buck/collections/coll/records/" "?token=1234"
874+
link = "http://example.org/buckets/buck/collections/coll/records/?token=1234"
875875

876876
response = [
877877
# First one returns a list of items with a pagination token.
@@ -897,7 +897,7 @@ async def test_pagination_is_followed_generator(record_async_setup: Client):
897897
async def test_pagination_is_followed_for_number_of_pages(record_async_setup: Client):
898898
client = record_async_setup
899899
# Mock the calls to request.
900-
link = "http://example.org/buckets/buck/collections/coll/records/" "?token=1234"
900+
link = "http://example.org/buckets/buck/collections/coll/records/?token=1234"
901901

902902
client.session.request.side_effect = [
903903
# First one returns a list of items with a pagination token.
@@ -923,7 +923,7 @@ async def test_pagination_is_followed_for_number_of_pages(record_async_setup: Cl
923923
async def test_pagination_is_not_followed_if_limit_is_specified(record_async_setup: Client):
924924
client = record_async_setup
925925
# Mock the calls to request.
926-
link = "http://example.org/buckets/buck/collections/coll/records/" "?token=1234"
926+
link = "http://example.org/buckets/buck/collections/coll/records/?token=1234"
927927

928928
client.session.request.side_effect = [
929929
build_response(
@@ -938,7 +938,7 @@ async def test_pagination_is_not_followed_if_limit_is_specified(record_async_set
938938

939939
async def test_pagination_supports_if_none_match(record_async_setup: Client):
940940
client = record_async_setup
941-
link = "http://example.org/buckets/buck/collections/coll/records/" "?token=1234"
941+
link = "http://example.org/buckets/buck/collections/coll/records/?token=1234"
942942

943943
client.session.request.side_effect = [
944944
# First one returns a list of items with a pagination token.
@@ -964,7 +964,7 @@ async def test_pagination_supports_if_none_match(record_async_setup: Client):
964964

965965
async def test_pagination_generator_if_none_match(record_async_setup: Client):
966966
client = record_async_setup
967-
link = "http://example.org/buckets/buck/collections/coll/records/" "?token=1234"
967+
link = "http://example.org/buckets/buck/collections/coll/records/?token=1234"
968968

969969
response = [
970970
# First one returns a list of items with a pagination token.

tests/test_client.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -209,13 +209,13 @@ def test_batch_options_are_transmitted(client_setup: Client, mocker: MockerFixtu
209209

210210
def test_client_is_represented_properly_with_bucket_and_collection(client_setup: Client):
211211
client = client_setup.clone(server_url=SERVER_URL, bucket="homebrewing", collection="recipes")
212-
expected_repr = f"<KintoClient {SERVER_URL}/" "buckets/homebrewing/collections/recipes>"
212+
expected_repr = f"<KintoClient {SERVER_URL}/buckets/homebrewing/collections/recipes>"
213213
assert str(client) == expected_repr
214214

215215

216216
def test_client_is_represented_properly_with_bucket(client_setup: Client):
217217
client = client_setup.clone(server_url=SERVER_URL, bucket="homebrewing")
218-
expected_repr = f"<KintoClient {SERVER_URL}/" "buckets/homebrewing>"
218+
expected_repr = f"<KintoClient {SERVER_URL}/buckets/homebrewing>"
219219
assert str(client) == expected_repr
220220

221221

@@ -1003,7 +1003,7 @@ def test_records_timestamp_is_cached_per_collection(record_setup: Client):
10031003
def test_pagination_is_followed(record_setup: Client):
10041004
client = record_setup
10051005
# Mock the calls to request.
1006-
link = "http://example.org/buckets/buck/collections/coll/records/" "?token=1234"
1006+
link = "http://example.org/buckets/buck/collections/coll/records/?token=1234"
10071007

10081008
client.session.request.side_effect = [
10091009
# First one returns a list of items with a pagination token.
@@ -1031,7 +1031,7 @@ def test_pagination_is_followed(record_setup: Client):
10311031
def test_pagination_is_followed_generator(record_setup: Client):
10321032
client = record_setup
10331033
# Mock the calls to request.
1034-
link = "http://example.org/buckets/buck/collections/coll/records/" "?token=1234"
1034+
link = "http://example.org/buckets/buck/collections/coll/records/?token=1234"
10351035

10361036
response = [
10371037
# First one returns a list of items with a pagination token.
@@ -1057,7 +1057,7 @@ def test_pagination_is_followed_generator(record_setup: Client):
10571057
def test_pagination_is_followed_for_number_of_pages(record_setup: Client):
10581058
client = record_setup
10591059
# Mock the calls to request.
1060-
link = "http://example.org/buckets/buck/collections/coll/records/" "?token=1234"
1060+
link = "http://example.org/buckets/buck/collections/coll/records/?token=1234"
10611061

10621062
client.session.request.side_effect = [
10631063
# First one returns a list of items with a pagination token.
@@ -1083,7 +1083,7 @@ def test_pagination_is_followed_for_number_of_pages(record_setup: Client):
10831083
def test_pagination_is_not_followed_if_limit_is_specified(record_setup: Client):
10841084
client = record_setup
10851085
# Mock the calls to request.
1086-
link = "http://example.org/buckets/buck/collections/coll/records/" "?token=1234"
1086+
link = "http://example.org/buckets/buck/collections/coll/records/?token=1234"
10871087

10881088
client.session.request.side_effect = [
10891089
build_response(
@@ -1098,7 +1098,7 @@ def test_pagination_is_not_followed_if_limit_is_specified(record_setup: Client):
10981098

10991099
def test_pagination_supports_if_none_match(record_setup: Client):
11001100
client = record_setup
1101-
link = "http://example.org/buckets/buck/collections/coll/records/" "?token=1234"
1101+
link = "http://example.org/buckets/buck/collections/coll/records/?token=1234"
11021102

11031103
client.session.request.side_effect = [
11041104
# First one returns a list of items with a pagination token.
@@ -1124,7 +1124,7 @@ def test_pagination_supports_if_none_match(record_setup: Client):
11241124

11251125
def test_pagination_generator_if_none_match(record_setup: Client):
11261126
client = record_setup
1127-
link = "http://example.org/buckets/buck/collections/coll/records/" "?token=1234"
1127+
link = "http://example.org/buckets/buck/collections/coll/records/?token=1234"
11281128

11291129
response = [
11301130
# First one returns a list of items with a pagination token.

tests/test_session.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,13 @@ def test_auth_can_be_passed_as_colon_separate(session_setup: Tuple[MagicMock, Se
246246

247247

248248
def test_auth_can_be_passed_as_basic_header(session_setup: Tuple[MagicMock, Session]):
249+
session = create_session(auth="Basic asdfghjkl;")
250+
assert isinstance(session.auth, kinto_http.TokenAuth)
251+
assert session.auth.type == "Basic"
252+
assert session.auth.token == "asdfghjkl;"
253+
254+
255+
def test_auth_can_be_passed_as_bearer(session_setup: Tuple[MagicMock, Session]):
249256
session = create_session(auth="Bearer+OIDC abcdef")
250257
assert isinstance(session.auth, kinto_http.BearerTokenAuth)
251258
assert session.auth.type == "Bearer+OIDC"

0 commit comments

Comments
 (0)