Password now hashed in app.

refactor
blallo 2019-07-13 11:39:06 +02:00
parent 2b46eb0353
commit 79f682cbb7
Signed by: blallo
GPG Key ID: 0CBE577C9B72DC3F
5 changed files with 75 additions and 24 deletions

View File

@ -22,11 +22,13 @@ from phi.async_ldap.model import (
Service,
create_new_,
User,
PhiUserExists,
PhiUserDoesNotExist,
PhiEntryExists,
PhiEntryDoesNotExist,
PhiAttributeMissing,
PhiUnauthorized,
Group,
)
from phi.security import hash_pass
BASE_DN = "dc=test,dc=abbiamoundominio,dc=org"
@ -41,7 +43,17 @@ EXISTING_USER = [
"sn": ["Existing User"],
"mail": ["existing@mail.org"],
"uid": ["existing_user"],
"userPassword": ["{SHA}oLY7P6V+DWAMJ9ix7vbMYGIfA+E="],
"userPassword": ["{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g="],
}
]
MISSING_AUTH_USER = [
{
"dn": f"uid=existing_user,ou=Hackers,{BASE_DN}>",
"objectClass": ["inetOrgPerson", "organizationalPerson", "person", "top"],
"cn": ["exists"],
"sn": ["Existing User"],
"mail": ["existing@mail.org"],
"uid": ["existing_user"],
}
]
@ -51,6 +63,7 @@ class MockClient:
self._base_dn = base_dn
self.args = args
self.called_with_args = {}
self.username = f"uid=mock_connection,ou=Services,{base_dn}"
@property
def base_dn(self):
@ -72,6 +85,8 @@ class MockClient:
return EXISTING_USER
elif f"uid=not_existing,ou=Hackers,{BASE_DN}" in args:
return []
elif f"uid=missing_auth_user,ou=Hackers,{BASE_DN}" in args:
return MISSING_AUTH_USER
conn.search = _search
@ -446,15 +461,19 @@ def test_User_singleton(client_fixture):
async def test_User_create_existing(client_fixture):
c = User("existing_user", client_fixture)
with pytest.raises(PhiUserExists):
await c.create("existing@mail.org", sn="exists", cn="Existing User")
with pytest.raises(PhiEntryExists) as e:
await c.create(
"existing@mail.org", password="password", sn="exists", cn="Existing User"
)
assert c.dn in str(e.value)
@pytest.mark.asyncio
async def test_User_create_not_existing(client_fixture):
c = User("not_existing", client_fixture)
await c.create("not@existing.org")
await c.create("not@existing.org", "password")
assert client_fixture.called_with_args["search"]["args"] == (c.dn, 0)
assert c._entry["mail"][0] == "not@existing.org"
@ -477,9 +496,10 @@ async def test_User_sync_existing(client_fixture, caplog):
async def test_User_sync_not_existing(client_fixture, caplog):
c = User("not_existing", client_fixture)
with pytest.raises(PhiUserDoesNotExist):
with pytest.raises(PhiEntryDoesNotExist) as e:
await c.sync()
assert c.dn in str(e.value)
assert client_fixture.called_with_args["search"]["args"] == (c.dn, 0)

View File

@ -67,7 +67,7 @@ cn: Guido
sn: Necchi
mail: gnecchi@autistici.org
uid: necchi
userPassword: {SHA}IZiNWojlNxrWIkk23XDh0svKY14=
userPassword: {SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=
dn: uid=perozzi,ou=Hackers,dc=unit,dc=macaomilano,dc=org
objectClass: inetOrgPerson

View File

@ -2,21 +2,25 @@ from setuptools import setup, find_packages
setup(
name='phi',
version='0.0.1',
description='Post-Human Interface',
name="phi",
version="0.0.1",
description="Post-Human Interface",
# license='',
url='https://git.abbiamoundominio.org/unit/phi',
author='unit',
author_email='unit@paranoici.org',
package_dir={'': 'src'},
url="https://git.abbiamoundominio.org/unit/phi",
author="unit",
author_email="unit@paranoici.org",
package_dir={"": "src"},
packages=find_packages("src"),
entry_points={"console_scripts": ["phid=phi.app:cli"]},
setup_requires=['pytest-runner'],
install_requires=['aiohttp==2.3.8', 'click==7.0', 'pyYAML', 'ldap3', 'bonsai==1.1.0'],
tests_require=['pytest', 'pytest-aiohttp', 'pytest-asyncio', 'async-generator']
setup_requires=["pytest-runner"],
install_requires=[
"aiohttp==2.3.8",
"click==7.0",
"pyYAML",
"ldap3",
"bonsai==1.1.0",
"passlib==1.7.1",
"bcrypt==3.1.7",
],
tests_require=["pytest", "pytest-aiohttp", "pytest-asyncio", "async-generator"],
)

View File

@ -7,6 +7,7 @@ import typing as T
from bonsai import LDAPEntry, LDAPModOp, NoSuchObjectError
from phi.logging import get_logger
from phi.security import hash_pass
log = get_logger(__name__)
@ -253,14 +254,17 @@ class User(Hackers):
def name(self, name):
raise RuntimeError("Name property is not modifiable.")
async def create(self, mail, sn=None, cn=None):
async def create(self, mail, password=None, sn=None, cn=None):
async with self.client.connect(is_async=True) as conn:
res = await conn.search(self.dn, 0)
if len(res) > 0:
raise PhiEntryExists(self.dn)
_sn = sn if sn is not None else self.name
_cn = cn if cn is not None else self.name
self._entry = await create_new_(self, uid=self.name, mail=mail, sn=_sn, cn=_cn)
hashed = hash_pass(password)
self._entry = await create_new_(
self, uid=self.name, mail=mail, sn=_sn, cn=_cn, userPassword=hashed
)
async def sync(self):
async with self.client.connect(is_async=True) as conn:

View File

@ -0,0 +1,23 @@
# -*- encoding: utf-8 -*-
from passlib.hash import (
ldap_sha1,
ldap_bcrypt,
ldap_sha256_crypt,
ldap_sha512_crypt,
ldap_pbkdf2_sha256,
ldap_pbkdf2_sha512,
)
HASH_CALLABLE = {
"sha1": ldap_sha1.hash,
"bcrypt": ldap_bcrypt.hash,
"sha256_crypt": ldap_sha256_crypt.hash,
"sha512_crypt": ldap_sha512_crypt.hash,
"pbkdf2_sha256": ldap_pbkdf2_sha256.hash,
"pbkdf2_sha512": ldap_pbkdf2_sha512.hash,
}
def hash_pass(password, method="sha1"):
return HASH_CALLABLE[method](password)