Use Identity instead of Seqence in SQLAlchemy 1.4 for MSSQL
diff --git a/airflow/www/fab_security/sqla/models.py b/airflow/www/fab_security/sqla/models.py
index 685b0a832d084..dea4b8c982718 100644
--- a/airflow/www/fab_security/sqla/models.py
+++ b/airflow/www/fab_security/sqla/models.py
@@ -15,11 +15,12 @@
 # specific language governing permissions and limitations
 # under the License.
 
+import datetime
+
 # This product contains a modified portion of 'Flask App Builder' developed by Daniel Vaz Gaspar.
 # (https://github.com/dpgaspar/Flask-AppBuilder).
 # Copyright 2013, Daniel Vaz Gaspar
-
-import datetime
+from typing import TYPE_CHECKING, Union
 
 from flask import g
 from flask_appbuilder.models.sqla import Model
@@ -41,12 +42,48 @@
 Compatibility note: The models in this file are duplicated from Flask AppBuilder.
 """
 
+if TYPE_CHECKING:
+    try:
+        from sqlalchemy import Identity
+    except Exception:
+        Identity = None
+
+
+def get_sequence_or_identity(sequence_name: str) -> Union[Sequence, 'Identity']:
+    """
+    Depending on the engine it either returns Sequence, or Identity (in case of MSSQL in SQLAlchemy 1.4).
+    In SQLAlchemy 1.4 using sequence is not allowed for primary key columns in MsSQL.
+    Primary columns in MsSQL use IDENTITY keyword to autoincrement.
+    Using Sequence for those fields used to be allowed in SQLAlchemy 1.3 (and essentially ignored
+    if only name was specified).
+
+    See https://docs.sqlalchemy.org/en/14/dialects/mssql.html
+
+        Changed in version 1.4: Removed the ability to use a Sequence object to modify IDENTITY
+        characteristics. Sequence objects now only manipulate true T-SQL SEQUENCE types.
+
+    :param sequence_name: name of the sequence
+    :return: Sequence or Identity
+    """
+    from airflow.settings import SQL_ALCHEMY_CONN
+
+    if SQL_ALCHEMY_CONN is not None and SQL_ALCHEMY_CONN.startswith('mssql'):
+        try:
+            from sqlalchemy import Identity
+
+            return Identity()
+        except Exception:
+            # Identity object is only available in SQLAlchemy 1.4.
+            # For SQLAlchemy 1.3 compatibility we return original Sequence if Identity is missing
+            pass
+    return Sequence(sequence_name)
+
 
 class Action(Model):
     """Represents permission actions such as `can_read`."""
 
     __tablename__ = "ab_permission"
-    id = Column(Integer, Sequence("ab_permission_id_seq"), primary_key=True)
+    id = Column(Integer, get_sequence_or_identity("ab_permission_id_seq"), primary_key=True)
     name = Column(String(100), unique=True, nullable=False)
 
     def __repr__(self):
@@ -57,7 +94,7 @@ class Resource(Model):
     """Represents permission object such as `User` or `Dag`."""
 
     __tablename__ = "ab_view_menu"
-    id = Column(Integer, Sequence("ab_view_menu_id_seq"), primary_key=True)
+    id = Column(Integer, get_sequence_or_identity("ab_view_menu_id_seq"), primary_key=True)
     name = Column(String(250), unique=True, nullable=False)
 
     def __eq__(self, other):
@@ -73,7 +110,7 @@ def __repr__(self):
 assoc_permission_role = Table(
     "ab_permission_view_role",
     Model.metadata,
-    Column("id", Integer, Sequence("ab_permission_view_role_id_seq"), primary_key=True),
+    Column("id", Integer, get_sequence_or_identity("ab_permission_view_role_id_seq"), primary_key=True),
     Column("permission_view_id", Integer, ForeignKey("ab_permission_view.id")),
     Column("role_id", Integer, ForeignKey("ab_role.id")),
     UniqueConstraint("permission_view_id", "role_id"),
@@ -85,7 +122,7 @@ class Role(Model):
 
     __tablename__ = "ab_role"
 
-    id = Column(Integer, Sequence("ab_role_id_seq"), primary_key=True)
+    id = Column(Integer, get_sequence_or_identity("ab_role_id_seq"), primary_key=True)
     name = Column(String(64), unique=True, nullable=False)
     permissions = relationship("Permission", secondary=assoc_permission_role, backref="role")
 
@@ -98,7 +135,7 @@ class Permission(Model):
 
     __tablename__ = "ab_permission_view"
     __table_args__ = (UniqueConstraint("permission_id", "view_menu_id"),)
-    id = Column(Integer, Sequence("ab_permission_view_id_seq"), primary_key=True)
+    id = Column(Integer, get_sequence_or_identity("ab_permission_view_id_seq"), primary_key=True)
     action_id = Column("permission_id", Integer, ForeignKey("ab_permission.id"))
     action = relationship("Action")
     resource_id = Column("view_menu_id", Integer, ForeignKey("ab_view_menu.id"))
@@ -111,7 +148,7 @@ def __repr__(self):
 assoc_user_role = Table(
     "ab_user_role",
     Model.metadata,
-    Column("id", Integer, Sequence("ab_user_role_id_seq"), primary_key=True),
+    Column("id", Integer, get_sequence_or_identity("ab_user_role_id_seq"), primary_key=True),
     Column("user_id", Integer, ForeignKey("ab_user.id")),
     Column("role_id", Integer, ForeignKey("ab_role.id")),
     UniqueConstraint("user_id", "role_id"),
@@ -122,7 +159,7 @@ class User(Model):
     """Represents an Airflow user which has roles assigned to it."""
 
     __tablename__ = "ab_user"
-    id = Column(Integer, Sequence("ab_user_id_seq"), primary_key=True)
+    id = Column(Integer, get_sequence_or_identity("ab_user_id_seq"), primary_key=True)
     first_name = Column(String(64), nullable=False)
     last_name = Column(String(64), nullable=False)
     username = Column(String(256), unique=True, nullable=False)
@@ -192,7 +229,7 @@ class RegisterUser(Model):
     """Represents a user registration."""
 
     __tablename__ = "ab_register_user"
-    id = Column(Integer, Sequence("ab_register_user_id_seq"), primary_key=True)
+    id = Column(Integer, get_sequence_or_identity("ab_register_user_id_seq"), primary_key=True)
     first_name = Column(String(64), nullable=False)
     last_name = Column(String(64), nullable=False)
     username = Column(String(256), unique=True, nullable=False)

Primary columns in MsSQL use IDENTITY keyword to autoincrement. Using
Sequence for those fields used to be allowed in SQLAlchemy 1.3 (and
essentially ignored if only name was specified).

See https://docs.sqlalchemy.org/en/14/dialects/mssql.html:

  Changed in version 1.4: Removed the ability to use a Sequence
  object to modify IDENTITY characteristics. Sequence objects
  now only manipulate true T-SQL SEQUENCE types.

<!--
Thank you for contributing! Please make sure that your code changes
are covered with tests. And in case of new features or big changes
remember to adjust the documentation.

Feel free to ping committers for the review!

In case of existing issue, reference it using one of the following:

closes: #ISSUE
related: #ISSUE

How to write a good git commit message:
http://chris.beams.io/posts/git-commit/
-->

---
**^ Add meaningful description above**

Read the **[Pull Request Guidelines](https://github.com/apache/airflow/blob/main/CONTRIBUTING.rst#pull-request-guidelines)** for more information.
In case of fundamental code change, Airflow Improvement Proposal ([AIP](https://cwiki.apache.org/confluence/display/AIRFLOW/Airflow+Improvements+Proposals)) is needed.
In case of a new dependency, check compliance with the [ASF 3rd Party License Policy](https://www.apache.org/legal/resolved.html#category-x).
In case of backwards incompatible changes please leave a note in [UPDATING.md](https://github.com/apache/airflow/blob/main/UPDATING.md).
