コード例 #1
0
def test_spa_get(app, client):
    """
    Test 'single-page-application' style redirects
    This uses json only.
    """
    with capture_flashes() as flashes:
        with capture_registrations() as registrations:
            response = client.post(
                "/register",
                data='{"email": "*****@*****.**",\
                                         "password": "******"}',
                headers={"Content-Type": "application/json"},
            )
            assert response.headers["Content-Type"] == "application/json"
        token = registrations[0]["confirm_token"]

        response = client.get("/confirm/" + token)
        assert response.status_code == 302
        split = urlsplit(response.headers["Location"])
        assert "localhost:8081" == split.netloc
        assert "/confirm-redirect" == split.path
        qparams = dict(parse_qsl(split.query))
        assert qparams["email"] == "*****@*****.**"
    # Arguably for json we shouldn't have any - this is buried in register_user
    # but really shouldn't be.
    assert len(flashes) == 1
コード例 #2
0
def test_bad_sender(app, client, get_message):
    # If SMS sender fails - make sure propagated
    # Test form, json, x signin, setup
    headers = {"Accept": "application/json", "Content-Type": "application/json"}

    # test normal, already setup up login.
    with capture_flashes() as flashes:
        data = {"email": "*****@*****.**", "password": "******"}
        response = client.post("login", data=data, follow_redirects=False)
        assert response.status_code == 302
        assert response.location == "http://localhost/login"
    assert get_message("FAILED_TO_SEND_CODE") in flashes[0]["message"].encode("utf-8")

    # test w/ JSON
    data = dict(email="*****@*****.**", password="******")
    response = client.post("login", json=data, headers=headers)
    assert response.status_code == 500
    assert response.json["response"]["error"].encode("utf-8") == get_message(
        "FAILED_TO_SEND_CODE"
    )

    # Now test setup
    tf_authenticate(app, client)
    client.post("/tf-confirm", data=dict(password="******"), follow_redirects=True)
    data = dict(setup="sms", phone="+442083661188")
    response = client.post("tf-setup", data=data)
    assert get_message("FAILED_TO_SEND_CODE") in response.data

    response = client.post("tf-setup", json=data, headers=headers)
    assert response.status_code == 500
    assert response.json["response"]["errors"]["setup"][0].encode(
        "utf-8"
    ) == get_message("FAILED_TO_SEND_CODE")
コード例 #3
0
def test_expired_reset_token(client, get_message):
    with capture_reset_password_requests() as requests:
        client.post("/reset",
                    data=dict(email="*****@*****.**"),
                    follow_redirects=True)

    user = requests[0]["user"]
    token = requests[0]["token"]

    time.sleep(1)

    with capture_flashes() as flashes:
        msg = get_message("PASSWORD_RESET_EXPIRED",
                          within="1 milliseconds",
                          email=user.email)

        # Test getting reset form with expired token
        response = client.get("/reset/" + token, follow_redirects=True)
        assert msg in response.data

        # Test trying to reset password with expired token
        response = client.post(
            "/reset/" + token,
            data={
                "password": "******",
                "password_confirm": "newpassword"
            },
            follow_redirects=True,
        )

        assert msg in response.data
    assert len(flashes) == 2
コード例 #4
0
def test_verify_fresh(app, client, get_message):
    # Hit a fresh-required endpoint and walk through verify
    authenticate(client)

    with capture_flashes() as flashes:
        response = client.get("/fresh", follow_redirects=True)
        assert b"Please Enter Your Password" in response.data
    assert flashes[0]["category"] == "error"
    assert flashes[0]["message"].encode("utf-8") == get_message(
        "REAUTHENTICATION_REQUIRED")
    form_response = response.data.decode("utf-8")
    matcher = re.match(r'.*action="([^"]*)".*', form_response,
                       re.IGNORECASE | re.DOTALL)
    verify_url = matcher.group(1)

    response = client.get(verify_url)
    assert b"Please Enter Your Password" in response.data

    response = client.post(verify_url,
                           data=dict(password="******"),
                           follow_redirects=False)
    assert b"Please Enter Your Password" in response.data

    response = client.post(verify_url,
                           data=dict(password="******"),
                           follow_redirects=False)
    assert response.location == "http://localhost/fresh"

    # should be fine now
    response = client.get("/fresh", follow_redirects=True)
    assert b"Fresh Only" in response.data
コード例 #5
0
def test_two_factor_two_factor_setup_anonymous(app, client, get_message):

    # trying to pick method without doing earlier stage
    data = dict(setup="mail")

    with capture_flashes() as flashes:
        response = client.post("/tf-setup", data=data)
        assert response.status_code == 302
    assert flashes[0]["category"] == "error"
    assert flashes[0]["message"].encode("utf-8") == get_message(
        "TWO_FACTOR_PERMISSION_DENIED")
コード例 #6
0
def test_spa_get_bad_token(app, client, get_message):
    """ Test expired and invalid token"""
    with capture_flashes() as flashes:
        with capture_reset_password_requests() as requests:
            response = client.post(
                "/reset",
                data='{"email": "*****@*****.**"}',
                headers={"Content-Type": "application/json"},
            )
            assert response.headers["Content-Type"] == "application/json"
            assert "user" not in response.jdata["response"]
        token = requests[0]["token"]
        time.sleep(1)

        response = client.get("/reset/" + token)
        assert response.status_code == 302
        split = urlsplit(response.headers["Location"])
        assert "localhost:8081" == split.netloc
        assert "/reset-error" == split.path
        qparams = dict(parse_qsl(split.query))
        assert len(qparams) == 2
        assert all(k in qparams for k in ["email", "error"])

        msg = get_message(
            "PASSWORD_RESET_EXPIRED", within="1 milliseconds", email="*****@*****.**"
        )
        assert msg == qparams["error"].encode("utf-8")

        # Test mangled token
        token = (
            "WyIxNjQ2MzYiLCIxMzQ1YzBlZmVhM2VhZjYwODgwMDhhZGU2YzU0MzZjMiJd."
            "BZEw_Q.lQyo3npdPZtcJ_sNHVHP103syjM"
            "&url_id=fbb89a8328e58c181ea7d064c2987874bc54a23d"
        )
        response = client.get("/reset/" + token)
        assert response.status_code == 302
        split = urlsplit(response.headers["Location"])
        assert "localhost:8081" == split.netloc
        assert "/reset-error" == split.path
        qparams = dict(parse_qsl(split.query))
        assert len(qparams) == 1
        assert all(k in qparams for k in ["error"])

        msg = get_message("INVALID_RESET_PASSWORD_TOKEN")
        assert msg == qparams["error"].encode("utf-8")
    assert len(flashes) == 0
コード例 #7
0
def test_authn_freshness(app, client, get_message):
    """ Test freshness using default reauthn_handler """
    @auth_required(within=30, grace=0)
    def myview():
        return Response(status=200)

    @auth_required(within=0.001, grace=0)
    def myspecialview():
        return Response(status=200)

    app.add_url_rule("/myview", view_func=myview, methods=["GET"])
    app.add_url_rule("/myspecialview",
                     view_func=myspecialview,
                     methods=["GET"])
    authenticate(client)

    # This should work and not be redirected
    response = client.get("/myview", follow_redirects=False)
    assert response.status_code == 200

    # This should require additional authn and redirect to verify
    time.sleep(0.1)
    with capture_flashes() as flashes:
        response = client.get("/myspecialview", follow_redirects=False)
        assert response.status_code == 302
        assert (
            response.location ==
            "http://localhost/verify?next=http%3A%2F%2Flocalhost%2Fmyspecialview"
        )
    assert flashes[0]["category"] == "error"
    assert flashes[0]["message"].encode("utf-8") == get_message(
        "REAUTHENTICATION_REQUIRED")

    # Test json error response
    response = client.get("/myspecialview",
                          headers={"accept": "application/json"})
    assert response.status_code == 401
    assert response.json["response"]["error"].encode("utf-8") == get_message(
        "REAUTHENTICATION_REQUIRED")
コード例 #8
0
def test_spa_get(app, client):
    """
    Test 'single-page-application' style redirects
    This uses json only.
    """
    with capture_flashes() as flashes:
        with capture_passwordless_login_requests() as requests:
            response = client.post(
                "/login",
                json=dict(email="*****@*****.**"),
                headers={"Content-Type": "application/json"},
            )
            assert response.headers["Content-Type"] == "application/json"
        token = requests[0]["login_token"]

        response = client.get("/login/" + token)
        assert response.status_code == 302
        split = urlsplit(response.headers["Location"])
        assert "localhost:8081" == split.netloc
        assert "/login-redirect" == split.path
        qparams = dict(parse_qsl(split.query))
        assert qparams["email"] == "*****@*****.**"
    assert len(flashes) == 0
コード例 #9
0
def test_recoverable_json(app, client, get_message):
    recorded_resets = []
    recorded_instructions_sent = []

    @password_reset.connect_via(app)
    def on_password_reset(app, user):
        recorded_resets.append(user)

    @reset_password_instructions_sent.connect_via(app)
    def on_instructions_sent(app, user, token):
        recorded_instructions_sent.append(user)

    with capture_flashes() as flashes:
        # Test reset password creates a token and sends email
        with capture_reset_password_requests() as requests:
            with app.mail.record_messages() as outbox:
                response = client.post(
                    "/reset",
                    json=dict(email="*****@*****.**"),
                    headers={"Content-Type": "application/json"},
                )
                assert response.headers["Content-Type"] == "application/json"

        assert len(recorded_instructions_sent) == 1
        assert len(outbox) == 1
        assert response.status_code == 200
        token = requests[0]["token"]

        # Test invalid email
        response = client.post(
            "/reset",
            json=dict(email="*****@*****.**"),
            headers={"Content-Type": "application/json"},
        )
        assert response.status_code == 400
        assert response.json["response"]["errors"]["email"][0].encode(
            "utf-8") == get_message("USER_DOES_NOT_EXIST")

        # Test submitting a new password but leave out 'confirm'
        response = client.post(
            "/reset/" + token,
            data='{"password": "******"}',
            headers={"Content-Type": "application/json"},
        )
        assert response.status_code == 400
        assert response.json["response"]["errors"]["password_confirm"][
            0].encode("utf-8") == get_message("PASSWORD_NOT_PROVIDED")

        # Test submitting a new password
        response = client.post(
            "/reset/" + token + "?include_auth_token",
            json=dict(password="******",
                      password_confirm="awesome sunset"),
            headers={"Content-Type": "application/json"},
        )
        assert all(k in response.json["response"]["user"]
                   for k in ["id", "authentication_token"])
        assert len(recorded_resets) == 1

        # reset automatically logs user in
        logout(client)

        # Test logging in with the new password
        response = client.post(
            "/login?include_auth_token",
            json=dict(email="*****@*****.**", password="******"),
            headers={"Content-Type": "application/json"},
        )
        assert all(k in response.json["response"]["user"]
                   for k in ["id", "authentication_token"])

        logout(client)

        # Use token again - should fail since already have set new password.
        response = client.post(
            "/reset/" + token,
            json=dict(password="******", password_confirm="newpassword"),
            headers={"Content-Type": "application/json"},
        )
        assert response.status_code == 400
        assert len(recorded_resets) == 1

        # Test invalid token
        response = client.post(
            "/reset/bogus",
            json=dict(password="******", password_confirm="newpassword"),
            headers={"Content-Type": "application/json"},
        )
        assert response.json["response"]["error"].encode(
            "utf-8") == get_message("INVALID_RESET_PASSWORD_TOKEN")
    assert len(flashes) == 0
コード例 #10
0
def test_simple_login_json(app, client_nc, get_message):
    auths = []

    @user_authenticated.connect_via(app)
    def authned(myapp, user, **extra_args):
        auths.append((user.email, extra_args["authn_via"]))

    headers = {
        "Accept": "application/json",
        "Content-Type": "application/json"
    }

    with capture_flashes() as flashes:

        response = client_nc.get("/us-signin", headers=headers)
        assert (response.json["response"]["methods"] ==
                app.config["SECURITY_US_ENABLED_METHODS"])
        assert (response.json["response"]["identity_attributes"] ==
                app.config["SECURITY_USER_IDENTITY_ATTRIBUTES"])

        with capture_send_code_requests() as requests:
            with app.mail.record_messages() as outbox:
                response = client_nc.post(
                    "/us-send-code",
                    json=dict(identity="*****@*****.**", chosen_method="email"),
                    headers=headers,
                    follow_redirects=True,
                )
                assert response.status_code == 200
                assert "csrf_token" in response.json["response"]
                assert "user" not in response.json["response"]
        assert len(requests) == 1
        assert len(outbox) == 1

        # try bad code
        response = client_nc.post(
            "/us-signin",
            json=dict(identity="*****@*****.**", passcode="blahblah"),
            headers=headers,
            follow_redirects=True,
        )
        assert response.status_code == 400
        assert response.json["response"]["errors"]["passcode"][0].encode(
            "utf-8") == get_message("INVALID_PASSWORD")

        # Login successfully with code
        response = client_nc.post(
            "/us-signin?include_auth_token",
            json=dict(identity="*****@*****.**", passcode=requests[0]["token"]),
            headers=headers,
            follow_redirects=True,
        )
        assert response.status_code == 200
        assert "authentication_token" in response.json["response"]["user"]
        assert "email" in auths[0][1]

        logout(client_nc)
        response = client_nc.get("/profile",
                                 headers=headers,
                                 follow_redirects=False)
        assert response.status_code == 401

        # login via SMS
        sms_sender = SmsSenderFactory.createSender("test")
        set_phone(app)
        response = client_nc.post(
            "/us-send-code",
            json=dict(identity="*****@*****.**", chosen_method="sms"),
            headers=headers,
            follow_redirects=True,
        )
        assert response.status_code == 200

        code = sms_sender.messages[0].split()[-1].strip(".")
        response = client_nc.post(
            "/us-signin?include_auth_token",
            json=dict(identity="*****@*****.**", passcode=code),
            headers=headers,
            follow_redirects=True,
        )
        assert response.status_code == 200
        assert "authentication_token" in response.json["response"]["user"]
    assert len(flashes) == 0