Skip to content

Commit eb5c1e2

Browse files
committed
Refactor: moved auth implementation to services/auth_service.py for better documentation and modularity
1 parent 05218dc commit eb5c1e2

File tree

3 files changed

+73
-90
lines changed

3 files changed

+73
-90
lines changed

src/auth/Auth.py

Lines changed: 9 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
1-
from flask import Blueprint, request, jsonify
2-
from flask_jwt_extended import create_access_token, create_refresh_token, jwt_required, get_jwt
3-
from src.models import User
4-
from .PayloadValidator import PayloadValidator
5-
from .Constants import Constants as AuthConstants
6-
from src.Utils import Constants
7-
import base64
1+
from flask import Blueprint
2+
from flask_jwt_extended import jwt_required
3+
from src.services.auth_service import AuthService
84

95
auth_bp = Blueprint("Auth",__name__)
106

@@ -22,95 +18,21 @@ def login():
2218
"""
2319
This endpoint will authenticate the user and create the token, returning a JWT pair (header, payload) cryptographed as standard with HS256
2420
"""
25-
try:
26-
request_user, request_password = str(base64.b64decode((request.headers.get("Authorization").split(" ")[1])), encoding="utf-8").split(":")
27-
user = User.by_id(request_user)
28-
if not user or not User.validate_password(user, request_password):
29-
return jsonify({
30-
"error" : "invalid username or password. check your input payload"
31-
}), Constants.HTTP_BAD_REQUEST.value
32-
access_token = _add_additional_claims(user.username)
33-
refresh_token = create_refresh_token(identity=user.username)
34-
return jsonify({
35-
"message" : "Logged in",
36-
"token" : {
37-
"access": access_token,
38-
"refresh": refresh_token
39-
}
40-
}), Constants.HTTP_OK.value
41-
except KeyError:
42-
return jsonify({
43-
"error": "one or more required fields were not provided. Check your input payload"
44-
}), Constants.HTTP_BAD_REQUEST.value
45-
except ValueError:
46-
return jsonify({
47-
"error": "Invalid Authorization parameters"
48-
}), Constants.HTTP_UNAUTHORIZED.value
4921

50-
def _add_additional_claims(username: str):
51-
additional_claims = {
52-
"perm" : ["log"]
53-
}
54-
if username == 'admin':
55-
additional_claims["perm"].append("create_user")
56-
return create_access_token(identity=username, additional_claims=additional_claims)
22+
return AuthService.login()
5723

58-
@auth_bp.post("/changePassword")
59-
@jwt_required()
24+
@auth_bp.post("/user/password")
6025
def change_password():
6126
"""
6227
Endpoint to allow chaning the password of an user. Only users with admin privileges can perform this acction
6328
Args:
6429
"""
65-
try:
66-
data = request.json
67-
claims = get_jwt()
68-
if claims["sub"] != data["username"]:
69-
return jsonify({
70-
"message": "Invalid token for the provided username."
71-
}), Constants.HTTP_UNAUTHORIZED.value
72-
user = _get_user()
73-
user.set_password(data['password'])
74-
user.save()
75-
return jsonify({
76-
"message": f'Password changed for user {user.username}'
77-
}), Constants.HTTP_OK.value
78-
except KeyError as e:
79-
return jsonify({
80-
"message": str(e)
81-
}), Constants.HTTP_BAD_REQUEST.value
82-
except ValueError:
83-
return jsonify({
84-
"message": AuthConstants.MISSING_AUTH.value
85-
}), Constants.HTTP_UNAUTHORIZED.value
86-
87-
@auth_bp.delete("/deleteUser")
30+
return AuthService.change_password()
31+
32+
@auth_bp.delete("/user")
8833
@jwt_required()
8934
def delete_user():
9035
"""
9136
Endpoint to allow deletion of an user. Only users with admin rights can access this resource.
9237
"""
93-
try:
94-
user = _get_user()
95-
claims = get_jwt()
96-
if AuthConstants.CLAIM_CREATE_USER.value not in claims["perm"]:
97-
return jsonify({
98-
"message": AuthConstants.MISSING_AUTH.value
99-
}), Constants.HTTP_UNAUTHORIZED.value
100-
user.delete()
101-
return jsonify({
102-
"message": "User deleted"
103-
}), Constants.HTTP_OK.value
104-
except KeyError as e:
105-
return jsonify({
106-
"message": str(e)
107-
}), Constants.HTTP_BAD_REQUEST.value
108-
109-
def _get_user():
110-
"""Retrieves the user that will have their password changed"""
111-
data = request.json
112-
PayloadValidator.validate_payload(data)
113-
user = User.by_id(data['username'])
114-
if not user:
115-
raise KeyError("User not found")
116-
return user
38+
return AuthService.delete_user()

src/services/auth_service.py

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,65 @@ def _add_additional_claims(username: str):
8888
}
8989
if username == 'admin':
9090
additional_claims["perm"].append("create_user")
91-
return create_access_token(identity=username, additional_claims=additional_claims)
91+
return create_access_token(identity=username, additional_claims=additional_claims)
92+
93+
@staticmethod
94+
@jwt_required()
95+
def change_password():
96+
"""
97+
Endpoint to allow chaning the password of an user. Only users with admin privileges can perform this acction
98+
Args:
99+
"""
100+
try:
101+
data = request.json
102+
claims = get_jwt()
103+
if claims["sub"] != data["username"]:
104+
return jsonify({
105+
"message": "Invalid token for the provided username."
106+
}), Constants.HTTP_UNAUTHORIZED.value
107+
user = AuthService.get_user()
108+
user.set_password(data['password'])
109+
user.save()
110+
return jsonify({
111+
"message": f'Password changed for user {user.username}'
112+
}), Constants.HTTP_OK.value
113+
except KeyError as e:
114+
return jsonify({
115+
"message": str(e)
116+
}), Constants.HTTP_BAD_REQUEST.value
117+
except ValueError:
118+
return jsonify({
119+
"message": AuthConstants.MISSING_AUTH.value
120+
}), Constants.HTTP_UNAUTHORIZED.value
121+
122+
@staticmethod
123+
@jwt_required()
124+
def delete_user():
125+
"""
126+
Endpoint to allow deletion of an user. Only users with admin rights can access this resource.
127+
"""
128+
try:
129+
user = AuthService.get_user()
130+
claims = get_jwt()
131+
if AuthConstants.CLAIM_CREATE_USER.value not in claims["perm"]:
132+
return jsonify({
133+
"message": AuthConstants.MISSING_AUTH.value
134+
}), Constants.HTTP_UNAUTHORIZED.value
135+
user.delete()
136+
return jsonify({
137+
"message": "User deleted"
138+
}), Constants.HTTP_OK.value
139+
except KeyError as e:
140+
return jsonify({
141+
"message": str(e)
142+
}), Constants.HTTP_BAD_REQUEST.value
143+
144+
@staticmethod
145+
def get_user():
146+
"""Retrieves the user that will have their password changed"""
147+
data = request.json
148+
PayloadValidator.validate_payload(data)
149+
user = User.by_id(data['username'])
150+
if not user:
151+
raise KeyError("User not found")
152+
return user

test/auth/test_auth_handlers.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ def test_change_password(self):
138138
token_auth = {
139139
"Authorization": f"Bearer {response['token']['access']}"
140140
}
141-
password_response = self.client_app.post("/auth/changePassword",
141+
password_response = self.client_app.post("/auth/user/password",
142142
headers=token_auth,
143143
json={
144144
"username" : username,
@@ -168,7 +168,7 @@ def test_delete_user(self):
168168
token_auth = {
169169
"Authorization": f"Bearer {response['token']['access']}"
170170
}
171-
delete_response = self.client_app.delete("/auth/deleteUser",
171+
delete_response = self.client_app.delete("/auth/user",
172172
headers=token_auth,
173173
json={
174174
"username" : self._common_credentials["username"],

0 commit comments

Comments
 (0)