Giter Site home page Giter Site logo

ministryofjustice / fab-oidc Goto Github PK

View Code? Open in Web Editor NEW
27.0 11.0 24.0 15 KB

Flask-AppBuilder SecurityManager for OpenIDConnect

License: MIT License

Python 100.00%
airflow airflow-authentication oidc openidconnect analytical-platform analytics-platform

fab-oidc's Introduction

Flask-AppBuilder SecurityManager for OpenIDConnect

Wrapper for flask_oidc that exposes a SecurityManager for use with any Flask-AppBuilder app.

It will allow your users to login with OpenIDConnect providers such as Auth0, Okta or Google Apps.

This is roughly inspired by the code in this stackoverflow answer. (MIT Licenced © thijsfranck)

Usage

Generic

Just override the default security manager in your Flask Appbuilder app.

from fab_oidc.security import OIDCSecurityManager

appbuilder = AppBuilder(app, db.session, security_manager_class=OIDCSecurityManager)

Airflow provides a hook in the webserver_config.py file where you can specify a security manager class. In webserver_config.py import the OIDCSecurityManager and set

from fab_oidc.security import AirflowOIDCSecurityManager
...
SECURITY_MANAGER_CLASS = AirflowOIDCSecurityManager

Airflow now requires that your SECURITY_MANAGER_CLASS is a subclass of AirflowSecurityManager. Use the special AirflowOIDCSecurityManager that is only defined if you're using this library alongside Airflow.

Superset works in a a similar way. Just as in Airflow, SECURITY_MANAGER_CLASS needs to be a subclass of SupersetSecurityManager the config is in a file called superset_config.py and the hook is called CUSTOM_SECURITY_MANAGER. There now exists a special SupersetOIDCSecurityManager that is only defined if you are using this library alongside Superset.

from fab_oidc.security import SupersetOIDCSecurityManager
...
CUSTOM_SECURITY_MANAGER = SupersetOIDCSecurityManager

Settings

The settings are the same as the flask_oidc settings, so look there for a reference.

if you're happy with flask_oidc's defaults the only thing you'll really need is something like:

OIDC_CLIENT_SECRETS = '/path/to/client_secret.json'

see the flask_oidc manual client registration docs for how to generate or write one.

OIDC Field configuration

If you like to change the default OIDC field that will be used as a username, first name and last name you can set the following env var in the shell you run your process:

export USERNAME_OIDC_FIELD='preferred_username'
export FIRST_NAME_OIDC_FIELD='given_name'
export LAST_NAME_OIDC_FIELD='family_name'

Copyright © 2018 HM Government (Ministry of Justice Digital Services). See LICENSE.txt for further details.

fab-oidc's People

Contributors

karlkerem avatar mrshu avatar nielsdenissen avatar r4vi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fab-oidc's Issues

App on intranet with Google login

Hi,
Is there any way to get FAB-oidc login from behind NAT?
I'd like to deploy an app on the intranet, without external domain name. A FQDN is needed for redirect_uri in Google Oauth settings.

By setting the 'OVERWRITE_REDIRECT_URI' to something fake (e.g. app.localdomain.com) the auth flow can be completed, but then the next step is a redirection from FAB to that URI. That, naturally, fails.

I couldn't find the spot where this redirection is done to override it...

Any clues? Thanks!

Question: Redirect loop between /login / and OIDC-Auth-Endpoint

Thanks for providing this nice component!

I struggle doing the configuration right and highly appreciate your support.

I end up in a redirect loop between the following resources in the mentioned order:

1. <airflow>/login
2. <OIDC/Keycloak>/auth/realms/airflow/protocol/openid-connect/auth
3. <airflow>/oidc_callback (sets the cookie: oidc_id_token)
4. <airflow>/login
5. <OIDC/Keycloak>/auth/realms/airflow/protocol/openid-connect/auth
6. <airflow>/oidc_callback
7...

My configuration is as follows:
airflow runs locally on http://localhost:8080
i use your image: quay.io/mojanalytics/airflow:1.10.3

webserver_config.py
[...]
AUTH_TYPE = AUTH_OID
AUTH_ROLE_ADMIN = 'Admin'
AUTH_USER_REGISTRATION = True
AUTH_USER_REGISTRATION_ROLE = "Admin"

OIDC_CLIENT_SECRETS = '/etc/airflow/client-configuration.json'
SECURITY_MANAGER_CLASS = AirflowOIDCSecurityManager
OIDC_USER_INFO_ENABLED = True
OIDC_SCOPES = ['openid', 'airflow']
OIDC_LOGOUT_URI = 'https://<domain>/auth/realms/airflow/protocol/openid-connect/logout?client_id=airflow&returnTo='
OIDC_CLOCK_SKEW: 560
OIDC_RESOURCE_CHECK_AUD: True
OIDC_INTROSPECTION_AUTH_METHOD: 'client_secret_post'

client-configuration.json
{
	"web": {
		"client_id": "airflow",
		"client_secret": "SECRET",
		"auth_uri": "https://<domain>/auth/realms/airflow/protocol/openid-connect/auth",
		"token_uri": "https://<domain>/auth/realms/airflow/protocol/openid-connect/token",
		"userinfo_uri": "https://<domain>/auth/realms/airflow/protocol/openid-connect/userinfo",
		"issuer": "https://<domain>/auth/realms/airflow",
		"redirect_uris": [
			"http://localhost:8080/*"
		]
	}
}

env vars for airflow. 
Through the scope 'airflow', those attributes are put into access- & identify-token. I checked that.
export USERNAME_OIDC_FIELD="preferred_username"
export FIRST_NAME_OIDC_FIELD="nickname"
export LAST_NAME_OIDC_FIELD="name"

By modifying views.py, I find out, that handle_login seems not to be invoked.
At least added logger-invocations do not create logs:

def handle_login():
   log.info("start handle login")

Do you have a hint what to check?

unable to retrieve the family_name and given_name from Okta

I try to setup airflow cluster to use Okta as authentication server.

client_secrets.json

{
  "web": {
    "client_id": "{{  CLIENT_ID }}",
    "client_secret": "{{ CLIENT_SECRET }}",
    "auth_uri": "https://{{ ORG_NAME }}.okta.com/oauth2/default/v1/authorize",
    "token_uri": "https://{{ ORG_NAME }}.okta.com/oauth2/default/v1/token",
    "issuer": "https://{{ ORG_NAME }}.okta.com/oauth2/default",
    "userinfo_uri": "https://{{ ORG_NAME }}.okta.com/oauth2/default/userinfo",
    "redirect_uris": [
      "http://localhost:8080/oidc/callback"
    ]
  }
}

webserver_config.py

SECURITY_MANAGER_CLASS = AirflowOIDCSecurityManager
OIDC_CLIENT_SECRETS = './airflow/client_secrets.json'
OIDC_COOKIE_SECURE = False
OIDC_USER_INFO_ENABLED = True

OIDC_CALLBACK_ROUTE = "/oidc/callback"
OIDC_SCOPES = ["openid", "profile", "email"]
OIDC_ID_TOKEN_COOKIE_NAME = "oidc_token"
OIDC_CLOCK_SKEW: 560
OIDC_RESOURCE_CHECK_AUD: True
OIDC_INTROSPECTION_AUTH_METHOD: 'client_secret_post'
$ export USERNAME_OIDC_FIELD="preferred_username"
$ export FIRST_NAME_OIDC_FIELD="given_name"
$ export LAST_NAME_OIDC_FIELD="name"

$ airflow webserver -p 8080

However, after login via Okta, It redirects to airflow url and returns error
airflow webserver log:

ERROR - Error adding new user to database. (sqlite3.IntegrityError) NOT NULL constraint failed: ab_user.first_name
[SQL: INSERT INTO ab_user (first_name, last_name, username, password, active, email, last_login, login_count, fail_login_count, created_on, changed_on, created_by_fk, changed_by_fk) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)]
[parameters: (None, 'Calvin P', '[email protected]', 'pbkdf2:sha256:150000$WJD65iwu$aa4b0deea85e841467441cc18ab8d007a22621af4bee1c2e8f0653467af434f0', 1, '[email protected]', None, None, None, '2020-07-27 23:16:50.722603', '2020-07-27 23:16:50.722867', None, None)]
(Background on this error at: http://sqlalche.me/e/gkpj)

If I understand it correctly, export LAST_NAME_OIDC_FIELD="name" is worked correctly, but FIRST_NAME_OIDC_FIELD="given_name" returns None
May I know How can I fix this issue?

Expectation:

  • able to retrieve the family_name and given_name from Okta to be able to create the users properly in airflow.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.