|
71 | 71 | uia_email_mapper, |
72 | 72 | uia_phone_mapper, |
73 | 73 | verify_hash, |
| 74 | + get_post_action_redirect, |
74 | 75 | ) |
75 | 76 | from flask_security.core import _get_serializer |
76 | 77 |
|
@@ -1367,18 +1368,73 @@ def test_open_redirect(app, client, get_message): |
1367 | 1368 | ("//github.com", ""), |
1368 | 1369 | ("\t//github.com", "%09//github.com"), |
1369 | 1370 | ] |
1370 | | - for i, o in test_urls: |
1371 | | - data = dict(email="matt@lp.com", password="password", next=i) |
1372 | | - response = client.post("/login", data=data, follow_redirects=False) |
1373 | | - if response.status_code in [302, 303]: |
1374 | | - # this means it passed form validation but should have been quoted |
1375 | | - assert check_location(app, response.location, o) |
1376 | | - elif response.status_code == 200: |
1377 | | - # should have failed form validation |
1378 | | - assert get_message("INVALID_REDIRECT") in response.data |
1379 | | - else: |
1380 | | - raise AssertionError("Bad response code") |
1381 | | - logout(client) |
| 1371 | + for nextloc in ["form", "query"]: |
| 1372 | + for i, o in test_urls: |
| 1373 | + if nextloc == "form": |
| 1374 | + data = dict(email="matt@lp.com", password="password", next=i) |
| 1375 | + response = client.post("/login", data=data, follow_redirects=False) |
| 1376 | + else: |
| 1377 | + data = dict(email="matt@lp.com", password="password") |
| 1378 | + response = client.post( |
| 1379 | + f"/login?next={i}", data=data, follow_redirects=False |
| 1380 | + ) |
| 1381 | + if response.status_code in [302, 303]: |
| 1382 | + # this means it passed form validation but should have been quoted |
| 1383 | + assert check_location(app, response.location, o) |
| 1384 | + elif response.status_code == 200: |
| 1385 | + # should have failed form validation |
| 1386 | + assert get_message("INVALID_REDIRECT") in response.data |
| 1387 | + else: |
| 1388 | + raise AssertionError("Bad response code") |
| 1389 | + logout(client) |
| 1390 | + |
| 1391 | + |
| 1392 | +@pytest.mark.settings(redirect_allow_subdomains=True) |
| 1393 | +def test_open_redirect_subdomain(app, client, get_message): |
| 1394 | + # As above - netloc is also susceptible to crazy escaping |
| 1395 | + # The first URL below, if cut-n-pasted into Chrome will end up at amazon.com |
| 1396 | + # The difference in response between in-form and query string is that |
| 1397 | + # the query string is unescaped by Werkzeug but the form value isn't. |
| 1398 | + app.config["SERVER_NAME"] = "lp.com" |
| 1399 | + test_urls = [ |
| 1400 | + ("https://amazon.com\\.lp.com", "https://amazon.com%5C.lp.com", None), |
| 1401 | + ( |
| 1402 | + "https://amazon.com%5C.lp.com", |
| 1403 | + "https://amazon.com%255C.lp.com", |
| 1404 | + "https://amazon.com%5C.lp.com", |
| 1405 | + ), |
| 1406 | + ( |
| 1407 | + "https://jwag:mypass@amazon.com\\.lp.com", |
| 1408 | + "https://jwag:mypass@amazon.com%5C.lp.com", |
| 1409 | + None, |
| 1410 | + ), |
| 1411 | + ] |
| 1412 | + for nextloc in ["form", "query"]: |
| 1413 | + for i, o, oq in test_urls: |
| 1414 | + if nextloc == "form": |
| 1415 | + data = dict(email="matt@lp.com", password="password", next=i) |
| 1416 | + response = client.post("/login", data=data, follow_redirects=False) |
| 1417 | + else: |
| 1418 | + data = dict(email="matt@lp.com", password="password") |
| 1419 | + response = client.post( |
| 1420 | + f"/login?next={i}", data=data, follow_redirects=False |
| 1421 | + ) |
| 1422 | + if response.status_code in [302, 303]: |
| 1423 | + # this means it passed form validation but should have been quoted |
| 1424 | + assert check_location( |
| 1425 | + app, response.location, oq if oq and (nextloc == "query") else o |
| 1426 | + ) |
| 1427 | + logout(client) |
| 1428 | + |
| 1429 | + |
| 1430 | +def test_get_post_action_redirect(app, client): |
| 1431 | + # test parts of get_post_action_redirect that are hard to get to via the client |
| 1432 | + # e.g. port |
| 1433 | + with app.test_request_context(base_url="https://lp.com:8080/"): |
| 1434 | + r = get_post_action_redirect( |
| 1435 | + "SECURITY_POST_LOGIN_VIEW", dict(next="https://lp.com:8080/myredirect") |
| 1436 | + ) |
| 1437 | + assert r == "https://lp.com:8080/myredirect" |
1382 | 1438 |
|
1383 | 1439 |
|
1384 | 1440 | def test_kwargs(): |
|
0 commit comments