예제 #1
0
def test_rate_limit(client, mock_time, listen):
    rate_limit_exceeded = listen(signals.rate_limit_exceeded)
    t0 = datetime(2016, 6, 13, 12, 0, 0, tzinfo=utc)
    now = None

    def set_time(t):
        nonlocal now
        now = t
        mock_time(t)

    def try_login(correct_otp, expect_limit, expect_success):
        device.last_t = -1
        device.save()
        otp_token = _totp(device, now) if correct_otp else '123456'
        resp = client.post('/accounts/login/', {
            'username': '******',
            'password': '******',
            'otp_token': otp_token,
        })
        html = resp.content.decode('utf8')
        is_rate_limit = 'Your account is temporarily locked' in html
        assert expect_limit == is_rate_limit

        if expect_success:
            assert resp.status_code == 302
            assert resp.url == '/'
        else:
            assert resp.status_code == 200

    invitations.invite('john', INVITATION_DURATION, create=True)
    device = _accept(client, models.Invitation.objects.get(), 'pw')
    client.logout()
    assert not _access_homepage(client)

    set_time(t0)
    # 3 failures and we should get locked out
    for _ in range(3):
        try_login(correct_otp=False, expect_limit=False, expect_success=False)

    # try some correct and incorrect logins, they should not work
    for _ in range(3):
        try_login(correct_otp=True, expect_limit=True, expect_success=False)
        try_login(correct_otp=False, expect_limit=True, expect_success=False)

    # one minute later, try again, it should work
    set_time(t0 + timedelta(minutes=1))
    try_login(correct_otp=True, expect_limit=False, expect_success=True)

    assert rate_limit_exceeded == [{'username': '******'}] * 6
예제 #2
0
def test_login(client, listen, username, password, interval, success):
    login_failure = listen(signals.login_failure)
    invitations.invite('john', INVITATION_DURATION, create=True)
    device = _accept(models.Invitation.objects.get(), 'pw')
    assert not _access_homepage(client)
    client.post('/accounts/login/', {
        'username': username,
        'password': password,
        'otp_token': _totp(device, now() + interval),
    })
    if success:
        assert login_failure == []
        assert _access_homepage(client)
    else:
        assert login_failure == [{'otp_failure': bool(interval)}]
        assert not _access_homepage(client)
예제 #3
0
def test_auto_logout(client, mock_time, listen):
    auto_logout = listen(signals.auto_logout)
    t0 = datetime(2016, 6, 13, 12, 0, 0, tzinfo=utc)

    mock_time(t0)
    invitations.invite('john', INVITATION_DURATION, create=True)
    device = _accept(client, models.Invitation.objects.get(), 'pw', t0)
    assert _access_homepage(client)

    mock_time(t0 + timedelta(hours=2, minutes=59))
    assert auto_logout == []
    assert _access_homepage(client)

    mock_time(t0 + timedelta(hours=3, minutes=0, seconds=5))
    assert not _access_homepage(client)
    assert auto_logout == [{'username': '******'}]
예제 #4
0
def test_login(client, listen, username, password, interval, success):
    login_failure = listen(signals.login_failure)
    invitations.invite('john', INVITATION_DURATION, create=True)
    device = _accept(models.Invitation.objects.get(), 'pw')
    assert not _access_homepage(client)
    client.post('/accounts/login/', {
        'username': username,
        'password': password,
        'otp_token': _totp(device, now() + interval),
    })
    if success:
        assert login_failure == []
        assert _access_homepage(client)
    else:
        assert login_failure == [{'otp_failure': bool(interval)}]
        assert not _access_homepage(client)
예제 #5
0
def test_rate_limit(client, mock_time, listen):
    rate_limit_exceeded = listen(signals.rate_limit_exceeded)
    t0 = datetime(2016, 6, 13, 12, 0, 0, tzinfo=utc)
    now = None

    def set_time(t):
        nonlocal now
        now = t
        mock_time(t)

    def try_login(correct_otp, expect_limit, expect_success):
        device.last_t = -1
        device.save()
        resp = client.post('/accounts/login/', {
            'username': '******',
            'password': '******',
            'otp_token': _totp(device, now) if correct_otp else '123456',
        })
        is_rate_limit = ('Your account is temporarily locked'
            in resp.content.decode('utf8'))
        assert expect_limit == is_rate_limit, \
            "rate limit shoud be {}".format(expect_limit)

        if expect_success:
            assert resp.status_code == 302
            assert resp.url == '/'
        else:
            assert resp.status_code == 200

    invitations.invite('john', INVITATION_DURATION, create=True)
    device = _accept(models.Invitation.objects.get(), 'pw')

    set_time(t0)
    # 3 failures and we should get locked out
    for _ in range(3):
        try_login(correct_otp=False, expect_limit=False, expect_success=False)

    # try some correct and incorrect logins, they should not work
    for _ in range(3):
        try_login(correct_otp=True, expect_limit=True, expect_success=False)
        try_login(correct_otp=False, expect_limit=True, expect_success=False)

    # one minute later, try again, it should work
    set_time(t0 + timedelta(minutes=1))
    try_login(correct_otp=True, expect_limit=False, expect_success=True)

    assert rate_limit_exceeded == [{'username': '******'}] * 6
예제 #6
0
def test_auto_logout(client, mock_time, listen):
    auto_logout = listen(signals.auto_logout)
    t0 = datetime(2016, 6, 13, 12, 0, 0, tzinfo=utc)

    mock_time(t0)
    invitations.invite('john', INVITATION_DURATION, create=True)
    device = _accept(models.Invitation.objects.get(), 'pw')
    assert not _access_homepage(client)
    client.post('/accounts/login/', {
        'username': '******',
        'password': '******',
        'otp_token': _totp(device, t0),
    })
    assert _access_homepage(client)

    mock_time(t0 + timedelta(hours=2, minutes=59))
    assert auto_logout == []
    assert _access_homepage(client)

    mock_time(t0 + timedelta(hours=3, minutes=0, seconds=5))
    assert not _access_homepage(client)
    assert auto_logout == [{'username': '******'}]
예제 #7
0
def test_flow(client, listen,
        mock_time, minutes, username_ok, password_ok, code_ok,
        invitation, success):

    invitation_open = listen(signals.invitation_open)
    invitation_accept = listen(signals.invitation_accept)

    t0 = datetime(2016, 6, 13, 12, 0, 0, tzinfo=utc)
    t1 = t0 + timedelta(minutes=minutes)

    mock_time(t0)
    url = invitations.invite('john', INVITATION_DURATION, create=True)
    assert not _access_homepage(client)

    mock_time(t1)
    client.get(url)

    if not invitation:
        assert TOTPDevice.objects.count() == 0
        return

    assert invitation_open == [{'username': '******'}]

    [device] = TOTPDevice.objects.all()
    hour = timedelta(hours=1)
    resp = client.post(url, {
        'username': '******' if username_ok else 'ramirez',
        'password': '******',
        'password-confirm': 'secretz' if password_ok else 'foobar',
        'code': _totp(device, t1) if code_ok else _totp(device, t1 + hour),
    })

    if success:
        assert invitation_accept == [{'username': '******'}]
        assert "Verification successful." in resp.content.decode('utf-8')
        assert _access_homepage(client)

    else:
        assert invitation_accept == []
        assert not _access_homepage(client)
예제 #8
0
def test_flow(client, listen,
        mock_time, minutes, username_ok, password_ok, code_ok,
        invitation, success):

    invitation_open = listen(signals.invitation_open)
    invitation_accept = listen(signals.invitation_accept)

    t0 = datetime(2016, 6, 13, 12, 0, 0, tzinfo=utc)
    t1 = t0 + timedelta(minutes=minutes)

    mock_time(t0)
    url = invitations.invite('john', INVITATION_DURATION, create=True)
    assert not _access_homepage(client)

    mock_time(t1)
    client.get(url)

    if not invitation:
        assert TOTPDevice.objects.count() == 0
        return

    assert invitation_open == [{'username': '******'}]

    [device] = TOTPDevice.objects.all()
    hour = timedelta(hours=1)
    resp = client.post(url, {
        'username': '******' if username_ok else 'ramirez',
        'password': '******',
        'password-confirm': 'secretz' if password_ok else 'foobar',
        'code': _totp(device, t1) if code_ok else _totp(device, t1 + hour),
    })

    if success:
        assert invitation_accept == [{'username': '******'}]
        assert "Verification successful." in resp.content.decode('utf-8')
        assert _access_homepage(client)

    else:
        assert invitation_accept == []
        assert not _access_homepage(client)