Login working

This commit is contained in:
= 2025-01-02 18:40:45 -05:00
parent da002cb02a
commit 5528c9b858
3 changed files with 39 additions and 161 deletions

View File

@ -18,6 +18,11 @@ login_schema = {
"pattern": "^[a-z0-9_]+$",
},
"password": {"type": "string", "minLength": 4},
"totp": {
"type": "string",
"minLength": 6,
"maxLength": 6,
},
},
"required": ["username", "password"],
"additionalProperties": False,
@ -55,7 +60,7 @@ class ApiAuthLoginHandler(BaseApiHandler):
username = data["username"]
password = data["password"]
totp = data.get("totp")
# pylint: disable=no-member
user_data = Users.get_or_none(Users.username == username)
@ -92,8 +97,24 @@ class ApiAuthLoginHandler(BaseApiHandler):
},
)
return
login_result = self.helper.verify_pass(password, user_data.password)
# Establish login result
login_result = None
# Verify user password
pass_login_result = self.helper.verify_pass(password, user_data.password)
# Get the length of user TOTP actions
totp_enabled = len(list(user_data.totp_user)) > 0
# Check if user has TOTP and if we got any type of TOTP data in the login
# payload
if totp_enabled and totp:
totp_login_result = self.controller.totp.verify_user_totp(
user_data.user_id, totp
)
# Check if both password auth and totp auth passed
login_result = pass_login_result is True and totp_login_result is True
elif not totp_enabled and not totp:
# If the user doesn't have TOTP enabled and they didn't send a TOTP code
# We'll pass them through
login_result = pass_login_result
# Valid Login
if login_result:
@ -168,155 +189,3 @@ class ApiAuthLoginHandler(BaseApiHandler):
self.clear_cookie("token")
# self.clear_cookie("user")
# self.clear_cookie("user_data")
class ApiAuthLoginHandler(BaseApiHandler):
def post(self):
try:
data = json.loads(self.request.body)
except json.decoder.JSONDecodeError as e:
logger.error(
"Invalid JSON schema for API"
f" login attempt from {self.get_remote_ip()}"
)
return self.finish_json(
400, {"status": "error", "error": "INVALID_JSON", "error_data": str(e)}
)
try:
validate(data, login_schema)
except ValidationError as e:
logger.error(
"Invalid JSON schema for API"
f" login attempt from {self.get_remote_ip()}"
)
return self.finish_json(
400,
{
"status": "error",
"error": "INVALID_JSON_SCHEMA",
"error_data": str(e),
},
)
username = data["username"]
password = data["password"]
# pylint: disable=no-member
user_data = Users.get_or_none(Users.username == username)
if user_data is None:
self.controller.log_attempt(self.get_remote_ip(), username)
auth_log.error(
f"User attempted to log into {username}."
" Authentication failed from remote IP"
f" {self.get_remote_ip()}. User not found"
)
return self.finish_json(
401,
{
"status": "error",
"error": "INCORRECT_CREDENTIALS",
"error_data": "INVALID CREDENTIALS",
"token": None,
},
)
if not user_data.enabled:
auth_log.error(
f"User attempted to log into {username}."
" Authentication failed from remote"
f" IP {self.get_remote_ip()} account disabled"
)
self.finish_json(
403,
{
"status": "error",
"error": "ACCOUNT_DISABLED",
"error_data": "ACCOUNT DISABLED",
"token": None,
},
)
return
login_result = self.helper.verify_pass(password, user_data.password)
# Valid Login
if login_result:
auth_log.info(
f"{username} successfully"
" authenticated and logged"
f" into panel from remote IP {self.get_remote_ip()}"
)
logger.info(f"User: {user_data} Logged in from IP: {self.get_remote_ip()}")
# record this login
query = Users.select().where(Users.username == username.lower()).get()
query.last_ip = self.get_remote_ip()
query.last_login = Helpers.get_time_as_string()
query.save()
# log this login
self.controller.management.add_to_audit_log(
user_data.user_id, "logged in via the API", None, self.get_remote_ip()
)
extra = None
totp_req = False
if list(user_data.totp_user) > 0:
totp_req = True
extra = {"type": "temp"}
token = self.controller.authentication.generate(user_data.user_id, extra)
self.set_current_user(user_data.user_id, token)
self.finish_json(
200,
{
"status": "ok",
"data": {
"token": token,
"user_id": str(user_data.user_id),
"page": "/panel/dashboard",
"totp": totp_req,
},
},
)
else:
# log this failed login attempt
self.controller.management.add_to_audit_log(
user_data.user_id, "Tried to log in", None, self.get_remote_ip()
)
self.controller.log_attempt(self.get_remote_ip(), username)
# Setup error message for failed login
error_msg = self.helper.translation.translate(
"login", "incorrect", self.helper.get_setting("language")
)
if password == "app/config/default-creds.txt":
error_msg += ". "
error_msg += self.helper.translation.translate(
"login", "defaultPath", self.helper.get_setting("language")
)
self.finish_json(
401,
{
"status": "error",
"error": "INCORRECT_CREDENTIALS",
"error_data": error_msg,
},
)
def set_current_user(self, user_id: str = None, token: str = None):
expire_days = self.helper.get_setting("cookie_expire")
# if helper comes back with false
if not expire_days:
expire_days = "5"
if user_id is not None:
self.set_cookie(
"token",
token,
expires_days=int(expire_days),
)
else:
self.clear_cookie("token")
# self.clear_cookie("user")
# self.clear_cookie("user_data")

View File

@ -183,17 +183,24 @@
//Create an object from the form data entries
let formDataObject = Object.fromEntries(formData.entries());
let body = {
"username": formDataObject.username,
"password": formDataObject.password,
}
if (formDataObject.totp != "") {
body = {
"username": formDataObject.username,
"password": formDataObject.password,
"totp": formDataObject.totp,
}
}
let res = await fetch(`/api/v2/auth/login/`, {
method: 'POST',
headers: {
'X-XSRFToken': formDataObject._xsrf,
"Content-Type": "application/json"
},
body: JSON.stringify({
"username": formDataObject.username,
"password": formDataObject.password,
"totp": formDataObject.totp,
}),
body: JSON.stringify(body),
});
let responseData = await res.json();
if (responseData.status === "ok") {

View File

@ -664,6 +664,7 @@
"roleName": "Role Name",
"selectManager": "Select Manager for User",
"super": "Super User",
"totpIdReq": "TOTP ID Required for request",
"userLang": "User Language",
"userName": "User Name",
"userNameDesc": "What do you want to call this user?",
@ -671,7 +672,8 @@
"userRolesDesc": "Roles this user is a member of.",
"userSettings": "User Settings",
"userTheme": "UI Theme",
"uses": "Number of uses allowed (-1==No Limit)"
"uses": "Number of uses allowed (-1==No Limit)",
"optReq": "TOTP is required for super users. You cannot remove your only TOTP method."
},
"validators": {
"backupName": "Backup name must be a string and a minimum length of 3.",