def test_change_hash_type(app, sqlalchemy_datastore):
    init_app_with_options(app, sqlalchemy_datastore, **{
        'SECURITY_PASSWORD_HASH': 'plaintext',
        'SECURITY_PASSWORD_SALT': None,
        'SECURITY_PASSWORD_SCHEMES': ['bcrypt', 'plaintext']
    })

    app.config['SECURITY_PASSWORD_HASH'] = 'bcrypt'
    app.config['SECURITY_PASSWORD_SALT'] = 'salty'

    app.security = Security(
        app,
        datastore=sqlalchemy_datastore,
        register_blueprint=False)

    client = app.test_client()

    response = client.post(
        '/login',
        data=dict(
            email='*****@*****.**',
            password='******'))
    assert response.status_code == 302

    response = client.get('/logout')

    response = client.post(
        '/login',
        data=dict(
            email='*****@*****.**',
            password='******'))
    assert response.status_code == 302
Beispiel #2
0
def test_flash_messages_off(app, sqlalchemy_datastore, get_message):
    init_app_with_options(app, sqlalchemy_datastore, **{
        'SECURITY_FLASH_MESSAGES': False
    })
    client = app.test_client()
    response = client.get('/profile')
    assert get_message('LOGIN') not in response.data
Beispiel #3
0
def test_get_user(app, datastore):
    # The order of identity attributes is important for testing.
    # drivers like psycopg2 will abort the transaction if they throw an
    # error and not continue on so we want to check that case of passing in
    # a string for a numeric field and being able to move onto the next
    # column.
    init_app_with_options(
        app, datastore, **{
            "SECURITY_USER_IDENTITY_ATTRIBUTES": (
                "email",
                "security_number",
                "username",
            )
        })

    with app.app_context():
        user_id = datastore.find_user(email="*****@*****.**").id

        user = datastore.get_user(user_id)
        assert user is not None

        user = datastore.get_user("*****@*****.**")
        assert user is not None

        user = datastore.get_user("matt")
        assert user is not None

        # Regression check (make sure we don't match wildcards)
        user = datastore.get_user("%lp.com")
        assert user is None

        # Verify that numeric non PK works
        user = datastore.get_user(123456)
        assert user is not None
Beispiel #4
0
def test_user_loader(app, sqlalchemy_datastore):
    # user_loader now tries first to match fs_uniquifier then match user.id
    # While we know that fs_uniquifier is a string - we don't know what user.id is
    # and we know that psycopg2 is really finicky about this.
    from flask_security.core import _user_loader

    init_app_with_options(app, sqlalchemy_datastore)
    with app.app_context():
        jill = sqlalchemy_datastore.find_user(email="*****@*****.**")

        # normal case
        user = _user_loader(jill.fs_uniquifier)
        assert user.email == "*****@*****.**"

        # send in an int - make sure it is cast to string for check against
        # fs_uniquifier
        user = _user_loader(1000)
        assert not user
        # with psycopg2 this will lock up DB but since we pass exceptions we can
        # check this by trying some other DB operation
        jill = sqlalchemy_datastore.find_user(email="*****@*****.**")
        assert jill

        # This works since DBs seem to try to cast to underlying type
        user = _user_loader("10")
        jill = sqlalchemy_datastore.find_user(email="*****@*****.**")
        assert jill

        # Since this doesn't match an existing fs_uniqifier, and user.id is an int
        # this will make pyscopg2 angry. This test verifies that we don't in fact
        # try to take a string and use it to lookup an int.
        user = _user_loader("someunknown")
        jill = sqlalchemy_datastore.find_user(email="*****@*****.**")
        assert jill
def test_login_with_bcrypt_enabled(app, sqlalchemy_datastore):
    init_app_with_options(app, sqlalchemy_datastore, **{
        'SECURITY_PASSWORD_HASH': 'bcrypt',
        'SECURITY_PASSWORD_SALT': 'salty'
    })
    response = authenticate(app.test_client(), follow_redirects=True)
    assert b'Home Page' in response.data
def test_modify_permissions(app, datastore):
    ds = datastore
    if not hasattr(ds.role_model, "permissions"):
        return
    init_app_with_options(app, ds)

    with app.app_context():
        perms = {"read", "write"}
        ds.create_role(name="test1", permissions=perms)
        ds.commit()

        t1 = ds.find_role("test1")
        assert perms == t1.get_permissions()
        orig_update_time = t1.update_datetime
        assert t1.update_datetime <= datetime.datetime.utcnow()

        t1.add_permissions("execute")
        ds.commit()

        t1 = ds.find_role("test1")
        assert perms.union({"execute"}) == t1.get_permissions()

        t1.remove_permissions("read")
        ds.commit()
        t1 = ds.find_role("test1")
        assert {"write", "execute"} == t1.get_permissions()
        assert t1.update_datetime > orig_update_time
def test_single_hash_should_have_no_salt(app, sqlalchemy_datastore):
    with raises(RuntimeError):
        init_app_with_options(app, sqlalchemy_datastore, **{
            'SECURITY_PASSWORD_HASH': 'bcrypt',
            'SECURITY_PASSWORD_SALT': 'salty',
            'SECURITY_PASSWORD_SINGLE_HASH': True,
        })
def test_missing_hash_salt_option(app, sqlalchemy_datastore):
    with raises(RuntimeError):
        init_app_with_options(app, sqlalchemy_datastore, **{
            'SECURITY_PASSWORD_HASH': 'bcrypt',
            'SECURITY_PASSWORD_SALT': None,
            'SECURITY_PASSWORD_SINGLE_HASH': False,
        })
def test_verify_password_bcrypt(app, sqlalchemy_datastore):
    init_app_with_options(app, sqlalchemy_datastore, **{
        'SECURITY_PASSWORD_HASH': 'bcrypt',
        'SECURITY_PASSWORD_SALT': 'salty'
    })
    with app.app_context():
        assert verify_password('pass', encrypt_password('pass'))
Beispiel #10
0
def test_change_hash_type(app, sqlalchemy_datastore):
    init_app_with_options(
        app, sqlalchemy_datastore, **{
            "SECURITY_PASSWORD_HASH": "plaintext",
            "SECURITY_PASSWORD_SALT": None,
            "SECURITY_PASSWORD_SCHEMES": ["bcrypt", "plaintext"],
        })

    app.config["SECURITY_PASSWORD_HASH"] = "bcrypt"
    app.config["SECURITY_PASSWORD_SALT"] = "salty"

    app.security = Security(app,
                            datastore=sqlalchemy_datastore,
                            register_blueprint=False)

    client = app.test_client()

    response = client.post("/login",
                           data=dict(email="*****@*****.**", password="******"))
    assert response.status_code == 302

    response = client.get("/logout")

    response = client.post("/login",
                           data=dict(email="*****@*****.**", password="******"))
    assert response.status_code == 302
def test_login_with_bcrypt_enabled(app, sqlalchemy_datastore):
    init_app_with_options(app, sqlalchemy_datastore, **{
        'SECURITY_PASSWORD_HASH': 'bcrypt',
        'SECURITY_PASSWORD_SALT': 'salty'
    })
    response = authenticate(app.test_client(), follow_redirects=True)
    assert b'Home Page' in response.data
def test_verify_password_bcrypt(app, sqlalchemy_datastore):
    init_app_with_options(app, sqlalchemy_datastore, **{
        'SECURITY_PASSWORD_HASH': 'bcrypt',
        'SECURITY_PASSWORD_SALT': 'salty'
    })
    with app.app_context():
        assert verify_password('pass', encrypt_password('pass'))
Beispiel #13
0
def test_passwordless_and_two_factor_configuration_mismatch(app, sqlalchemy_datastore):
    with pytest.raises(ValueError):
        init_app_with_options(
            app,
            sqlalchemy_datastore,
            **{"SECURITY_TWO_FACTOR": True, "SECURITY_TWO_FACTOR_ENABLED_METHODS": []}
        )
Beispiel #14
0
def test_flash_messages_off(app, sqlalchemy_datastore, get_message):
    init_app_with_options(app, sqlalchemy_datastore, **{
        'SECURITY_FLASH_MESSAGES': False
    })
    client = app.test_client()
    response = client.get('/profile')
    assert get_message('LOGIN') not in response.data
Beispiel #15
0
def test_addition_identity_attributes(app, sqlalchemy_datastore):
    init_app_with_options(
        app, sqlalchemy_datastore,
        **{'SECURITY_USER_IDENTITY_ATTRIBUTES': ('email', 'username')})
    client = app.test_client()
    response = authenticate(client, email='matt', follow_redirects=True)
    assert b'Hello [email protected]' in response.data
Beispiel #16
0
def test_change_hash_type(app, sqlalchemy_datastore):
    init_app_with_options(
        app, sqlalchemy_datastore, **{
            'SECURITY_PASSWORD_HASH': 'plaintext',
            'SECURITY_PASSWORD_SALT': None,
            'SECURITY_PASSWORD_SCHEMES': ['bcrypt', 'plaintext']
        })

    app.config['SECURITY_PASSWORD_HASH'] = 'bcrypt'
    app.config['SECURITY_PASSWORD_SALT'] = 'salty'

    app.security = Security(app,
                            datastore=sqlalchemy_datastore,
                            register_blueprint=False)

    client = app.test_client()

    response = client.post('/login',
                           data=dict(email='*****@*****.**', password='******'))
    assert response.status_code == 302

    response = client.get('/logout')

    response = client.post('/login',
                           data=dict(email='*****@*****.**', password='******'))
    assert response.status_code == 302
Beispiel #17
0
def test_addition_identity_attributes(app, sqlalchemy_datastore):
    init_app_with_options(app, sqlalchemy_datastore, **{
        'SECURITY_USER_IDENTITY_ATTRIBUTES': ('email', 'username')
    })
    client = app.test_client()
    response = authenticate(client, email='matt', follow_redirects=True)
    assert b'Hello [email protected]' in response.data
Beispiel #18
0
def test_addition_identity_attributes(app, sqlalchemy_datastore):
    init_app_with_options(
        app, sqlalchemy_datastore,
        **{"SECURITY_USER_IDENTITY_ATTRIBUTES": ("email", "username")})
    client = app.test_client()
    response = authenticate(client, email="matt", follow_redirects=True)
    assert b"Welcome [email protected]" in response.data
def test_logout_methods(app, sqlalchemy_datastore, logout_methods):
    init_app_with_options(app, sqlalchemy_datastore,
                          **{"SECURITY_LOGOUT_METHODS": logout_methods})

    client = app.test_client()

    authenticate(client)

    response = client.get("/logout", follow_redirects=True)

    if "GET" in logout_methods:
        assert response.status_code == 200

        authenticate(client)

    else:
        assert response.status_code == 405  # method not allowed

    response = client.post("/logout", follow_redirects=True)

    if "POST" in logout_methods:
        assert response.status_code == 200

    else:
        assert response.status_code == 405  # method not allowed
def test_find_role(app, datastore):
    init_app_with_options(app, datastore)

    role = datastore.find_role('admin')
    assert role is not None

    role = datastore.find_role('bogus')
    assert role is None
def test_verify_password_bcrypt_single_hash(app, sqlalchemy_datastore):
    init_app_with_options(app, sqlalchemy_datastore, **{
        'SECURITY_PASSWORD_HASH': 'bcrypt',
        'SECURITY_PASSWORD_SALT': None,
        'SECURITY_PASSWORD_SINGLE_HASH': True,
    })
    with app.app_context():
        assert verify_password('pass', encrypt_password('pass'))
Beispiel #22
0
def test_delete_user(app, datastore):
    init_app_with_options(app, datastore)

    user = datastore.find_user(email='*****@*****.**')
    datastore.delete_user(user)
    datastore.commit()
    user = datastore.find_user(email='*****@*****.**')
    assert user is None
Beispiel #23
0
def test_find_role(app, datastore):
    init_app_with_options(app, datastore)

    role = datastore.find_role('admin')
    assert role is not None

    role = datastore.find_role('bogus')
    assert role is None
def test_delete_user(app, datastore):
    init_app_with_options(app, datastore)

    user = datastore.find_user(email='*****@*****.**')
    datastore.delete_user(user)
    datastore.commit()
    user = datastore.find_user(email='*****@*****.**')
    assert user is None
Beispiel #25
0
def test_bcrypt_speed(app, sqlalchemy_datastore):
    init_app_with_options(
        app, sqlalchemy_datastore, **{
            "SECURITY_PASSWORD_HASH": "bcrypt",
            "SECURITY_PASSWORD_SALT": "salty",
            "SECURITY_PASSWORD_SINGLE_HASH": False,
        })
    with app.app_context():
        print(timeit.timeit(lambda: hash_password("pass"), number=100))
Beispiel #26
0
def test_login_with_bcrypt_enabled(app, sqlalchemy_datastore):
    init_app_with_options(
        app, sqlalchemy_datastore, **{
            "SECURITY_PASSWORD_HASH": "bcrypt",
            "SECURITY_PASSWORD_SALT": "salty",
            "SECURITY_PASSWORD_SINGLE_HASH": False,
        })
    response = authenticate(app.test_client(), follow_redirects=True)
    assert b"Home Page" in response.data
Beispiel #27
0
def test_delete_user(app, datastore):
    init_app_with_options(app, datastore)

    with app.app_context():
        user = datastore.find_user(email="*****@*****.**")
        datastore.delete_user(user)
        datastore.commit()
        user = datastore.find_user(email="*****@*****.**")
        assert user is None
Beispiel #28
0
def test_verify_password_bcrypt_single_hash(app, sqlalchemy_datastore):
    init_app_with_options(
        app, sqlalchemy_datastore, **{
            "SECURITY_PASSWORD_HASH": "bcrypt",
            "SECURITY_PASSWORD_SALT": None,
            "SECURITY_PASSWORD_SINGLE_HASH": True,
        })
    with app.app_context():
        assert verify_password("pass", hash_password("pass"))
Beispiel #29
0
def test_find_role(app, datastore):
    init_app_with_options(app, datastore)

    with app.app_context():
        role = datastore.find_role("admin")
        assert role is not None

        role = datastore.find_role("bogus")
        assert role is None
def test_get_permissions(app, datastore):
    """ Verify that role.permissions = None works. """
    ds = datastore
    if not hasattr(ds.role_model, "permissions"):
        return
    init_app_with_options(app, ds)

    with app.app_context():
        t1 = ds.find_role("simple")
        assert set() == t1.get_permissions()
Beispiel #31
0
def test_verify_password_argon2(app, sqlalchemy_datastore):
    init_app_with_options(app, sqlalchemy_datastore,
                          **{"SECURITY_PASSWORD_HASH": "argon2"})
    with app.app_context():
        hashed_pwd = hash_password("pass")
        assert verify_password("pass", hashed_pwd)
        assert "t=10" in hashed_pwd

        # Verify double hash
        assert verify_password("pass", argon2.hash(get_hmac("pass")))
Beispiel #32
0
def test_argon2_speed(app, sqlalchemy_datastore):
    init_app_with_options(
        app, sqlalchemy_datastore, **{
            "SECURITY_PASSWORD_HASH": "argon2",
            "SECURITY_PASSWORD_HASH_PASSLIB_OPTIONS": {
                "argon2__rounds": 10
            },
        })
    with app.app_context():
        print("Hash time for {} iterations: {}".format(
            100, timeit.timeit(lambda: hash_password("pass"), number=100)))
def test_create_user_with_roles(app, datastore):
    init_app_with_options(app, datastore)

    role = datastore.find_role('admin')
    datastore.commit()

    user = datastore.create_user(email='*****@*****.**', username='******',
                                 password='******', roles=[role])
    datastore.commit()
    user = datastore.find_user(email='*****@*****.**')
    assert user.has_role('admin') is True
Beispiel #34
0
def test_verify_password_backward_compatibility(app, sqlalchemy_datastore):
    init_app_with_options(
        app, sqlalchemy_datastore, **{
            'SECURITY_PASSWORD_HASH': 'bcrypt',
            'SECURITY_PASSWORD_SINGLE_HASH': False,
            'SECURITY_PASSWORD_SCHEMES': ['bcrypt', 'plaintext']
        })
    with app.app_context():
        # double hash
        assert verify_password('pass', encrypt_password('pass'))
        # single hash
        assert verify_password('pass', plaintext.hash('pass'))
Beispiel #35
0
def test_verify_password_backward_compatibility(app, sqlalchemy_datastore):
    init_app_with_options(
        app, sqlalchemy_datastore, **{
            "SECURITY_PASSWORD_HASH": "bcrypt",
            "SECURITY_PASSWORD_SINGLE_HASH": False,
            "SECURITY_PASSWORD_SCHEMES": ["bcrypt", "plaintext"],
        })
    with app.app_context():
        # double hash
        assert verify_password("pass", hash_password("pass"))
        # single hash
        assert verify_password("pass", plaintext.hash("pass"))
def test_create_user_with_roles(app, datastore):
    init_app_with_options(app, datastore)

    with app.app_context():
        role = datastore.find_role('admin')
        datastore.commit()

        user = datastore.create_user(email='*****@*****.**', username='******',
                                     password='******', roles=[role])
        datastore.commit()
        user = datastore.find_user(email='*****@*****.**')
        assert user.has_role('admin') is True
Beispiel #37
0
def test_verify_password_bcrypt_rounds_too_low(app, sqlalchemy_datastore):
    with raises(ValueError) as exc_msg:
        init_app_with_options(
            app,
            sqlalchemy_datastore,
            **{
                "SECURITY_PASSWORD_HASH": "bcrypt",
                "SECURITY_PASSWORD_SALT": "salty",
                "SECURITY_PASSWORD_HASH_OPTIONS": {"bcrypt": {"rounds": 3}},
            }
        )
    assert all(s in str(exc_msg) for s in ["rounds", "too low"])
Beispiel #38
0
def test_verify_password_bcrypt_rounds_too_low(app, sqlalchemy_datastore):
    with raises(ValueError) as exc_msg:
        init_app_with_options(
            app, sqlalchemy_datastore, **{
                'SECURITY_PASSWORD_HASH': 'bcrypt',
                'SECURITY_PASSWORD_SALT': 'salty',
                'SECURITY_PASSWORD_HASH_OPTIONS': {
                    'bcrypt': {
                        'rounds': 3
                    }
                }
            })
    assert all(s in str(exc_msg) for s in ['rounds', 'too low'])
def test_get_user(app, datastore):
    init_app_with_options(app, datastore, **{
        'SECURITY_USER_IDENTITY_ATTRIBUTES': ('email', 'username')
    })

    with app.app_context():
        user_id = datastore.find_user(email='*****@*****.**').id

        user = datastore.get_user(user_id)
        assert user is not None

        user = datastore.get_user('*****@*****.**')
        assert user is not None

        user = datastore.get_user('matt')
        assert user is not None
def test_add_role_to_user(app, datastore):
    init_app_with_options(app, datastore)

    # Test with user object
    user = datastore.find_user(email='*****@*****.**')
    assert user.has_role('editor') is False
    assert datastore.add_role_to_user(user, 'editor') is True
    assert datastore.add_role_to_user(user, 'editor') is False
    assert user.has_role('editor') is True

    # Test with email
    assert datastore.add_role_to_user('*****@*****.**', 'editor') is True
    user = datastore.find_user(email='*****@*****.**')
    assert user.has_role('editor') is True

    # Test remove role
    assert datastore.remove_role_from_user(user, 'editor') is True
    assert datastore.remove_role_from_user(user, 'editor') is False
Beispiel #41
0
def test_invalid_hash_scheme(app, sqlalchemy_datastore, get_message):
    with pytest.raises(ValueError):
        init_app_with_options(app, sqlalchemy_datastore, **{
            'SECURITY_PASSWORD_HASH': 'bogus'
        })
def test_missing_hash_salt_option(app, sqlalchemy_datastore):
    with raises(RuntimeError):
        init_app_with_options(app, sqlalchemy_datastore, **{
            'SECURITY_PASSWORD_HASH': 'bcrypt',
        })