github-advanced-security[bot] commented on code in PR #47869:
URL: https://github.com/apache/airflow/pull/47869#discussion_r2003486470


##########
airflow/api_fastapi/auth/managers/simple/simple_auth_manager.py:
##########
@@ -98,37 +103,47 @@
 
     @staticmethod
     def get_passwords(users: list[dict[str, str]]) -> dict[str, str]:
-        user_passwords_from_file = {}
-
-        # Read passwords from file
         password_file = SimpleAuthManager.get_generated_password_file()
-        if os.path.isfile(password_file):
-            with open(password_file) as file:
-                passwords_str = file.read().strip()
-                user_passwords_from_file = json.loads(passwords_str)
-
-        usernames = {user["username"] for user in users}
-        return {
-            username: password
-            for username, password in user_passwords_from_file.items()
-            if username in usernames
-        }
+        with open(password_file, "r+") as file:
+            return SimpleAuthManager._get_passwords(users=users, 
stream=file)[0]
 
     def init(self) -> None:
         is_simple_auth_manager_all_admins = conf.getboolean("core", 
"simple_auth_manager_all_admins")
         if is_simple_auth_manager_all_admins:
             return
         users = self.get_users()
-        passwords = self.get_passwords(users)
-        for user in users:
-            if user["username"] not in passwords:
-                # User dot not exist in the file, adding it
-                passwords[user["username"]] = self._generate_password()
-
-            self._print_output(f"Password for user '{user['username']}': 
{passwords[user['username']]}")
-
-        with open(self.get_generated_password_file(), "w") as file:
-            file.write(json.dumps(passwords))
+        password_file = self.get_generated_password_file()
+
+        try:
+            if not os.path.exists(password_file):
+                with open(password_file, "w") as file:
+                    file.write("{}\n")
+            with open(password_file, "r+") as file:
+                try:
+                    # Non-blocking exclusive lock on this file
+                    # Fastapi spins up N workers, so this method is called N 
times in N different processes
+                    # This needs to be called only once so we use the file 
``password_file`` as locking mechanism
+                    fcntl.flock(file, fcntl.LOCK_EX | fcntl.LOCK_NB)
+                    passwords, changed = self._get_passwords(users=users, 
stream=file)
+                    for user in users:
+                        if user["username"] not in passwords:
+                            # User dot not exist in the file, adding it
+                            passwords[user["username"]] = 
self._generate_password()
+                            self._print_output(
+                                f"Password for user '{user['username']}': 
{passwords[user['username']]}"
+                            )
+                            changed = True
+
+                    if changed:
+                        file.seek(0)
+                        file.truncate()
+                        file.write(json.dumps(passwords) + "\n")

Review Comment:
   ## Clear-text storage of sensitive information
   
   This expression stores [sensitive data (password)](1) as clear text.
   This expression stores [sensitive data (password)](2) as clear text.
   
   [Show more 
details](https://github.com/apache/airflow/security/code-scanning/440)



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to