This is an automated email from the ASF dual-hosted git repository.

vincbeck pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new d6db11e763 Extract the part that depends on FAB from the standalone 
command (#33676)
d6db11e763 is described below

commit d6db11e7634953579ca4737b20aa405f65869834
Author: RaphaĆ«l Vandon <[email protected]>
AuthorDate: Tue Sep 26 06:18:04 2023 -0700

    Extract the part that depends on FAB from the standalone command (#33676)
---
 .../auth/managers/fab/security_manager/override.py | 39 ++++++++++++++++++++++
 airflow/cli/commands/standalone_command.py         | 36 +++-----------------
 airflow/www/security_manager.py                    |  7 ++++
 3 files changed, 51 insertions(+), 31 deletions(-)

diff --git a/airflow/auth/managers/fab/security_manager/override.py 
b/airflow/auth/managers/fab/security_manager/override.py
index 4b884c303a..2e5bf313d9 100644
--- a/airflow/auth/managers/fab/security_manager/override.py
+++ b/airflow/auth/managers/fab/security_manager/override.py
@@ -20,6 +20,8 @@ from __future__ import annotations
 import base64
 import json
 import logging
+import os
+import random
 import uuid
 import warnings
 from functools import cached_property
@@ -332,6 +334,43 @@ class 
FabAirflowSecurityManagerOverride(AirflowSecurityManagerV2):
         """Returns FAB builtin roles."""
         return self.appbuilder.app.config.get("FAB_ROLES", {})
 
+    def create_admin_standalone(self) -> tuple[str | None, str | None]:
+        """Create an Admin user with a random password so that users can 
access airflow."""
+        from airflow.configuration import AIRFLOW_HOME, 
make_group_other_inaccessible
+
+        user_name = "admin"
+
+        # We want a streamlined first-run experience, but we do not want to
+        # use a preset password as people will inevitably run this on a public
+        # server. Thus, we make a random password and store it in AIRFLOW_HOME,
+        # with the reasoning that if you can read that directory, you can see
+        # the database credentials anyway.
+        password_path = os.path.join(AIRFLOW_HOME, 
"standalone_admin_password.txt")
+
+        user_exists = self.find_user(user_name) is not None
+        we_know_password = os.path.isfile(password_path)
+
+        # If the user does not exist, make a random password and make it
+        if not user_exists:
+            print(f"FlaskAppBuilder Authentication Manager: Creating 
{user_name} user")
+            role = self.find_role("Admin")
+            assert role is not None
+            # password does not contain visually similar characters: ijlIJL1oO0
+            password = 
"".join(random.choices("abcdefghkmnpqrstuvwxyzABCDEFGHKMNPQRSTUVWXYZ23456789", 
k=16))
+            with open(password_path, "w") as file:
+                file.write(password)
+            make_group_other_inaccessible(password_path)
+            self.add_user(user_name, "Admin", "User", "[email protected]", 
role, password)
+            print(f"FlaskAppBuilder Authentication Manager: Created 
{user_name} user")
+        # If the user does exist, and we know its password, read the password
+        elif user_exists and we_know_password:
+            with open(password_path) as file:
+                password = file.read().strip()
+        # Otherwise we don't know the password
+        else:
+            password = None
+        return user_name, password
+
     def _init_config(self):
         """
         Initialize config.
diff --git a/airflow/cli/commands/standalone_command.py 
b/airflow/cli/commands/standalone_command.py
index 7821d1d8c1..1eca350f58 100644
--- a/airflow/cli/commands/standalone_command.py
+++ b/airflow/cli/commands/standalone_command.py
@@ -18,7 +18,6 @@ from __future__ import annotations
 
 import logging
 import os
-import random
 import socket
 import subprocess
 import threading
@@ -28,7 +27,7 @@ from typing import TYPE_CHECKING
 
 from termcolor import colored
 
-from airflow.configuration import AIRFLOW_HOME, conf, 
make_group_other_inaccessible
+from airflow.configuration import conf
 from airflow.executors import executor_constants
 from airflow.executors.executor_loader import ExecutorLoader
 from airflow.jobs.job import most_recent_job
@@ -179,39 +178,14 @@ class StandaloneCommand:
         self.print_output("standalone", "Checking database is initialized")
         db.initdb()
         self.print_output("standalone", "Database ready")
-        # See if a user needs creating
-        # We want a streamlined first-run experience, but we do not want to
-        # use a preset password as people will inevitably run this on a public
-        # server. Thus, we make a random password and store it in AIRFLOW_HOME,
-        # with the reasoning that if you can read that directory, you can see
-        # the database credentials anyway.
+
+        # Then create a "default" admin user if necessary
         from airflow.auth.managers.fab.cli_commands.utils import 
get_application_builder
 
         with get_application_builder() as appbuilder:
-            user_exists = appbuilder.sm.find_user("admin")
-        password_path = os.path.join(AIRFLOW_HOME, 
"standalone_admin_password.txt")
-        we_know_password = os.path.isfile(password_path)
-        # If the user does not exist, make a random password and make it
-        if not user_exists:
-            self.print_output("standalone", "Creating admin user")
-            role = appbuilder.sm.find_role("Admin")
-            assert role is not None
-            # password does not contain visually similar characters: ijlIJL1oO0
-            password = 
"".join(random.choices("abcdefghkmnpqrstuvwxyzABCDEFGHKMNPQRSTUVWXYZ23456789", 
k=16))
-            with open(password_path, "w") as file:
-                file.write(password)
-            make_group_other_inaccessible(password_path)
-            appbuilder.sm.add_user("admin", "Admin", "User", 
"[email protected]", role, password)
-            self.print_output("standalone", "Created admin user")
-        # If the user does exist and we know its password, read the password
-        elif user_exists and we_know_password:
-            with open(password_path) as file:
-                password = file.read().strip()
-        # Otherwise we don't know the password
-        else:
-            password = None
+            user_name, password = appbuilder.sm.create_admin_standalone()
         # Store what we know about the user for printing later in startup
-        self.user_info = {"username": "admin", "password": password}
+        self.user_info = {"username": user_name, "password": password}
 
     def is_ready(self):
         """
diff --git a/airflow/www/security_manager.py b/airflow/www/security_manager.py
index 0797260f86..87f845bb4f 100644
--- a/airflow/www/security_manager.py
+++ b/airflow/www/security_manager.py
@@ -603,6 +603,13 @@ class AirflowSecurityManagerV2(SecurityManager, 
LoggingMixin):
 
         session.commit()
 
+    def create_admin_standalone(self) -> tuple[str | None, str | None]:
+        """Perform the required steps when initializing airflow for standalone 
mode.
+
+        If necessary, returns the username and password to be printed in the 
console for users to log in.
+        """
+        return None, None
+
     def sync_roles(self) -> None:
         """
         Initialize default and custom roles with related permissions.

Reply via email to