Simple and rapid application development framework, built on top of Flask. includes detailed security, auto CRUD generation for your models, google charts and much more. Demo (login with guest/welcome) - http://flaskappbuilder.pythonanywhere.com/

Overview

Flask App Builder

PyPI https://codecov.io/github/dpgaspar/Flask-AppBuilder/coverage.svg?branch=master

Simple and rapid application development framework, built on top of Flask. includes detailed security, auto CRUD generation for your models, google charts and much more.

Extensive configuration of all functionality, easily integrate with normal Flask/Jinja2 development.

Checkout installation video on YouTube

Quick how to Demo from the docs (login has guest/welcome).

Change Log

Versions for further detail on what changed.

BREAKING CHANGE on 3.0.0 (OAuth)

Major version 3, changed it's OAuth dependency from flask-oauth to authlib, due to this OAuth configuration changed:

Before:

OAUTH_PROVIDERS = [
    {'name':'google', 'icon':'fa-google', 'token_key':'access_token',
        'remote_app': {
            'consumer_key':'GOOGLE KEY',
            'consumer_secret':'GOOGLE SECRET',
            'base_url':'https://www.googleapis.com/oauth2/v2/',
            'request_token_params':{
              'scope': 'email profile'
            },
            'request_token_url':None,
            'access_token_url':'https://accounts.google.com/o/oauth2/token',
            'authorize_url':'https://accounts.google.com/o/oauth2/auth'}
    }
]

Now:

OAUTH_PROVIDERS = [
    {'name':'google', 'icon':'fa-google', 'token_key':'access_token',
        'remote_app': {
            'client_id':'GOOGLE KEY',
            'client_secret':'GOOGLE SECRET',
            'api_base_url':'https://www.googleapis.com/oauth2/v2/',
            'client_kwargs':{
              'scope': 'email profile'
            },
            'request_token_url':None,
            'access_token_url':'https://accounts.google.com/o/oauth2/token',
            'authorize_url':'https://accounts.google.com/o/oauth2/auth'}
    }
]

Also make sure you change your dependency for flask-oauth to authlib

Fixes, Bugs and contributions

You're welcome to report bugs, propose new features, or even better contribute to this project.

Issues, bugs and new features

Contribute

Includes:

  • Database
    • SQLAlchemy, multiple database support: sqlite, MySQL, ORACLE, MSSQL, DB2 etc.
    • Partial support for MongoDB using MongoEngine.
    • Multiple database connections support (Vertical partitioning).
    • Easy mixin audit to models (created/changed by user, and timestamps).
  • Security
    • Automatic permissions lookup, based on exposed methods. It will grant all permissions to the Admin Role.
    • Inserts on the Database all the detailed permissions possible on your application.
    • Public (no authentication needed) and Private permissions.
    • Role based permissions.
    • Authentication support for OAuth, OpenID, Database, LDAP and REMOTE_USER environ var.
    • Support for self user registration.
  • Views and Widgets
    • Automatic menu generation.
    • Automatic CRUD generation.
    • Multiple actions on db records.
    • Big variety of filters for your lists.
    • Various view widgets: lists, master-detail, list of thumbnails etc
    • Select2, Datepicker, DateTimePicker
    • Related Select2 fields.
    • Google charts with automatic group by or direct values and filters.
    • AddOn system, write your own and contribute.
  • CRUD REST API
    • Automatic CRUD RESTful APIs.
    • Internationalization
    • Integration with flask-jwt-extended extension to protect your endpoints.
    • Metadata for dynamic rendering.
    • Selectable columns and metadata keys.
    • Automatic and configurable data validation.
  • Forms
    • Automatic, Add, Edit and Show from Database Models
    • Labels and descriptions for each field.
    • Automatic base validators from model's definition.
    • Custom validators, extra fields, custom filters for related dropdown lists.
    • Image and File support for upload and database field association. It will handle everything for you.
    • Field sets for Form's (Django style).
  • i18n
    • Support for multi-language via Babel
  • Bootstrap 3.1.1 CSS and js, with Select2 and DatePicker
  • Font-Awesome icons, for menu icons and actions.

Some pictures

Login page (with AUTH_DB)

https://raw.github.com/dpgaspar/flask-AppBuilder/master/images/login_db.png

Login page (with AUTH_OAUTH)

https://raw.github.com/dpgaspar/flask-AppBuilder/master/images/login_oauth.png

Security

https://raw.github.com/dpgaspar/flask-AppBuilder/master/images/security.png

Lists:

List contacts example

https://raw.github.com/dpgaspar/flask-AppBuilder/master/images/contact_list.png

List Group example with search

https://raw.github.com/dpgaspar/flask-AppBuilder/master/images/group_list.png

Charts:

Group by pie chart

https://raw.github.com/dpgaspar/flask-AppBuilder/master/images/grouped_chart.png

Direct time chart

https://raw.github.com/dpgaspar/flask-AppBuilder/master/images/direct_chart.png

Group by time chart

https://raw.github.com/dpgaspar/flask-AppBuilder/master/images/chart_time2.png

Projects/Organizations using FAB

If you would like to share your project, or let everyone know that you're using FAB on your organization please submit a PR or send me an email with the details.

Projects:

  • Superset - a data exploration platform designed to be visual, intuitive, and interactive
  • Airflow - a platform to programmatically author, schedule, and monitor workflows.

Organizations:

Depends on:

  • flask
  • click
  • colorama
  • flask-sqlalchemy
  • flask-login
  • flask-openid
  • flask-wtform
  • flask-Babel
Comments
  • refactor: AUTH_LDAP/AUTH_OAUTH + implement role mapping

    refactor: AUTH_LDAP/AUTH_OAUTH + implement role mapping

    This PR is a significant refactor for AUTH_LDAP and AUTH_OAUTH.

    Aside adding significant unit testing, and resolving many issues, it implements a feature with AUTH_ROLES_MAPPING to allow mapping LDAP/OAUTH groups to FAB Roles.

    For more information, please see the updated docs/security.rst

    Resolves:

    • #518
    • #956
    • #1123
    • https://github.com/apache/airflow/issues/8179
    • https://github.com/apache/incubator-superset/issues/3419

    Superseeds these PRs:

    • #770
    urgent 
    opened by thesuperzapper 35
  • Map LDAP groups to FAB roles

    Map LDAP groups to FAB roles

    Thought I'd start working on a way to map LDAP groups to FAB roles (discussion started in #518). The proposal would be as follows: In the config file one could define a dict with mappings from FAB role to LDAP group. During login there would be two ways of checking membership: either gathering all membersOf from the user result, or iterating over all groups in the dict and checking if the user is a member (whichever the admin deems more economical or appropriate). Finally the results would be compared to the existing roles, and the diff would be sent to the backend, removing roles that have been removed and adding those that had been added. Thoughts?

    Ping @bolkedebruin @periscube

    enhancement pending stale 
    opened by villebro 31
  • doing rest queries

    doing rest queries

    I'm trying to figure out doing REST queries to edit data and not finding a lot of documentation / examples. I can do a GET on https://localhost/contactmodelview/json to get a dump of the table in json. But if I want to delete an entry, it seems I need to use the action option. When I try:

    http://localhost/contactmodelview/action/delete/1

    I get permission denied. Looking at the code, it seems the action needs to match a permission in the permissions table, so I tried

    http://localhost/contactmodelview/action/can_delete/1

    but that gives me an error:

    2014-10-28 14:02:22,673:ERROR:app:Exception on /contactmodelview/action/can_delete/1 [GET]
    Traceback (most recent call last):
      File "/usr/lib/python2.7/dist-packages/flask/app.py", line 1817, in wsgi_app
        response = self.full_dispatch_request()
      File "/usr/lib/python2.7/dist-packages/flask/app.py", line 1477, in full_dispatch_request
        rv = self.handle_user_exception(e)
      File "/usr/lib/python2.7/dist-packages/flask/app.py", line 1381, in handle_user_exception
        reraise(exc_type, exc_value, tb)
      File "/usr/lib/python2.7/dist-packages/flask/app.py", line 1475, in full_dispatch_request
        rv = self.dispatch_request()
      File "/usr/lib/python2.7/dist-packages/flask/app.py", line 1461, in dispatch_request
        return self.view_functions[rule.endpoint](**req.view_args)
      File "/usr/lib/python2.7/dist-packages/flask_appbuilder/views.py", line 278, in action
        return action.func(self.datamodel.get(pk))
    AttributeError: 'NoneType' object has no attribute 'func'
    [pid: 28451|app: 0|req: 127/127] 192.168.0.178 () {52 vars in 1917 bytes} [Tue Oct 28 14:02:22 2014] GET /app/contactmodelview/action/can_delete/1 => generated 291 bytes in 213 msecs (HTTP/1.1 500) 2 headers in 84 bytes (1 switches on core 0)
    
    question 
    opened by ben-github 29
  • Sort on Strings?

    Sort on Strings?

    When I view a table, I get blue hyperlinks on many column that allow me to sort on that view (toggling on click between ascending and descending). But some columns don't have the blue hyperlinks. It seems that String columns are the ones I can't sort, while Date, Boolean and Integer columns are sorta-able. Is this known behavior? If so, what would it take to be able to sort on strings?

    enhancement 
    opened by ben-github 26
  • Dynamic field filter in select2

    Dynamic field filter in select2

    Maybe I am not really understanding edit_form_query_rel_fields, but this is a pretty important feature. Build a filter to the drop down list based on the selection of previous drop down lists.

    Usecase user select category A from form field 1. User can then only select subsets of category A from form field 2.

    Is there an easy way of doing this

    PS 0.10 looks rad

    enhancement 
    opened by philliproso 25
  • LDAP user registration: hex-encoded strings instead of human-readable

    LDAP user registration: hex-encoded strings instead of human-readable

    I reported this on a side note in #432, but I feel, it would be more appropriate to file a new issue:

    Versions

    • Python 3.4.5
    Flask==0.12.1
    Flask-AppBuilder==1.8.1
    Flask-Babel==0.11.1
    Flask-Cache==0.13.1
    Flask-Login==0.2.11
    Flask-Migrate==1.5.1
    Flask-OpenID==1.2.5
    Flask-Script==2.0.5
    Flask-SQLAlchemy==2.0
    Flask-Testing==0.6.1
    Flask-WTF==0.14.2
    superset==0.17.3
    

    Expected results

    Logging in with a previously not registered user results in a new user account created from the information gathered from LDAP with all corresponding fields (fisrt name, last name,…) filled out correctly.

    Actual results

    Login works and so does the creation of the user account. However, while the username field is filled out correctly, other fields, such as first_name or last_name:

    hex_problem

    It should be noted that this behavior is only present in a python 3 environment. When run in a python 2.7 venv, everything works as expected.

    bug 
    opened by rumbin 24
  • Nice framework!  but How to pass values as label to template and edit view?

    Nice framework! but How to pass values as label to template and edit view?

    Thanks very much for the framework released, i have read lot of interesting parts and play around with it, it's very handy for fast application development

    However i have a little question to ask,

    I have to defined ModelView classes, I want to add and edit new items inherited from the master Class as shown here. but while editing the sub model, how do I pass the the parent value to the child class? how do i render that in the template?

    class ChildView(ModelView):
        datamodel = SQLAInterface(Child)
        add_template = 'child_add.html'
    
        list_columns = ['child_id', 'parent_id' 'name']
        list_widget = ListThumbnail
        add_widget = FormWidget
        include_cols =  ['child_id', 'parent_id' 'name']
        value_columns =  ['child_id', 'parent_id' 'name']
        add_columns =  ['child_id', 'parent_id' 'name']
    
    class ParentView(ModelView):
    
        datamodel = SQLAInterface(Parent)
        list_widget = ListItem
    
        list_columns = ['parent']
        related_views = [ChildView]
    

    Unfortunately, there is nothing displaying in my child_add.html template as indicated in the tutorial as follow. can you suggest what's the best approach of rendering elements in the templates?

    
    {% import 'appbuilder/general/lib.html' as lib %}
    {% extends 'appbuilder/general/widgets/base_list.html' %}
    
    {% block list_header %}
       {{ super() }}
       <a href="url_for('Class.method for my control')" class="btn btn-sm btn-primary"
            <i class="fa fa-rocket"></i>
       </a>
    {% endblock %}
    
    {% block begin_loop_values %}
        {% for item in value_columns %}
            {% set pk = pks[loop.index-1] %}
            {% if actions %}
                <input id="{{pk}}" class="action_check" name="rowid" value="{{pk}}" type="checkbox">
            {% endif %}
            {% if can_show or can_edit or can_delete %}
                {{ lib.btn_crud(can_show, can_edit, can_delete, pk, modelview_name, filters) }}
            {% endif %}
            </div>
    
            {% for value in include_columns %}
                <p {{ item[value]|safe }}</p>
            {% endfor %}
    
            {% for value in list_columns %}
                <p {{ item[value]|safe }}</p>
            {% endfor %}
    
    
            {% for value in value_columns %}
                <p {{ item[value]|safe }}</p>
            {% endfor %}
    
    
            {% for value in add_columns %}
                <p {{ item[value]|safe }}</p>
            {% endfor %}
    
    
    
        {% endfor %}
    {% endblock %}
    
    
    question pending 
    opened by alexandropov 21
  • Adds ability for users to have multiple roles.

    Adds ability for users to have multiple roles.

    Adds new mapping table to link users with multiple roles. Tested and works, however, because it changes the ab_user table (removes the role_id column) and needs another table for role mapping, it breaks FAB when used with already existing database.

    This is not ready to be merged in yet, but I did a pull request to keep comments and code in a central place. Hopefully I can add migration stuff and then we can do a merge if everything looks good.

    Migration should be easy (drop column, add mapping table and do insert based on user's role_id) but I'm not sure where / how to put that.

    opened by ben-github 21
  • MultipleView with search

    MultipleView with search

    Help me, plz! Make MultipleView with search. https://flask-appbuilder.readthedocs.io/en/latest/quickhowto.html?highlight=multiple We need an independent search for every list on the page. How to do it?

    image

    If you select filters at the top and click search, then they are reset to the bottom sheet. And vice versa.

    opened by vash-sa 20
  • related_views not loading in widgets['related_views'] but does load in related views

    related_views not loading in widgets['related_views'] but does load in related views

    I am having a problem working with related views. An Event has many Attendees. You can see a snapshot of the models here:

    
    class Attendee(db.Model):
        __bind_key__ = 'WILL_DB'
        __tablename__ = 'attendee'
    
        id = Column(INTEGER, primary_key=True)
        event_id = Column(INTEGER, index=True)
        ...
    
        Event = relationship('Event', primaryjoin="Attendee.event_id == foreign(Event.id)")
    
    
    class Event(db.Model):
        __bind_key__ = 'WILL_DB'
        __tablename__ = 'event'
    
        id = Column(INTEGER, primary_key=True)
        rep_id = Column(String(50), nullable=False, server_default=text("''"))
        ...
    
    

    My view functions are as follows

    
    class AttendeeView(ModelView):
        datamodel = SQLAInterface(Attendee)
        list_columns = [x.name for x in Attendee.__table__.columns]
        list_columns.remove("signature")
        list_columns.remove("hcp_data")
    
        show_columns = [x.name for x in Attendee.__table__.columns]
        show_columns.remove("signature")
        show_columns.remove("hcp_data")
    
    
    class EventView(ModelView):
        datamodel = SQLAInterface(Event)
        related_views = [AttendeeView]
        show_template = 'appbuilder/general/model/show_cascade.html'
    
    

    ...and registering:

    appbuilder.add_view(
        EventView,
        "Events",
        icon="fa-calendar",
        category="WILL Support",
        category_icon="fa-wheelchair"
    )
    appbuilder.add_view(
        AttendeeView,
        "Attendees",
        icon="fa-user",
        category="WILL Support",
        category_icon="fa-wheelchair"
    )
    

    When navigating to a /eventview/show/10 page for example, I get this output

      File "<project_root>/app/templates/appbuilder/general/model/show_cascade.html", line 15, in template
        {{ widgets.get('related_views')[loop.index - 1](pk = pk)|safe }}
    TypeError: 'NoneType' object is not callable
    

    When debugging it seems that in this block which in in the file show_cascade.html and similarly in the other show htmls files.

    {% block related_views %}
        {% if related_views is defined %}
            {% for view in related_views %}
                {% call lib.accordion_tag(view.__class__.__name__,view.title, False) %}
                    {{ widgets.get('related_views')[loop.index - 1](pk = pk)|safe }}
                {% endcall %}
            {% endfor %}
        {% endif %}
    {% endblock related_views %}
    

    The variable related_views contains the appropriate AttendeeView however, widgets['related_views'] has nothing.

    Is there an issue with my relationship? This is an old database that doesn't have the correct key setups so I need to do the relationship this way : Event = relationship('Event', primaryjoin="Attendee.event_id == foreign(Event.id)")

    Same data as this issue #973

    opened by jnorton2 19
  • Making an item in row clickable?

    Making an item in row clickable?

    Say an item is clicked in row, how to take user to new page and populate it and showing more detailed view associated with that row?

    Correction:

    Expanded view of the selected row underneath clicked row with more details about that particular row, NOT navigating away from it.

    question 
    opened by scheung38 19
  • Question/Feature Request: Additional user search/filtering on related_views.

    Question/Feature Request: Additional user search/filtering on related_views.

    Environment

    Flask-Appbuilder version: Flask-AppBuilder==3.4.5

    Describe the expected results

    I expected the ability for users to filter on additional fields on top of the parent ID in a related list view, similar to the usual list modelview. Is this possible in any way? Main reason is for select-all and and multiple item actions it would be useful when you have lots of child items.

    Right now it seems to need leaving the related view and navigating to the child item's own list view and then manually configuring the same parent ID filter along with the extra filters - which is a bit unfriendly when everything else already accessible from the related_view.

    Is this behaviour supported in any way or on the roadmap?

    Describe the actual results

    Any filtering queries via GET do not filter the related_view items, and the search accordion isn't present for related_views.

    Steps to reproduce

    opened by steve-embling 0
  • release: 4.2.0 RC1

    release: 4.2.0 RC1

    Description

    Release 4.2.0 for early testing

    ADDITIONAL INFORMATION

    • [ ] Has associated issue:
    • [ ] Is CRUD MVC related.
    • [ ] Is Auth, RBAC security related.
    • [ ] Changes the security db schema.
    • [ ] Introduces new feature
    • [ ] Removes existing feature
    opened by dpgaspar 1
  • Unable to turn off cert validation or point to CA bundle

    Unable to turn off cert validation or point to CA bundle

    In the following example, API_BASE_URL is an https:// URL with self-signed certificates.

    Requests fail with

    [2022-12-20T18:17:49.363+0000] {views.py:659} ERROR - Error authorizing OAuth access token: HTTPSConnectionPool(host='keycloak.redacted.redacted, port=443): Max retries exceeded with url: /auth/realms/redacted/protocol/openid-connect/token (Caused by SSLError(SSLCertVerificationError(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: self signed certificate (_ssl.c:1129)')))

    How can we either:

    • Set TLS verification to false, or
    • Preferably, point FAB OAUTH_PROVIDERS config to a CA bundle to validate the cert?
    OAUTH_PROVIDERS = [
        {
            "name": "keycloak",
            "token_key": "access_token",
            "icon": "fa-key",
            "remote_app": {
                "api_base_url": API_BASE_URL,
                "client_kwargs": {"scope": "email profile"},
                "access_token_url": f"{API_BASE_URL}/token",
                "authorize_url": f"{API_BASE_URL}/auth",
                "request_token_url": None,
                "client_id": CLIENT_ID,
                "client_secret": CLIENT_SECRET,
            },
        }
    ]
    
    opened by brsolomon-deloitte 0
  • show, edit and delete on view returns 404 on modelview with model that inherits from dict

    show, edit and delete on view returns 404 on modelview with model that inherits from dict

    Environment

    Flask-Appbuilder version: 4.1.6

    pip freeze output:

    alembic==1.8.1
    apispec==3.3.2
    attrs==22.1.0
    Babel==2.11.0
    certifi==2022.12.7
    charset-normalizer==2.1.1
    click==8.1.3
    colorama==0.4.6
    dnspython==2.2.1
    email-validator==1.3.0
    Flask==2.2.2
    Flask-AppBuilder==4.1.6
    Flask-Babel==2.0.0
    Flask-JWT-Extended==4.4.4
    Flask-Login==0.6.2
    Flask-Migrate==4.0.0
    Flask-SQLAlchemy==2.5.1
    Flask-WTF==1.0.1
    greenlet==2.0.1
    idna==3.4
    itsdangerous==2.1.2
    Jinja2==3.1.2
    jsonschema==4.17.3
    Mako==1.2.4
    MarkupSafe==2.1.1
    marshmallow==3.19.0
    marshmallow-enum==1.5.1
    marshmallow-sqlalchemy==0.26.1
    packaging==22.0
    prison==0.2.1
    PyJWT==2.6.0
    pyrsistent==0.19.2
    python-dateutil==2.8.2
    pytz==2022.6
    PyYAML==6.0
    requests==2.28.1
    six==1.16.0
    SQLAlchemy==1.4.45
    SQLAlchemy-Utils==0.38.3
    urllib3==1.26.13
    Werkzeug==2.2.2
    WTForms==3.0.1
    

    Describe the expected results

    I would like to be able to show, edit or delete the resources from this model inside the GUI

    class Company(Model, dict):
        """ Tag """
        id = Column(Integer, primary_key=True)
        name = Column(String(50), unique=True, nullable=False)
        code_name = Column(String(10), unique=True, nullable=False)
        subscription_expiration = Column(Date(), nullable=False)
    
        tags = relationship(
            "Tag", secondary=association_company_tag_table, backref="companies")
        employees = relationship("Recipient", back_populates="company", cascade="all, delete-orphan")
    
    
        def __repr__(self):
            return self.name
    
    

    Describe the actual results

    When I try to show, edit or delete a model that inherits from dict it returns a 404 with a valid pk

    image image image image image

    Steps to reproduce

    Using the model above in a model view

    Solution

    On the BaseCRUDView class (file baseviews.py: L1185, L1239 and L1294) The checking for existing record is done like this

    item = self.datamodel.get(pk, self._base_filters)
    if not item:
        abort(404)
    

    By doing it this way, it is working and does not abort with my model

    item = self.datamodel.get(pk, self._base_filters)
    if item is None:
        abort(404)
    

    Was the first way implemented purposely or is it possible to make pull request to fix this issue? Thank you for your time

    pending 
    opened by befuhro 5
  • AUHT_USER_REGISTRATION  NOT WORKING

    AUHT_USER_REGISTRATION NOT WORKING

    i deployed Superser with Docker-Compose,and want to login in and authory with ldap. there is my superset_confug.py

    #AUTHENTICATION FONFIG
    104 AUTH_TYPE = AUTH_LDAP
    105 AUHT_USER_REGISTRATION = True
    106 AUTH_USER_REGISTRATION_ROLE = "Alpha"
    107 AUTH_LDAP_UID_FIELD = "cn"
    108 AUTH_LDAP_FIRSTNAME_FIELD = "givenName"
    109 AHTU_LDAP_LASTNAME_FIELD= "sn"
    110 AUTH_LDAP_EMAIL_FIELD = "mail"
    112 AUTH_LDAP_SERVER = "ldap://xxxxxx:389"
    114 AUTH_LDAP_SEARCH = "cn=%s,ou=groups,dc=xx,dc=xx"
    

    With the above configuration,I can login wiht ldap user,but already in Superset.It is Seem that `AUHT_USER_REGISTRATION = True' not working.Because when login with the user both in ldap and Superset, ldap can verify the password. If the user not in Superset,it can not login.

    Users in Superset

    image

    Users in ldap

    image

    The user test3 can not login in Superset,but others is ok.

    question pending 
    opened by ljclour 3
  • Azure OAuth CSRF State Not Equal Error

    Azure OAuth CSRF State Not Equal Error

    If you'd like to report a bug in Flask-Appbuilder, fill out the template below. Provide any extra information that may be useful

    Responsible disclosure: We want to keep Flask-AppBuilder safe for everyone. If you've discovered a security vulnerability please report to [email protected].

    Environment

    Flask-Appbuilder version:

    pip freeze output: Flask-Appbuilder version==4.1.4

    Describe the expected results

    We are currently running Airflow 2.4.3 on Kubernetes with the Airflow Community helm chart version 8.6.1 (located here: https://github.com/airflow-helm/charts).

    We have enabled Azure OAuth authentication for our webserver. This should bring up our webserver with an "login with azure" button and we should be able to click it and log in just fine. This is our webserver_config that we are using:

    from flask_appbuilder.security.manager import AUTH_OAUTH
    from airflow.www.security import AirflowSecurityManager
    import logging
    from typing import Dict, Any, List, Union
    import os
    import sys
    
    #Add this as a module to pythons path
    sys.path.append('/opt/airflow')
    
    log = logging.getLogger(__name__)
    log.setLevel(os.getenv("AIRFLOW__LOGGING__FAB_LOGGING_LEVEL", "DEBUG"))
    
    class AzureCustomSecurity(AirflowSecurityManager):
        # In this example, the oauth provider == 'azure'.
        # If you ever want to support other providers, see how it is done here:
        # https://github.com/dpgaspar/Flask-AppBuilder/blob/master/flask_appbuilder/security/manager.py#L550
        def get_oauth_user_info(self, provider, resp):
            # Creates the user info payload from Azure.
            # The user previously allowed your app to act on their behalf,
            #   so now we can query the user and teams endpoints for their data.
            # Username and team membership are added to the payload and returned to FAB.
            if provider == "azure":
                log.debug("Azure response received : {0}".format(resp))
                id_token = resp["id_token"]
                log.debug(str(id_token))
                me = self._azure_jwt_token_parse(id_token)
                log.debug("Parse JWT token : {0}".format(me))
                return {
                    "name": me.get("name", ""),
                    "email": me["upn"],
                    "first_name": me.get("given_name", ""),
                    "last_name": me.get("family_name", ""),
                    "id": me["oid"],
                    "username": me["oid"],
                    "role_keys": me.get("roles", []),
                }
    
    # Adding this in because if not the redirect url will start with http and we want https
    os.environ["AIRFLOW__WEBSERVER__ENABLE_PROXY_FIX"] = "True"
    WTF_CSRF_ENABLED = False
    CSRF_ENABLED = False
    AUTH_TYPE = AUTH_OAUTH
    AUTH_ROLES_SYNC_AT_LOGIN = True  # Checks roles on every login
    # Make sure to replace this with the path to your security manager class
    FAB_SECURITY_MANAGER_CLASS = "webserver_config.AzureCustomSecurity"
    # a mapping from the values of `userinfo["role_keys"]` to a list of FAB roles
    AUTH_ROLES_MAPPING = {
        "airflow_dev_admin": ["Admin"],
        "airflow_dev_op": ["Op"],
        "airflow_dev_user": ["User"],
        "airflow_dev_viewer": ["Viewer"]
        }
    # force users to re-auth after 30min of inactivity (to keep roles in sync)
    PERMANENT_SESSION_LIFETIME = 1800
    # If you wish, you can add multiple OAuth providers.
    OAUTH_PROVIDERS = [
        {
            "name": "azure",
            "icon": "fa-windows",
            "token_key": "access_token",
            "remote_app": {
                "client_id": "CLIENT_ID",
                "client_secret": 'AZURE_DEV_CLIENT_SECRET',
                "api_base_url": "https://login.microsoftonline.com/TENANT_ID",
                "request_token_url": None,
                'request_token_params': {
                    'scope': 'openid email profile'
                },
                "access_token_url": "https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/token",
                "access_token_params": {
                    'scope': 'openid email profile'
                },
                "authorize_url": "https://login.microsoftonline.com/TENANT_ID/oauth2/v2.0/authorize",
                "authorize_params": {
                    'scope': 'openid email profile',
                },
                'jwks_uri':'https://login.microsoftonline.com/common/discovery/v2.0/keys',
            },
        },
    ]
    

    Describe the actual results

    Instead, we are getting this error after we click the Azure button:

    [2022-11-28 22:04:58,744] {views.py:659} ERROR - Error authorizing OAuth access token: mismatching_state: CSRF Warning! State not equal in request and response. airflow-web [2022-11-28 22:04:58,744] {views.py:659} ERROR - Error authorizing OAuth access token: mismatching_state: CSRF Warning! State not equal in request and response.

    Steps to reproduce

    Running Airflow 2.4.3 on Kubernetes with the Airflow Community helm chart version 8.6.1 and using the webserver_config file like above. When the webserver is running, you click on the "login to azure" button.

    Additional Comments

    I already posted an issue like this in the Airflow repo, and they said this could more then likely be a Flask problem, which is why I am making this issue here. If any other information is needed please let me know

    question pending 
    opened by ahipp13 7
Releases(v4.2.0)
  • v4.2.0(Jan 3, 2023)

    Minor release 4.1.6

    • feat: add opt-in outer default load option to model REST API (#1971) [Daniel Vaz Gaspar]
    • chore: Add more type annotation to REST API module (#1969) [Daniel Vaz Gaspar]
    • fix: upgrade Select2 to 4.0.13 (#1968) [Nicola Gramola]
    • fix: REST API one-to-one relationship (#1965) [Daniel Vaz Gaspar]
    • fix(api): _info HTTP 500 when exists a defined invalid search field (#1963) [Daniel Vaz Gaspar]
    • chore: Use implicit default loading rather than explicit joined eager loading (#1961) [John Bodley]
    • chore: Increase upper-bound on apispec (#1903) [Tomáš Drtina]
    • fix: replace deprecated attachment_filename (#1956) [Steve Embling]
    Source code(tar.gz)
    Source code(zip)
  • v4.1.6(Nov 10, 2022)

  • v4.1.5(Nov 2, 2022)

    Patch release 4.1.5

    • fix: HTML label IDs for db and ldap login (#1935) [Dosenpfand]
    • fix: OAuth state parameter (#1932) [Daniel Vaz Gaspar]
    • docs: Fix a few typos (#1929) [Tim Gates]
    • chore: Update compiled german translation, delete backup file (#1928) [Dosenpfand]
    • fix: addon managers import (#1920) [Daniel Vaz Gaspar]
    Source code(tar.gz)
    Source code(zip)
  • v4.1.4(Sep 5, 2022)

    Patch release 4.1.4

    • chore: Redirect to prev url on login for AuthRemoteUserView (#1901) [Alexander Ryndin]
    • chore: Bump upper bounds on wtforms and flask-wtf (#1904) [Tomáš Drtina]
    • fix(mvc): related model view setting default related field value (#1898) [Daniel Vaz Gaspar]
    • fix: DateTimePicker rendering in forms (#1698) [Federico Padua]
    • test(fab_cli): tag tests that need internet so they can be skipped (#1880) [jnahmias]
    • fix: fix a wrong 'next' URL in javascript (#1897) [Sansarun Sukawongviwat]
    • chore: allow authlib > 1 updated docs (#1891) [Daniel Vaz Gaspar]
    • docs: fix oauth example config (#1890) [Daniel Vaz Gaspar]
    • docs: fix oauth example config (#1889) [Daniel Vaz Gaspar]
    Source code(tar.gz)
    Source code(zip)
  • v4.1.3(Jul 6, 2022)

    Patch release 4.1.3

    • fix: user stats view search (#1887) [Daniel Vaz Gaspar]
    • fix: Do not render hidden form fields twice (#1848) [Dosenpfand]
    • chore: Bump requirements pillow version, remove PIL from doc (#1873) [Dosenpfand]
    • fix: custom menu option (#1884) [Daniel Vaz Gaspar]
    • fix: FAB_INDEX_VIEW type check (#1883) [Daniel Vaz Gaspar]
    • fix(api): register responses with apispec using components.response() (#1881) [jnahmias]
    • docs: add responsible disclosure text to security (#1882) [Daniel Vaz Gaspar]
    • chore: Improve german translation (#1872) [Dosenpfand]
    • fix: populating permission and vm instead of just setting the id (#1874) [Zef Lin]
    Source code(tar.gz)
    Source code(zip)
  • v4.1.2(Jun 23, 2022)

    Patch release 4.1.2

    • fix: remove sqlite dbs from examples (#1853) [Daniel Vaz Gaspar]
    • fix(MVC): discard excluded filters from query (#1862) [Daniel Vaz Gaspar]
    Source code(tar.gz)
    Source code(zip)
  • v4.1.1(May 25, 2022)

    Patch release 4.1.1

    • fix: custom security class import, bad cast (#1851) [Daniel Vaz Gaspar]
    • fix: Set certificates before reconnecting to LDAP (#1846) [Sebastian Bernauer]
    Source code(tar.gz)
    Source code(zip)
  • v4.1.0(May 3, 2022)

    Minor release 4.1.0

    • docs: add FAB_ADD_SECURITY_API config option (#1840) [Daniel Vaz Gaspar]
    • feat: add keycloak auth provider options (#1832) [nilivingston]
    • docs: add Azure OAUTH example (#1837) [Mathew Wicks]
    • fix: security api (#1831) [Daniel Vaz Gaspar]
    • fix: dependency constraints, bump flask-login, flask-wtf (#1838) [Daniel Vaz Gaspar]
    • fix: noop user update on Auth db, use set user model (#1834) [Daniel Vaz Gaspar]
    • chore: bump postgres to 14 (#1833) [Daniel Vaz Gaspar]
    • chore: Update and fix german translation (#1827) [Dosenpfand]
    • chore: Enhance is_safe_redirect_url (#1826) [Geido]
    • feat: Add CRUD apis for role, permission, user (#1801) [Mayur]
    • docs: updated brackets in OAuth Authentication (#1798) [David Berg]
    • chore: add Slovenian language (#1828) [dkrat7]
    • fix: doc requirements (#1820) [Daniel Vaz Gaspar]
    Source code(tar.gz)
    Source code(zip)
  • v4.0.0(Mar 29, 2022)

    Major release 4.0.0

    • chore: major bumps Flask, Click, PyJWT and flask-jwt-extended (https://github.com/dpgaspar/Flask-AppBuilder/pull/1817) [Daniel Vaz Gaspar] [Breaking changes]

    Breaking changes: https://flask-appbuilder.readthedocs.io/en/latest/breaking.html#breaking-changes

    Source code(tar.gz)
    Source code(zip)
  • v3.4.5(Mar 15, 2022)

    Patch release 3.4.5

    • test: Add test for export-roles --indent's argument “duck casting” to int (https://github.com/dpgaspar/Flask-AppBuilder/pull/1811) [Étienne Boisseau-Sierra]
    • fix: next url on login (OAuth, OID, DB) (https://github.com/dpgaspar/Flask-AppBuilder/pull/1804) [Daniel Vaz Gaspar]
    • docs: Update doc i18 to flask_babel (https://github.com/dpgaspar/Flask-AppBuilder/pull/1792) [Federico Padua]
    • feat(cli): allow export-roles to be beautified (https://github.com/dpgaspar/Flask-AppBuilder/pull/1724) [Étienne Boisseau-Sierra]
    Source code(tar.gz)
    Source code(zip)
  • v3.4.4(Jan 28, 2022)

    Patch release 3.4.4

    • fix: Support SQLAlchemy 1.4.X (#1786) [Daniel Vaz Gaspar]
    • feat: allow multiple values for the same filter (#1737) [Will Rogers]
    • fix: Only update user.last_login on successful authentication (#1775) [blag]
    • chore: update jsonschema pip package (#1782) [Hugh A. Miles II]
    Source code(tar.gz)
    Source code(zip)
  • v3.4.3(Jan 28, 2022)

    Patch release 3.4.3

    • fix: openapi on and off config flag (#1770) [Daniel Vaz Gaspar]
    • fix: data not defined in azure oauth (#1769) [Dalton Pearson]
    • fix: Handle authorize_access_token exception (#1766) [Michał Konarski]
    • fix: Set role and confirm password while adding user mandatory (#1758) [Mayur]
    • fix: required roles on user form not showing error msg (#1772) [Daniel Vaz Gaspar]
    • fix: make servers be actual servers on swagger, full endpoint paths (#1773) [Daniel Vaz Gaspar]
    • docs: adds missing config key FAB_OPENAPI_SERVERS (#1776)
    Source code(tar.gz)
    Source code(zip)
  • v3.4.2(Jan 5, 2022)

    Patch release 3.4.2

    • chore: Use assertEqual instead of assertEquals for Python 3.11 compatibility (#1763) [Karthikeyan Singaravelan]
    • chore: improve code quality and balance (#1761) [Daniel Vaz Gaspar]
    Source code(tar.gz)
    Source code(zip)
  • v3.4.1(Dec 13, 2021)

    Patch release 3.4.1

    • feat: Adding role_keys into Azure OAuth (#1744) [Michael Yee]
    • docs: Fix small documentation issues (#1755) [Dosenpfand]
    • fix: 1154 Add LOGOUT_REDIRECT_URL setting (#1749) [blag]
    • fix: optional unauthorized status codes (#1753) [Daniel Vaz Gaspar]
    • docs: Fix indentation of function content (#1752) [akettmann-e24]
    • fix: optionally return HTTP 403 instead of 401 when unauthorized (#1748) [Daniel Vaz Gaspar]
    • chore: Redirect to prev url on login (#1747) [Geido]
    • docs: add aws cognito setup code examples (#1746) [Pin Jin]
    • fix: Added sr-only class to icon only links (#1727) [Thomas Stivers]
    • chore: [Deprecation] Use Markup instead of HTMLString (#1729) [Andrey Polegoshko]
    Source code(tar.gz)
    Source code(zip)
  • v3.4.0(Nov 10, 2021)

    Minor release 3.4.0

    • chore: pin down WTForms (#1735) [Daniel Vaz Gaspar]
    • fix: ModuleNotFoundError from wtforms 3.0.0 (#1733) [Ke Zhu]
    • fix: add .env for docker-compose (#1728) [Daniel Vaz Gaspar]
    • fix: OAuth login flow (#1707) [Daniel Vaz Gaspar]
    Source code(tar.gz)
    Source code(zip)
  • v3.3.4(Oct 14, 2021)

    Patch release 3.3.4

    • chore: improve tests more coverage (#1713) [Daniel Vaz Gaspar]
    • docs: fix requirements funcparserlib (#1703) [Daniel Vaz Gaspar]
    • chore: improve schema validation (#1712) [Daniel Vaz Gaspar]
    • chore: bump dependencies (#1697) [Daniel Vaz Gaspar]
    • docs: fix requirements (#1702) [Daniel Vaz Gaspar]
    • docs: fix issue 1700 (#1701) [Federico Padua]
    Source code(tar.gz)
    Source code(zip)
  • v3.3.3(Sep 14, 2021)

    Patch release 3.3.3

    • fix: related filters with bogus data (#1695) [Daniel Vaz Gaspar]
    • chore: Bump flask-openid to 1.3.0 (#1693) [Daniel Vaz Gaspar]
    • chore: bump JQuery to 3.6.0 (#1688) [Daniel Vaz Gaspar]
    • chore: bump prison version (#1689) [Beto Dealmeida]
    • feat: password complexity option on DB Auth (#1687) [Daniel Vaz Gaspar]
    • fix: check if there is an email field in userinfo (#1663) [Yoshitaka Sakurai]
    Source code(tar.gz)
    Source code(zip)
  • v3.3.2(Jul 27, 2021)

    Patch release 3.3.2

    • fix: improve next URL on OAuth (#1668) [Daniel Vaz Gaspar]
    • chore: Bump click to 8.0.1 (#1665) [Hugh A. Miles II]
    • feat(cli): Add import/export of roles with permissions (#1662) [krsnik93]
    Source code(tar.gz)
    Source code(zip)
  • v3.3.0(May 10, 2021)

    Minor release: 3.3.0

    • fix: auth balance (#1634) [Daniel Gaspar]
    • feat: Support for conditional menu item rendering (#1631) [Ben Reinhart]
    • docs: fix number of languages in i18n.rst (#1630) [Aleksandr Gordienko]
    • feat: Add support for before_request hooks (#1629) [Ben Reinhart]
    • docs: Typos and small changes in docs/templates.rst (#1625) [Federico Padua]
    Source code(tar.gz)
    Source code(zip)
  • v3.2.3(Apr 26, 2021)

    Patch release 3.2.3

    • fix: improve performance for get role permissions (#1624) [Daniel Gaspar]
    • feat: get user permissions API (#1620) [Daniel Gaspar]
    • fix: Ignore LDAP search referrals (#1602) [Fred Thomsen]
    • fix: relax AzureAD mandatory fields (#1608) [hyunjong.lee]
    Source code(tar.gz)
    Source code(zip)
  • v3.2.2(Apr 6, 2021)

  • v3.2.1(Mar 29, 2021)

    Patch release 3.2.1

    • docs: improve contributing run single test (#1579) [Daniel Vaz Gaspar]
    • fix: sqlalchemy 1.4.0 breaking changes (#1586) [Daniel Vaz Gaspar]
    Source code(tar.gz)
    Source code(zip)
  • v3.2.0(Feb 19, 2021)

    Minor release 3.2.0

    • fix: issue 1469 error in filters (#1541) [Duy Nguyen Hoang]
    • fix: showing excluded routes in server log (#1565) [runoutnow]
    • refactor: AUTH_LDAP/AUTH_OAUTH + implement role mapping (#1374) [Mathew Wicks]
    • fix(api): OpenAPI spec of nested components without auto generated names (#1547) [Daniel Vaz Gaspar]
    • fix(mvc): action confirmation on single show view (#1539) [Daniel Vaz Gaspar]
    • docs: improve docs around LDAP auth (#1526) [Daniel Vaz Gaspar]
    • ci: tests for python 3.8 and 3.9 (#1525) [Daniel Vaz Gaspar]
    • docs: fix, swagger path in readme (#1518) [Felix Rilling]
    • fix: oauth #1511 (#1522) [Daniel Vaz Gaspar]
    • fix: github actions (#1523) [Daniel Vaz Gaspar]
    • fix: changelog (#1507) [Daniel Vaz Gaspar]
    Source code(tar.gz)
    Source code(zip)
  • 3.1.1(Nov 26, 2020)

    Patch release 3.1.1

    Change log:

    • fix: MVC order by related column use alias (#1504) [Daniel Vaz Gaspar]
    • fix: remove unnecessary CSS class/styling from dropdowns (#1503) [Ryan Hamilton]
    • deps: constraint pre 1 packages following semver (#1502) [Daniel Vaz Gaspar]
    • fix: MVC order by on relation (#1500) [Daniel Vaz Gaspar]
    • docs: add github actions badge (#1501) [Daniel Vaz Gaspar]
    • fix: remove unnecessary classes from dropdowns (#1491) [Ryan Hamilton]
    • ci: migrate from travis to github actions (#1497) [Daniel Vaz Gaspar]
    • fix: lint (#1498) [Daniel Vaz Gaspar]
    • fix: Improve UX by moving drop-down caret within clickable target (#1492) [Ryan Hamilton]
    • style: use a clearer visual representation for "delete" actions (#1495) [Ryan Hamilton]
    • fix: "actions" on ModelViews with composite primary keys (#1493) [Ash Berlin-Taylor]
    • docs: migrate examples/quickhowto3 to version 3.x.x (#1488) [luizduma]
    • fix: REST API inner joins eager loading (#1486) [Daniel Vaz Gaspar]
    Source code(tar.gz)
    Source code(zip)
Owner
Daniel Vaz Gaspar
Daniel Vaz Gaspar
Swagger/OpenAPI First framework for Python on top of Flask with automatic endpoint validation & OAuth2 support

Connexion Connexion is a framework that automagically handles HTTP requests based on OpenAPI Specification (formerly known as Swagger Spec) of your AP

Zalando SE 4.2k Jan 7, 2023
Swagger/OpenAPI First framework for Python on top of Flask with automatic endpoint validation & OAuth2 support

Connexion Connexion is a framework that automagically handles HTTP requests based on OpenAPI Specification (formerly known as Swagger Spec) of your AP

Zalando SE 3.5k Feb 17, 2021
Appier is an object-oriented Python web framework built for super fast app development.

Joyful Python Web App development Appier is an object-oriented Python web framework built for super fast app development. It's as lightweight as possi

Hive Solutions 122 Dec 22, 2022
Fully featured framework for fast, easy and documented API development with Flask

Flask RestPlus IMPORTANT NOTICE: This project has been forked to Flask-RESTX and will be maintained by by the python-restx organization. Flask-RESTPlu

Axel H. 2.7k Jan 4, 2023
Fully featured framework for fast, easy and documented API development with Flask

Flask RestPlus IMPORTANT NOTICE: This project has been forked to Flask-RESTX and will be maintained by by the python-restx organization. Flask-RESTPlu

Axel H. 2.5k Feb 17, 2021
Screaming-fast Python 3.5+ HTTP toolkit integrated with pipelining HTTP server based on uvloop and picohttpparser.

Japronto! There is no new project development happening at the moment, but it's not abandoned either. Pull requests and new maintainers are welcome. I

Paweł Piotr Przeradowski 8.6k Dec 29, 2022
Flask-Potion is a RESTful API framework for Flask and SQLAlchemy, Peewee or MongoEngine

Flask-Potion Description Flask-Potion is a powerful Flask extension for building RESTful JSON APIs. Potion features include validation, model resource

DTU Biosustain 491 Dec 8, 2022
Flask-Potion is a RESTful API framework for Flask and SQLAlchemy, Peewee or MongoEngine

Flask-Potion Description Flask-Potion is a powerful Flask extension for building RESTful JSON APIs. Potion features include validation, model resource

DTU Biosustain 484 Feb 3, 2021
Flask Sugar is a web framework for building APIs with Flask, Pydantic and Python 3.6+ type hints.

Flask Sugar is a web framework for building APIs with Flask, Pydantic and Python 3.6+ type hints. check parameters and generate API documents automatically. Flask Sugar是一个基于flask,pyddantic,类型注解的API框架, 可以检查参数并自动生成API文档

null 162 Dec 26, 2022
Chisel is a light-weight Python WSGI application framework built for creating well-documented, schema-validated JSON web APIs

chisel Chisel is a light-weight Python WSGI application framework built for creating well-documented, schema-validated JSON web APIs. Here are its fea

Craig Hobbs 2 Dec 2, 2021
An effective, simple, and async security library for the Sanic framework.

Sanic Security An effective, simple, and async security library for the Sanic framework. Table of Contents About the Project Getting Started Prerequis

Sunset Dev 72 Nov 30, 2022
Online Boutique is a cloud-native microservices demo application

Online Boutique is a cloud-native microservices demo application. Online Boutique consists of a 10-tier microservices application. The application is

Matt Reider 1 Oct 22, 2021
You can use the mvc pattern in your flask application using this extension.

You can use the mvc pattern in your flask application using this extension. Installation Run the follow command to install mvc_flask: $ pip install mv

Marcus Pereira 37 Dec 17, 2022
The Modern And Developer Centric Python Web Framework. Be sure to read the documentation and join the Slack channel questions: http://slack.masoniteproject.com

NOTE: Masonite 2.3 is no longer compatible with the masonite-cli tool. Please uninstall that by running pip uninstall masonite-cli. If you do not unin

Masonite 1.9k Jan 4, 2023
Asynchronous HTTP client/server framework for asyncio and Python

Async http client/server framework Key Features Supports both client and server side of HTTP protocol. Supports both client and server Web-Sockets out

aio-libs 13.2k Jan 5, 2023
CherryPy is a pythonic, object-oriented HTTP framework. https://docs.cherrypy.org/

Welcome to the GitHub repository of CherryPy! CherryPy is a pythonic, object-oriented HTTP framework. It allows building web applications in much the

CherryPy 1.6k Dec 29, 2022
A familiar HTTP Service Framework for Python.

Responder: a familiar HTTP Service Framework for Python Powered by Starlette. That async declaration is optional. View documentation. This gets you a

Taoufik 3.6k Dec 27, 2022
Free and open source full-stack enterprise framework for agile development of secure database-driven web-based applications, written and programmable in Python.

Readme web2py is a free open source full-stack framework for rapid development of fast, scalable, secure and portable database-driven web-based applic

null 2k Dec 31, 2022
Asita is a web application framework for python based on express-js framework.

Asita is a web application framework for python. It is designed to be easy to use and be more easy for javascript users to use python frameworks because it is based on express-js framework.

Mattéo 4 Nov 16, 2021