10000 fixup! DO NOT MERGE: Add pytest suite for OAuth · jchampio/postgres@ae96119 · GitHub
[go: up one dir, main page]

Skip to content

Commit ae96119

Browse files
committed
fixup! DO NOT MERGE: Add pytest suite for OAuth
1 parent c2965bd commit ae96119

File tree

3 files changed

+97
-35
lines changed

3 files changed

+97
-35
lines changed

src/test/python/client/test_oauth.py

Lines changed: 68 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1538,6 +1538,16 @@ def alt_patterns(*patterns):
15381538
r"failed to obtain device authorization: response is too large",
15391539
id="gigantic authz response",
15401540
),
1541+
pytest.param(
1542+
(200, RawResponse('{"":' + "[" * 16)),
1543+
r"failed to parse device authorization: JSON is too deeply nested",
1544+
id="overly nested authz response array",
1545+
),
1546+
pytest.param(
1547+
(200, RawResponse('{"":' * 17)),
1548+
r"failed to parse device authorization: JSON is too deeply nested",
1549+
id="overly nested authz response object",
1550+
),
15411551
pytest.param(
15421552
(400, {}),
15431553
r'failed to parse token error response: field "error" is missing',
@@ -1709,6 +1719,16 @@ def token_endpoint(headers, params):
17091719
r"failed to obtain access token: response is too large",
17101720
id="gigantic token response",
17111721
),
1722+
pytest.param(
1723+
(200, RawResponse('{"":' + "[" * 16)),
1724+
r"failed to parse access token response: JSON is too deeply nested",
1725+
i 57AE d="overly nested token response array",
1726+
),
1727+
pytest.param(
1728+
(200, RawResponse('{"":' * 17)),
1729+
r"failed to parse access token response: JSON is too deeply nested",
1730+
id="overly nested token response object",
1731+
),
17121732
pytest.param(
17131733
(400, {}),
17141734
r'failed to parse token error response: field "error" is missing',
@@ -2004,7 +2024,7 @@ def token_endpoint(headers, params):
20042024
id="bad JSON: invalid syntax",
20052025
),
20062026
pytest.param(
2007-
b"\xFF\xFF\xFF\xFF",
2027+
b"\xff\xff\xff\xff",
20082028
"server's error response is not valid UTF-8",
20092029
id="bad JSON: invalid encoding",
20102030
),
@@ -2146,7 +2166,7 @@ def test_oauth_discovery_server_error(accept, response, expected_error):
21462166
id="NULL bytes in document",
21472167
),
21482168
pytest.param(
2149-
(200, RawBytes(b"blah\xFFblah")),
2169+
(200, RawBytes(b"blah\xffblah")),
21502170
r"failed to parse OpenID discovery document: response is not valid UTF-8",
21512171
id="document is not UTF-8",
21522172
),
@@ -2288,6 +2308,22 @@ def test_oauth_discovery_server_error(accept, response, expected_error):
22882308
r"failed to fetch OpenID discovery document: response is too large",
22892309
id="gigantic discovery response",
22902310
),
2311+
pytest.param(
2312+
(
2313+
200,
2314+
RawResponse('{"":' + "[" * 16),
2315+
),
2316+
r"failed to parse OpenID discovery document: JSON is too deeply nested",
2317+
id="overly nested discovery response array",
2318+
),
2319+
pytest.param(
2320+
(
2321+
200,
2322+
RawResponse('{"":' * 17),
2323+
),
2324+
r"failed to parse OpenID discovery document: JSON is too deeply nested",
2325+
id="overly nested discovery response object",
2326+
),
22912327
pytest.param(
22922328
(
22932329
200,
@@ -2382,6 +2418,15 @@ def failing_discovery_handler(headers, params):
23822418
"server rejected OAuth bearer token: invalid_request",
23832419
id="standard server error: invalid_request",
23842420
),
2421+
pytest.param(
2422+
{"": [[[[[[[]]]]]]], "status": "invalid_request"},
2423+
pq3.types.ErrorResponse,
2424+
dict(
2425+
fields=[b"SFATAL", b"C28000", b"Mexpected error message", b""],
2426+
),
2427+
"server rejected OAuth bearer token: invalid_request",
2428+
id="standard server error: invalid_request with ignored array",
2429+
),
23852430
pytest.param(
23862431
{"status": "invalid_token"},
23872432
pq3.types.ErrorResponse,
@@ -2412,6 +2457,20 @@ def failing_discovery_handler(headers, params):
24122457
"duplicate SASL authentication request",
24132458
id="broken server: SASL reinitialization after error",
24142459
),
2460+
pytest.param(
2461+
RawResponse('{"":' + "[" * 8),
2462+
pq3.types.AuthnRequest,
2463+
dict(type=pq3.authn.SASL, body=[b"OAUTHBEARER", b""]),
2464+
"JSON is too deeply nested",
2465+
id="broken server: overly nested JSON response array",
2466+
),
2467+
pytest.param(
2468+
RawResponse('{"":' * 9),
2469+
pq3.types.AuthnRequest,
2470+
dict(type=pq3.authn.SASL, body=[b"OAUTHBEARER", b""]),
2471+
"JSON is too deeply nested",
2472+
id="broken server: overly nested JSON response object",
2473+
),
24152474
],
24162475
)
24172476
def test_oauth_server_error(
@@ -2439,12 +2498,15 @@ def bearer_hook(typ, pgconn, request):
24392498
start_oauth_handshake(conn)
24402499

24412500
# Ignore the client data. Return an error "challenge".
2442-
if "openid-configuration" in sasl_err:
2443-
sasl_err["openid-configuration"] = wkuri
2501+
if isinstance(sasl_err, RawResponse):
2502+
resp = sasl_err
2503+
else:
2504+
if "openid-configuration" in sasl_err:
2505+
sasl_err["openid-configuration"] = wkuri
24442506

2445-
resp = json.dumps(sasl_err)
2446-
resp = resp.encode("utf-8")
2507+
resp = json.dumps(sasl_err)
24472508

2509+
resp = resp.encode("utf-8")
24482510
pq3.send(
24492511
conn, pq3.types.AuthnRequest, type=pq3.authn.SASLContinue, body=resp
24502512
)

src/test/python/requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
black
1+
black~=25.0
22
# cryptography 35.x and later add many platform/toolchain restrictions, beware
33
cryptography~=3.4.8
44
# TODO: figure out why 2.10.70 broke things

src/test/python/test_pq3.py

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
id="1-byte payload and extra padding",
4040
),
4141
pytest.param(
42-
b"\x00\x00\x00\x0B\x00\x03\x00\x00hi\x00",
42+
b"\x00\x00\x00\x0b\x00\x03\x00\x00hi\x00",
4343
Container(len=11, proto=pq3.protocol(3, 0), payload=[b"hi"]),
4444
b"",
4545
id="implied parameter list when using proto version 3.0",
@@ -64,7 +64,7 @@ def test_Startup_parse(raw, expected, extra):
6464
),
6565
pytest.param(
6666
dict(len=10, proto=0x12345678),
67-
b"\x00\x00\x00\x0A\x12\x34\x56\x78\x00\x00",
67+
b"\x00\x00\x00\x0a\x12\x34\x56\x78\x00\x00",
6868
id="len and proto set explicitly",
6969
),
7070
pytest.param(
@@ -74,7 +74,7 @@ def test_Startup_parse(raw, expected, extra):
7474
),
7575
pytest.param(
7676
dict(proto=0x12345678, payload=b"abcd"),
77-
b"\x00\x00\x00\x0C\x12\x34\x56\x78abcd",
77+
b"\x00\x00\x00\x0c\x12\x34\x56\x78abcd",
7878
id="implied len with payload",
7979
),
8080
pytest.param(
@@ -84,7 +84,7 @@ def test_Startup_parse(raw, expected, extra):
8484
),
8585
pytest.param(
8686
dict(payload=[b"hi", b""]),
87-
b"\x00\x00\x00\x0C\x00\x03\x00\x00hi\x00\x00",
87+
b"\x00\x00\x00\x0c\x00\x03\x00\x00hi\x00\x00",
8888
id="implied proto version 3 and len when sending more than one parameter",
8989
),
9090
pytest.param(
@@ -131,7 +131,7 @@ def test_Startup_build(packet, expected_bytes):
131131
id="AuthenticationOk",
132132
),
133133
pytest.param(
134-
b"R\x00\x00\x00\x12\x00\x00\x00\x0AEXTERNAL\x00\x00",
134+
b"R\x00\x00\x00\x12\x00\x00\x00\x0aEXTERNAL\x00\x00",
135135
dict(
136136
type=pq3.types.AuthnRequest,
137137
len=18,
@@ -141,7 +141,7 @@ def test_Startup_build(packet, expected_bytes):
141141
id="AuthenticationSASL",
142142
),
143143
pytest.param(
144-
b"R\x00\x00\x00\x0D\x00\x00\x00\x0B12345",
144+
b"R\x00\x00\x00\x0d\x00\x00\x00\x0b12345",
145145
dict(
146146
type=pq3.types.AuthnRequest,
147147
len=13,
@@ -151,7 +151,7 @@ def test_Startup_build(packet, expected_bytes):
151151
id="AuthenticationSASLContinue",
152152
),
153153
pytest.param(
154-
b"R\x00\x00\x00\x0D\x00\x00\x00\x0C12345",
154+
b"R\x00\x00\x00\x0d\x00\x00\x00\x0c12345",
155155
dict(
156156
type=pq3.types.AuthnRequest,
157157
len=13,
@@ -161,7 +161,7 @@ def test_Startup_build(packet, expected_bytes):
161161
id="AuthenticationSASLFinal",
162162
),
163163
pytest.param(
164-
b"p\x00\x00\x00\x0Bhunter2",
164+
b"p\x00\x00\x00\x0bhunter2",
165165
dict(
166166
type=pq3.types.PasswordMessage,
167167
len=11,
@@ -171,7 +171,7 @@ def test_Startup_build(packet, expected_bytes):
171171
id="PasswordMessage",
172172
),
173173
pytest.param(
174-
b"K\x00\x00\x00\x0C\x00\x00\x00\x00\x12\x34\x56\x78",
174+
b"K\x00\x00\x00\x0c\x00\x00\x00\x00\x12\x34\x56\x78",
175175
dict(
176176
type=pq3.types.BackendKeyData,
177177
len=12,
@@ -219,7 +219,7 @@ def test_Startup_build(packet, expected_bytes):
219219
id="Query",
220220
),
221221
pytest.param(
222-
b"D\x00\x00\x00\x0B\x00\x01\x00\x00\x00\x01!",
222+
b"D\x00\x00\x00\x0b\x00\x01\x00\x00\x00\x01!",
223223
dict(type=pq3.types.DataRow, len=11, payload=dict(columns=[b"!"])),
224224
b"",
225225
id="DataRow",
@@ -237,9 +237,9 @@ def test_Startup_build(packet, expected_bytes):
237237
id="EmptyQueryResponse",
238238
),
239239
pytest.param(
240-
b"I\x00\x00\x00\x04\xFF",
240+
b"I\x00\x00\x00\x04\xff",
241241
dict(type=b"I", len=4, payload=None),
242-
b"\xFF",
242+
b"\xff",
243243
id="EmptyQueryResponse with extra bytes",
244244
),
245245
pytest.param(
@@ -278,7 +278,7 @@ def test_Pq3_parse(raw, expected, extra):
278278
),
279279
pytest.param(
280280
dict(type=b"*", len=12, payload=b"1234"),
281-
b"*\x00\x00\x00\x0C1234",
281+
b"*\x00\x00\x00\x0c1234",
282282
id="overridden len (payload underflow)",
283283
),
284284
pytest.param(
@@ -299,36 +299,36 @@ def test_Pq3_parse(raw, expected, extra):
299299
body=[b"SCRAM-SHA-256-PLUS", b"SCRAM-SHA-256", b""],
300300
),
301301
),
302-
b"R\x00\x00\x00\x2A\x00\x00\x00\x0ASCRAM-SHA-256-PLUS\x00SCRAM-SHA-256\x00\x00",
302+
b"R\x00\x00\x00\x2a\x00\x00\x00\x0aSCRAM-SHA-256-PLUS\x00SCRAM-SHA-256\x00\x00",
303303
id="implied len/type for AuthenticationSASL",
304304
),
305305
pytest.param(
306306
dict(
307307
type=pq3.types.AuthnRequest,
308308
payload=dict(type=pq3.authn.SASLContinue, body=b"12345"),
309309
),
310-
b"R\x00\x00\x00\x0D\x00\x00\x00\x0B12345",
310+
b"R\x00\x00\x00\x0d\x00\x00\x00\x0b12345",
311311
id="implied len/type for AuthenticationSASLContinue",
312312
),
313313
pytest.param(
314314
dict(
315315
type=pq3.types.AuthnRequest,
316316
payload=dict(type=pq3.authn.SASLFinal, body=b"12345"),
317317
),
318-
b"R\x00\x00\x00\x0D\x00\x00\x00\x0C12345",
318+
b"R\x00\x00\x00\x0d\x00\x00\x00\x0c12345",
319319
id="implied len/type for AuthenticationSASLFinal",
320320
),
321321
pytest.param(
322322
dict(
323323
type=pq3.types.PasswordMessage,
324324
payload=b"hunter2",
325325
),
326-
b"p\x00\x00\x00\x0Bhunter2",
326+
b"p\x00\x00\x00\x0bhunter2",
327327
id="implied len/type for PasswordMessage",
328328
),
329329
pytest.param(
330330
dict(type=pq3.types.BackendKeyData, payload=dict(pid=1, key=7)),
331-
b"K\x00\x00\x00\x0C\x00\x00\x00\x01\x00\x00\x00\x07",
331+
b"K\x00\x00\x00\x0c\x00\x00\x00\x01\x00\x00\x00\x07",
332332
id="implied len/type for BackendKeyData",
333333
),
334334
pytest.param(
@@ -338,7 +338,7 @@ def test_Pq3_parse(raw, expected, extra):
338338
),
339339
pytest.param(
340340
dict(type=pq3.types.ErrorResponse, payload=dict(fields=[b"error", b""])),
341-
b"E\x00\x00\x00\x0Berror\x00\x00",
341+
b"E\x00\x00\x00\x0berror\x00\x00",
342342
id="implied len/type for ErrorResponse",
343343
),
344344
pytest.param(
@@ -358,7 +358,7 @@ def test_Pq3_parse(raw, expected, extra):
358358
),
359359
pytest.param(
360360
dict(type=pq3.types.DataRow, payload=dict(columns=[b"abcd"])),
361-
b"D\x00\x00\x00\x0E\x00\x01\x00\x00\x00\x04abcd",
361+
b"D\x00\x00\x00\x0e\x00\x01\x00\x00\x00\x04abcd",
362362
id="implied len/type for DataRow",
363363
),
364364
pytest.param(
@@ -406,7 +406,7 @@ def test_Pq3_build(fields, expected):
406406
id="empty column value",
407407
),
408408
pytest.param(
409-
b"\x00\x02\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
409+
b"\x00\x02\xff\xff\xff\xff\xff\xff\xff\xff",
410410
dict(columns=[None, None]),
411411
b"",
412412
id="null columns",
@@ -433,7 +433,7 @@ def test_DataRow_parse(raw, expected, extra):
433433
),
434434
pytest.param(
435435
dict(columns=[None, None]),
436-
b"\x00\x02\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF",
436+
b"\x00\x02\xff\xff\xff\xff\xff\xff\xff\xff",
437437
id="null columns",
438438
),
439439
],
@@ -449,7 +449,7 @@ def test_DataRow_build(fields, expected):
449449
"raw,expected,exception",
450450
[
451451
pytest.param(
452-
b"EXTERNAL\x00\xFF\xFF\xFF\xFF",
452+
b"EXTERNAL\x00\xff\xff\xff\xff",
453453
dict(name=b"EXTERNAL", len=-1, data=None),
454454
None,
455455
id="no initial response",
@@ -467,7 +467,7 @@ def test_DataRow_build(fields, expected):
467467
id="extra data",
468468
),
469469
pytest.param(
470-
b"EXTERNAL\x00\x00\x00\x00\xFFme",
470+
b"EXTERNAL\x00\x00\x00\x00\xffme",
471471
None,
472472
StreamError,
473473
id="underflow",
@@ -489,12 +489,12 @@ def test_SASLInitialResponse_parse(raw, expected, exception):
489489
[
490490
pytest.param(
491491
dict(name=b"EXTERNAL"),
492-
b"EXTERNAL\x00\xFF\xFF\xFF\xFF",
492+
b"EXTERNAL\x00\xff\xff\xff\xff",
493493
id="no initial response",
494494
),
495495
pytest.param(
496496
dict(name=b"EXTERNAL", data=None),
497-
b"EXTERNAL\x00\xFF\xFF\xFF\xFF",
497+
b"EXTERNAL\x00\xff\xff\xff\xff",
498498
id="no initial response (explicit None)",
499499
),
500500
pytest.param(
@@ -504,7 +504,7 @@ def test_SASLInitialResponse_parse(raw, expected, exception):
504504
),
505505
pytest.param(
506506
dict(name=b"EXTERNAL", data=b"me@example.com"),
507-
b"EXTERNAL\x00\x00\x00\x00\x0Eme@example.com",
507+
b"EXTERNAL\x00\x00\x00\x00\x0eme@example.com",
508508
id="initial response",
509509
),
510510
pytest.param(
@@ -514,7 +514,7 @@ def test_SASLInitialResponse_parse(raw, expected, exception):
514514
),
515515
pytest.param(
516516
dict(name=b"EXTERNAL", len=14, data=b"me"),
517-
b"EXTERNAL\x00\x00\x00\x00\x0Eme",
517+
b"EXTERNAL\x00\x00\x00\x00\x0eme",
518518
id="data underflow",
519519
),
520520
],

0 commit comments

Comments
 (0)
0