api.auth.user: POST with hashing of input password
This commit is contained in:
parent
8494f3737d
commit
b6e6f1c833
5 changed files with 29 additions and 8 deletions
|
|
@ -1,5 +1,6 @@
|
|||
# scopes.api.auth user
|
||||
|
||||
from datetime import datetime
|
||||
from fastapi import APIRouter, Body
|
||||
import jwt
|
||||
from pwdlib import PasswordHash
|
||||
|
|
@ -13,6 +14,7 @@ from scopes.storage.common import Storage
|
|||
|
||||
class User(BaseModel):
|
||||
uid: str | None = None
|
||||
timeStamp: datetime | None = None
|
||||
name: str
|
||||
login: str
|
||||
display_name: str
|
||||
|
|
@ -20,6 +22,9 @@ class User(BaseModel):
|
|||
pw_hash: str | None = Field(exclude=True, default=None)
|
||||
groups: List[str] = Field(default_factory=list)
|
||||
|
||||
class UserIn(User):
|
||||
password: str | None = None
|
||||
|
||||
# password handling, authentication
|
||||
|
||||
pw_hash = PasswordHash.recommended()
|
||||
|
|
@ -52,7 +57,7 @@ async def get_users(storage: deps.Storage):
|
|||
return result
|
||||
|
||||
@router.post('/users', response_model=User)
|
||||
async def post_user(user: Annotated[User, Body()], storage: deps.Storage):
|
||||
async def post_user(user: Annotated[UserIn, Body()], storage: deps.Storage):
|
||||
users = storage.create(st_user.Users)
|
||||
tr = st_user.User.fromObject(user)
|
||||
users.save(tr)
|
||||
|
|
|
|||
|
|
@ -55,9 +55,14 @@ class Record:
|
|||
def toObject(self, cls):
|
||||
return cls(**self.asDict(flatten=True))
|
||||
|
||||
@staticmethod
|
||||
def prepareData(data):
|
||||
return data
|
||||
|
||||
@classmethod
|
||||
def fromObject(cls, obj):
|
||||
inp = obj.model_dump()
|
||||
headValues = [inp.pop(hf) for hf in cls.headFields]
|
||||
return cls(*headValues, data=inp)
|
||||
data = cls.prepareData(inp)
|
||||
return cls(*headValues, data=data)
|
||||
|
||||
|
|
|
|||
|
|
@ -33,11 +33,11 @@ class Record(shape.Record):
|
|||
return base | self.head | self.data
|
||||
return base | super().asDict()
|
||||
|
||||
@classmethod
|
||||
def fromObject(cls, obj):
|
||||
tr = super().fromObject(obj)
|
||||
tr.data.pop('uid', None)
|
||||
return tr
|
||||
@staticmethod
|
||||
def prepareData(data):
|
||||
data.pop('uid', None)
|
||||
data.pop('timeStamp', None)
|
||||
return data
|
||||
|
||||
@property
|
||||
def uid(self):
|
||||
|
|
|
|||
|
|
@ -8,6 +8,15 @@ class User(concept.Concept):
|
|||
headFields = ('name', 'login')
|
||||
prefix = 'user'
|
||||
|
||||
@staticmethod
|
||||
def prepareData(data):
|
||||
from scopes.api.auth.user import hashPassword
|
||||
data = concept.Concept.prepareData(data)
|
||||
pw = data.pop('password', None)
|
||||
if pw:
|
||||
data['pw_hash'] = hashPassword(pw)
|
||||
return data
|
||||
|
||||
|
||||
@registerContainerClass
|
||||
class Users(concept.Concepts):
|
||||
|
|
|
|||
|
|
@ -73,8 +73,10 @@ def test_user(storage, caplog):
|
|||
u01i = users[0]
|
||||
assert u01i.get(pw_hash) is None
|
||||
resp = clt.post('/users', json={'name': 'jane', 'login': 'jane',
|
||||
'display_name': 'Jane', 'email': 'jane@xmpl.org'})
|
||||
'display_name': 'Jane', 'email': 'jane@xmpl.org',
|
||||
'password': 'secret'})
|
||||
assert resp.status_code == 200
|
||||
u02 = resp.json()
|
||||
assert u02['uid'] == 'user-2'
|
||||
assert u02.get('timeStamp') is not None
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue