diff --git a/airflow/auth/managers/base_auth_manager.py b/airflow/auth/managers/base_auth_manager.py index 66b79b0a26daf..d626f3681031a 100644 --- a/airflow/auth/managers/base_auth_manager.py +++ b/airflow/auth/managers/base_auth_manager.py @@ -54,6 +54,10 @@ def get_cli_commands() -> list[CLICommand]: def get_user_name(self) -> str: """Return the username associated to the user in session.""" + @abstractmethod + def get_user_display_name(self) -> str: + """Return the user's display name associated to the user in session.""" + @abstractmethod def get_user(self) -> BaseUser: """Return the user associated to the user in session.""" diff --git a/airflow/auth/managers/fab/fab_auth_manager.py b/airflow/auth/managers/fab/fab_auth_manager.py index 27c96d6dd596c..290329dcc8530 100644 --- a/airflow/auth/managers/fab/fab_auth_manager.py +++ b/airflow/auth/managers/fab/fab_auth_manager.py @@ -62,17 +62,22 @@ def get_cli_commands() -> list[CLICommand]: SYNC_PERM_COMMAND, # not in a command group ] + def get_user_display_name(self) -> str: + """Return the user's display name associated to the user in session.""" + user = self.get_user() + first_name = user.first_name.strip() if isinstance(user.first_name, str) else "" + last_name = user.last_name.strip() if isinstance(user.last_name, str) else "" + return f"{first_name} {last_name}".strip() + def get_user_name(self) -> str: """ Return the username associated to the user in session. - For backward compatibility reasons, the username in FAB auth manager is the concatenation of the - first name and the last name. + For backward compatibility reasons, the username in FAB auth manager can be any of username, + email, or the database user ID. """ user = self.get_user() - first_name = user.first_name or "" - last_name = user.last_name or "" - return f"{first_name} {last_name}".strip() + return user.username or user.email or self.get_user_id() def get_user(self) -> User: """Return the user associated to the user in session.""" diff --git a/airflow/migrations/versions/0130_2_8_0_add_owner_display_name_to_audit_log_table.py b/airflow/migrations/versions/0130_2_8_0_add_owner_display_name_to_audit_log_table.py new file mode 100644 index 0000000000000..93e06ce576a48 --- /dev/null +++ b/airflow/migrations/versions/0130_2_8_0_add_owner_display_name_to_audit_log_table.py @@ -0,0 +1,50 @@ +# +# 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. + +"""Add owner_display_name to (Audit) Log table + +Revision ID: f7bf2a57d0a6 +Revises: 375a816bbbf4 +Create Date: 2023-09-12 17:21:45.149658 + +""" + +import sqlalchemy as sa +from alembic import op + + +# revision identifiers, used by Alembic. +revision = "f7bf2a57d0a6" +down_revision = "375a816bbbf4" +branch_labels = None +depends_on = None +airflow_version = "2.8.0" + +TABLE_NAME = "log" + + +def upgrade(): + """Adds owner_display_name column to log""" + with op.batch_alter_table(TABLE_NAME) as batch_op: + batch_op.add_column(sa.Column("owner_display_name", sa.String(500))) + + +def downgrade(): + """Removes owner_display_name column from log""" + with op.batch_alter_table(TABLE_NAME) as batch_op: + batch_op.drop_column("owner_display_name") diff --git a/airflow/models/log.py b/airflow/models/log.py index c3cbaeeabc3cf..7431083d78c39 100644 --- a/airflow/models/log.py +++ b/airflow/models/log.py @@ -37,6 +37,7 @@ class Log(Base): event = Column(String(30)) execution_date = Column(UtcDateTime) owner = Column(String(500)) + owner_display_name = Column(String(500)) extra = Column(Text) __table_args__ = ( @@ -45,7 +46,7 @@ class Log(Base): Index("idx_log_event", event), ) - def __init__(self, event, task_instance=None, owner=None, extra=None, **kwargs): + def __init__(self, event, task_instance=None, owner=None, owner_display_name=None, extra=None, **kwargs): self.dttm = timezone.utcnow() self.event = event self.extra = extra @@ -70,6 +71,7 @@ def __init__(self, event, task_instance=None, owner=None, extra=None, **kwargs): self.map_index = kwargs["map_index"] self.owner = owner or task_owner + self.owner_display_name = owner_display_name or None def __str__(self) -> str: - return f"Log({self.event}, {self.task_id}, {self.owner}, {self.extra})" + return f"Log({self.event}, {self.task_id}, {self.owner}, {self.owner_display_name}, {self.extra})" diff --git a/airflow/utils/db.py b/airflow/utils/db.py index f5c5313aa3f1f..9108ec2e5946f 100644 --- a/airflow/utils/db.py +++ b/airflow/utils/db.py @@ -88,7 +88,7 @@ "2.6.0": "98ae134e6fff", "2.6.2": "c804e5c76e3e", "2.7.0": "405de8318b3a", - "2.8.0": "375a816bbbf4", + "2.8.0": "f7bf2a57d0a6", } diff --git a/airflow/www/decorators.py b/airflow/www/decorators.py index 38aed59de94d0..db856f5de6d34 100644 --- a/airflow/www/decorators.py +++ b/airflow/www/decorators.py @@ -88,8 +88,10 @@ def wrapper(*args, **kwargs): with create_session() as session: if not get_auth_manager().is_logged_in(): user = "anonymous" + user_display = "" else: user = get_auth_manager().get_user_name() + user_display = get_auth_manager().get_user_display_name() fields_skip_logging = {"csrf_token", "_csrf_token"} extra_fields = [ @@ -108,6 +110,7 @@ def wrapper(*args, **kwargs): event=event or f.__name__, task_instance=None, owner=user, + owner_display_name=user_display, extra=str(extra_fields), task_id=params.get("task_id"), dag_id=params.get("dag_id"), diff --git a/airflow/www/templates/appbuilder/navbar_right.html b/airflow/www/templates/appbuilder/navbar_right.html index 1ccf28db418f1..4227d7a3cc98a 100644 --- a/airflow/www/templates/appbuilder/navbar_right.html +++ b/airflow/www/templates/appbuilder/navbar_right.html @@ -66,11 +66,11 @@ {% if auth_manager.is_logged_in() %}