I have started using Apache Airflow (Built upon FAB) and enabled authentication through OAuth (as shown in FAB Security). I have ONLY one OAUTH_PROVIDER (azure).
FYI, Airflow version 2.1.4
When I launch my airflow home page, it used to open the direct login page of my OAUTH_PROVIDER.
NOW, the real problem started when I upgraded my airflow to 2.2.4 AND configured the same OAUTH (Azure) provider.
When I launch my airflow home page, a page coming like this
After clicking the button "Sign In with azure", the user login page comes.
Compared to the older airflow, the latest version got an extra page.
Why is matter to me?
We are rendering airflow in a web app and this extra "sign in with" page does not look good.
Please provide some info on SKIPPING that extra interaction.
After upgrading Airflow, Flask Appbuilder version was probably also bumped and that caused change in behavior. Basically:
Flask Appbuilder < 3.4.0
made it possible to have automatic sign-in when just one oauth provider was configuredFlask Appbuilder >= 3.4.0
changed the behavior and made it impossible to achieve this. This is the PR (with justification) that removed this functionality: https://github.com/dpgaspar/Flask-AppBuilder/pull/1707If you want previous behavior to be used in your deployment, this is what most likely would work (although I didn't test it):
CustomAuth0AuthView
- it would bring back old behavior on login
method. (I used v4.1.3 as reference code and modified it slightly).webserver_config.py
:
from flask_appbuilder.security.views import AuthOAuthView
class CustomAuthOAuthView(AuthOAuthView):
@expose("/login/")
@expose("/login/<provider>")
@expose("/login/<provider>/<register>")
def login(self, provider: Optional[str] = None) -> WerkzeugResponse:
log.debug("Provider: {0}".format(provider))
if g.user is not None and g.user.is_authenticated:
log.debug("Already authenticated {0}".format(g.user))
return redirect(self.appbuilder.get_url_for_index)
if provider is None:
if len(self.appbuilder.sm.oauth_providers) > 1:
return self.render_template(
self.login_template,
providers=self.appbuilder.sm.oauth_providers,
title=self.title,
appbuilder=self.appbuilder,
)
else:
provider = self.appbuilder.sm.oauth_providers[0]["name"]
log.debug("Going to call authorize for: {0}".format(provider))
state = jwt.encode(
request.args.to_dict(flat=False),
self.appbuilder.app.config["SECRET_KEY"],
algorithm="HS256",
)
try:
if provider == "twitter":
return self.appbuilder.sm.oauth_remotes[provider].authorize_redirect(
redirect_uri=url_for(
".oauth_authorized",
provider=provider,
_external=True,
state=state,
)
)
else:
return self.appbuilder.sm.oauth_remotes[provider].authorize_redirect(
redirect_uri=url_for(
".oauth_authorized", provider=provider, _external=True
),
state=state.decode("ascii") if isinstance(state, bytes) else state,
)
except Exception as e:
log.error("Error on OAuth authorize: {0}".format(e))
flash(as_unicode(self.invalid_login_message), "warning")
return redirect(self.appbuilder.get_url_for_index)
CustomSecurityManager
. It would use your custom view to handle login.webserver_config.py
:
from airflow.www.security import AirflowSecurityManager
class CustomSecurityManager(AirflowSecurityManager):
authoidview = CustomAuthOAuthView
CustomSecurityManager
webserver_config.py
:
SECURITY_MANAGER_CLASS = CustomSecurityManager