Password now hashed in app.
This commit is contained in:
parent
2b46eb0353
commit
79f682cbb7
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
32
setup.py
32
setup.py
|
@ -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"],
|
||||
)
|
||||
|
|
|
@ -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:
|
||||
|
|
23
src/phi/security.py
Normal file
23
src/phi/security.py
Normal 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)
|
Loading…
Reference in New Issue
Block a user