Move user details view to fab auth manager (#32756)

diff --git a/airflow/auth/managers/base_auth_manager.py b/airflow/auth/managers/base_auth_manager.py
index 6f148cd..6456160 100644
--- a/airflow/auth/managers/base_auth_manager.py
+++ b/airflow/auth/managers/base_auth_manager.py
@@ -52,6 +52,11 @@
         """Return the login page url."""
         ...
 
+    @abstractmethod
+    def get_url_user_profile(self) -> str:
+        """Return the url to a page displaying info about the current user."""
+        ...
+
     def get_security_manager_override_class(self) -> type:
         """
         Return the security manager override class.
diff --git a/airflow/auth/managers/fab/fab_auth_manager.py b/airflow/auth/managers/fab/fab_auth_manager.py
index 6dee27c..c009ff6 100644
--- a/airflow/auth/managers/fab/fab_auth_manager.py
+++ b/airflow/auth/managers/fab/fab_auth_manager.py
@@ -59,3 +59,9 @@
             return url_for(f"{self.security_manager.auth_view.endpoint}.login", next=kwargs["next_url"])
         else:
             return url_for(f"{self.security_manager.auth_view.endpoint}.login")
+
+    def get_url_user_profile(self) -> str:
+        """Return the url to a page displaying info about the current user."""
+        if not self.security_manager.user_view:
+            raise AirflowException("`user_view` not defined in the security manager.")
+        return url_for(f"{self.security_manager.user_view.endpoint}.userinfo")
diff --git a/airflow/auth/managers/fab/views/__init__.py b/airflow/auth/managers/fab/views/__init__.py
new file mode 100644
index 0000000..13a8339
--- /dev/null
+++ b/airflow/auth/managers/fab/views/__init__.py
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
diff --git a/airflow/auth/managers/fab/views/user_details.py b/airflow/auth/managers/fab/views/user_details.py
new file mode 100644
index 0000000..d8aed53
--- /dev/null
+++ b/airflow/auth/managers/fab/views/user_details.py
@@ -0,0 +1,55 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+from __future__ import annotations
+
+from flask_appbuilder.security.views import UserDBModelView
+
+from airflow.security import permissions
+from airflow.www.fab_security.views import MultiResourceUserMixin
+
+
+class CustomUserDBModelView(MultiResourceUserMixin, UserDBModelView):
+    """Customize permission names for FAB's builtin UserDBModelView."""
+
+    _class_permission_name = permissions.RESOURCE_USER
+
+    class_permission_name_mapping = {
+        "resetmypassword": permissions.RESOURCE_MY_PASSWORD,
+        "resetpasswords": permissions.RESOURCE_PASSWORD,
+        "userinfoedit": permissions.RESOURCE_MY_PROFILE,
+        "userinfo": permissions.RESOURCE_MY_PROFILE,
+    }
+
+    method_permission_name = {
+        "add": "create",
+        "download": "read",
+        "show": "read",
+        "list": "read",
+        "edit": "edit",
+        "delete": "delete",
+        "resetmypassword": "read",
+        "resetpasswords": "read",
+        "userinfo": "read",
+        "userinfoedit": "read",
+    }
+
+    base_permissions = [
+        permissions.ACTION_CAN_CREATE,
+        permissions.ACTION_CAN_READ,
+        permissions.ACTION_CAN_EDIT,
+        permissions.ACTION_CAN_DELETE,
+    ]
diff --git a/airflow/www/extensions/init_appbuilder.py b/airflow/www/extensions/init_appbuilder.py
index 5a492f9..2537ea8 100644
--- a/airflow/www/extensions/init_appbuilder.py
+++ b/airflow/www/extensions/init_appbuilder.py
@@ -596,10 +596,6 @@
     def get_url_for_index(self):
         return url_for(f"{self.indexview.endpoint}.{self.indexview.default_view}")
 
-    @property
-    def get_url_for_userinfo(self):
-        return url_for(f"{self.sm.user_view.endpoint}.userinfo")
-
     def get_url_for_locale(self, lang):
         return url_for(
             f"{self.bm.locale_view.endpoint}.{self.bm.locale_view.default_view}",
diff --git a/airflow/www/fab_security/views.py b/airflow/www/fab_security/views.py
index 24e09e7..8e1dd62 100644
--- a/airflow/www/fab_security/views.py
+++ b/airflow/www/fab_security/views.py
@@ -26,7 +26,6 @@
     ResetMyPasswordView,
     ResetPasswordView,
     RoleModelView,
-    UserDBModelView,
     UserInfoEditView,
     UserLDAPModelView,
     UserOAuthModelView,
@@ -229,39 +228,6 @@
         )
 
 
-class CustomUserDBModelView(MultiResourceUserMixin, UserDBModelView):
-    """Customize permission names for FAB's builtin UserDBModelView."""
-
-    _class_permission_name = permissions.RESOURCE_USER
-
-    class_permission_name_mapping = {
-        "resetmypassword": permissions.RESOURCE_MY_PASSWORD,
-        "resetpasswords": permissions.RESOURCE_PASSWORD,
-        "userinfoedit": permissions.RESOURCE_MY_PROFILE,
-        "userinfo": permissions.RESOURCE_MY_PROFILE,
-    }
-
-    method_permission_name = {
-        "add": "create",
-        "download": "read",
-        "show": "read",
-        "list": "read",
-        "edit": "edit",
-        "delete": "delete",
-        "resetmypassword": "read",
-        "resetpasswords": "read",
-        "userinfo": "read",
-        "userinfoedit": "read",
-    }
-
-    base_permissions = [
-        permissions.ACTION_CAN_CREATE,
-        permissions.ACTION_CAN_READ,
-        permissions.ACTION_CAN_EDIT,
-        permissions.ACTION_CAN_DELETE,
-    ]
-
-
 class CustomUserLDAPModelView(MultiResourceUserMixin, UserLDAPModelView):
     """Customize permission names for FAB's builtin UserLDAPModelView."""
 
diff --git a/airflow/www/security.py b/airflow/www/security.py
index 101b55d..7f534e7 100644
--- a/airflow/www/security.py
+++ b/airflow/www/security.py
@@ -24,6 +24,7 @@
 from sqlalchemy import or_
 from sqlalchemy.orm import Session, joinedload
 
+from airflow.auth.managers.fab.views.user_details import CustomUserDBModelView
 from airflow.exceptions import AirflowException, RemovedInAirflow3Warning
 from airflow.models import DagBag, DagModel
 from airflow.security import permissions
@@ -37,7 +38,6 @@
     CustomResetMyPasswordView,
     CustomResetPasswordView,
     CustomRoleModelView,
-    CustomUserDBModelView,
     CustomUserInfoEditView,
     CustomUserLDAPModelView,
     CustomUserOAuthModelView,
diff --git a/airflow/www/templates/appbuilder/navbar_right.html b/airflow/www/templates/appbuilder/navbar_right.html
index e26b6fa..7252b96 100644
--- a/airflow/www/templates/appbuilder/navbar_right.html
+++ b/airflow/www/templates/appbuilder/navbar_right.html
@@ -73,7 +73,7 @@
        <b class="caret"></b>
     </a>
     <ul class="dropdown-menu">
-      <li><a href="{{appbuilder.get_url_for_userinfo}}"><span class="material-icons">account_circle</span>{{_("Your Profile")}}</a></li>
+      <li><a href="{{auth_manager.get_url_user_profile()}}"><span class="material-icons">account_circle</span>{{_("Your Profile")}}</a></li>
       <li role="separator" class="divider"></li>
       <li><a href="{{appbuilder.get_url_for_logout}}"><span class="material-icons">exit_to_app</span>{{_("Log Out")}}</a></li>
     </ul>