Skip to content

Commit c5cf081

Browse files
committed
remove kwargs and add sqlalchemy validators
1 parent cf79a5f commit c5cf081

File tree

3 files changed

+48
-47
lines changed

3 files changed

+48
-47
lines changed

lib/pbench/server/api/resources/users_api.py

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import jwt
2+
import datetime
23
from flask import request, jsonify, make_response
34
from flask_restful import Resource, abort
45
from flask_bcrypt import check_password_hash
@@ -126,6 +127,7 @@ def post(self):
126127
first_name=first_name,
127128
last_name=last_name,
128129
email=email_id,
130+
registered_on=datetime.datetime.now(),
129131
)
130132

131133
# insert the user
@@ -439,33 +441,7 @@ def put(self, username):
439441
abort(500, message="INTERNAL ERROR")
440442

441443
# TODO: Check if the user has the right privileges
442-
if verified:
443-
# Check if the user payload contain fields that are either non-updatabale or
444-
# are not present in the user db. If any key in the payload does not match
445-
# with the column name we will abort the update request.
446-
non_updatable = list(
447-
set(post_data.keys()) - set(User.__table__.columns.keys())
448-
)
449-
if non_updatable:
450-
self.logger.warning(
451-
"User trying to update fields that are not present in the user database. Fields: {}",
452-
non_updatable,
453-
)
454-
abort(400, message="Invalid fields in update request payload")
455-
try:
456-
# We will update the user object with the keys and values provided in the request payload.
457-
# THe keys need to match with the column names in the user model.
458-
user.update(**post_data)
459-
except ValueError:
460-
self.logger.warning(
461-
"Either provided values to update the user does not adhere to the user model "
462-
"datatype or user attempted to update the protected properties."
463-
)
464-
abort(400, message="Invalid fields in update request payload")
465-
except Exception:
466-
self.logger.exception("Exception occurred during updating user object")
467-
abort(500, message="INTERNAL ERROR")
468-
else:
444+
if not verified:
469445
self.logger.warning(
470446
"Username retrieved from the auth token {} is different from the username provided",
471447
self.auth.token_auth.current_user().id,
@@ -474,6 +450,41 @@ def put(self, username):
474450
403, message="Authentication token does not belong to the current user"
475451
)
476452

453+
# Check if the user payload contain fields that are either non-updatabale or
454+
# are not present in the user db. If any key in the payload does not match
455+
# with the column name we will abort the update request.
456+
non_existent = list(set(post_data.keys()) - set(User.__table__.columns.keys()))
457+
non_updatable = list(
458+
set(post_data.keys()).intersection(set(User.get_protected()))
459+
)
460+
if non_updatable:
461+
for field in non_updatable:
462+
if getattr(user, field) != post_data[f"{field}"]:
463+
self.logger.warning(
464+
"Either provided values to update the user does not adhere to the user model "
465+
"datatype or user attempted to update the protected properties."
466+
)
467+
abort(400, message="Invalid data in update request payload")
468+
if non_existent:
469+
self.logger.warning(
470+
"User trying to update fields that are not present in the user database. Fields: {}",
471+
non_existent,
472+
)
473+
abort(400, message="Invalid fields in update request payload")
474+
try:
475+
# We will update the user object with the keys and values provided in the request payload.
476+
# THe keys need to match with the column names in the user model.
477+
user.update(**post_data)
478+
except ValueError:
479+
self.logger.warning(
480+
"Either provided values to update the user does not adhere to the user model "
481+
"datatype or user attempted to update the protected properties."
482+
)
483+
abort(400, message="Invalid fields in update request payload")
484+
except Exception:
485+
self.logger.exception("Exception occurred during updating user object")
486+
abort(500, message="INTERNAL ERROR")
487+
477488
return_data = user.get_json()
478489
response_object = {
479490
"status": "success",

lib/pbench/server/database/models/users.py

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import datetime
21
from flask_bcrypt import generate_password_hash
32
from email_validator import validate_email
43
from sqlalchemy import Column, Integer, String, DateTime, LargeBinary
@@ -21,15 +20,6 @@ class User(Database.Base):
2120
email = Column(String(255), unique=True, nullable=False)
2221
auth_tokens = relationship("ActiveTokens", backref="users")
2322

24-
def __init__(self, **kwargs):
25-
super().__init__(**kwargs)
26-
self.username = kwargs.get("username")
27-
self.first_name = kwargs.get("first_name")
28-
self.last_name = kwargs.get("last_name")
29-
self.password = generate_password_hash(kwargs.get("password"))
30-
self.email = kwargs.get("email")
31-
self.registered_on = datetime.datetime.now()
32-
3323
def __str__(self):
3424
return f"User, id: {self.id}, username: {self.username}"
3525

@@ -42,6 +32,10 @@ def get_json(self):
4232
"registered_on": self.registered_on,
4333
}
4434

35+
@staticmethod
36+
def get_protected():
37+
return ["registered_on", "id"]
38+
4539
@staticmethod
4640
def query(id=None, username=None, email=None):
4741
# Currently we would only query with single argument. Argument need to be either username/id/email
@@ -72,13 +66,9 @@ def add(self):
7266
Database.db_session.rollback()
7367
raise e
7468

75-
# Prevent update on "registered_on" field
76-
@validates("registered_on")
77-
def evaluate_registered_on(self, key, value):
78-
if self.registered_on: # Field already exists
79-
if self.registered_on.strftime("%Y-%m-%d %H:%M:%S.%f") != value:
80-
raise ValueError("registered_on cannot be modified.")
81-
return value
69+
@validates("password")
70+
def evaluate_password(self, key, value):
71+
return generate_password_hash(value)
8272

8373
# validate the email field
8474
@validates("email")
@@ -101,8 +91,6 @@ def update(self, **kwargs):
10191
# Insert the auth token
10292
self.auth_tokens.append(value)
10393
Database.db_session.add(value)
104-
elif key == "password":
105-
setattr(self, key, generate_password_hash(value))
10694
else:
10795
setattr(self, key, value)
10896
Database.db_session.commit()

lib/pbench/test/unit/server/test_user_auth.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def test_registration_with_registered_user(client, server_config):
9292
username="user",
9393
first_name="firstname",
9494
last_name="lastname",
95+
registered_on=datetime.datetime.now(),
9596
)
9697
Database.db_session.add(user)
9798
Database.db_session.commit()
@@ -286,7 +287,7 @@ def test_update_user(client, server_config):
286287
)
287288
data = response.json
288289
assert response.status_code == 400
289-
assert data["message"] == "Invalid fields in update request payload"
290+
assert data["message"] == "Invalid data in update request payload"
290291

291292
# Test password update
292293
response = client.put(
@@ -302,6 +303,7 @@ def test_update_user(client, server_config):
302303
time.sleep(1)
303304
response = login_user(client, server_config, "username", "newpass")
304305
data_login = response.json
306+
assert response.status_code == 200
305307
assert data_login["status"] == "success"
306308
assert data_login["message"] == "Successfully logged in."
307309

0 commit comments

Comments
 (0)