From 396ce14b9f5b9bbdef12a72bd0dc91be5766a00a Mon Sep 17 00:00:00 2001 From: Chris Pritchard Date: Sun, 21 Oct 2018 23:38:12 +0100 Subject: [PATCH] OIDC (#1) Implemented OIDC using authlib --- app/__init__.py | 2 + app/models.py | 7 ++ app/oauth.py | 35 ++++++- .../admin_setting_authentication.html | 94 ++++++++++++++++++- app/templates/login.html | 7 +- app/views.py | 48 +++++++++- requirements.txt | 3 +- run.py | 2 +- 8 files changed, 189 insertions(+), 9 deletions(-) diff --git a/app/__init__.py b/app/__init__.py index 00c510c..fe9004b 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -4,6 +4,7 @@ from flask_login import LoginManager from flask_sqlalchemy import SQLAlchemy as SA from flask_migrate import Migrate from flask_oauthlib.client import OAuth +from authlib.flask.client import OAuth as AuthlibOAuth from sqlalchemy.exc import OperationalError # subclass SQLAlchemy to enable pool_pre_ping @@ -30,6 +31,7 @@ login_manager.init_app(app) db = SQLAlchemy(app) # database migrate = Migrate(app, db) # flask-migrate oauth_client = OAuth(app) # oauth +authlib_oauth_client = AuthlibOAuth(app) # authlib oauth if app.config.get('SAML_ENABLED') and app.config.get('SAML_ENCRYPT'): from app.lib import certutil diff --git a/app/models.py b/app/models.py index 2710080..c2306f8 100644 --- a/app/models.py +++ b/app/models.py @@ -1840,6 +1840,13 @@ class Setting(db.Model): 'google_token_params': {'scope': 'email profile'}, 'google_authorize_url':'https://accounts.google.com/o/oauth2/auth', 'google_base_url':'https://www.googleapis.com/oauth2/v1/', + 'oidc_oauth_enabled': False, + 'oidc_oauth_key': '', + 'oidc_oauth_secret': '', + 'oidc_oauth_scope': 'email', + 'oidc_oauth_api_url': '', + 'oidc_oauth_token_url': '', + 'oidc_oauth_authorize_url': '', 'forward_records_allow_edit': {'A': True, 'AAAA': True, 'AFSDB': False, 'ALIAS': False, 'CAA': True, 'CERT': False, 'CDNSKEY': False, 'CDS': False, 'CNAME': True, 'DNSKEY': False, 'DNAME': False, 'DS': False, 'HINFO': False, 'KEY': False, 'LOC': True, 'MX': True, 'NAPTR': False, 'NS': True, 'NSEC': False, 'NSEC3': False, 'NSEC3PARAM': False, 'OPENPGPKEY': False, 'PTR': True, 'RP': False, 'RRSIG': False, 'SOA': False, 'SPF': True, 'SSHFP': False, 'SRV': True, 'TKEY': False, 'TSIG': False, 'TLSA': False, 'SMIMEA': False, 'TXT': True, 'URI': False}, 'reverse_records_allow_edit': {'A': False, 'AAAA': False, 'AFSDB': False, 'ALIAS': False, 'CAA': False, 'CERT': False, 'CDNSKEY': False, 'CDS': False, 'CNAME': False, 'DNSKEY': False, 'DNAME': False, 'DS': False, 'HINFO': False, 'KEY': False, 'LOC': True, 'MX': False, 'NAPTR': False, 'NS': True, 'NSEC': False, 'NSEC3': False, 'NSEC3PARAM': False, 'OPENPGPKEY': False, 'PTR': True, 'RP': False, 'RRSIG': False, 'SOA': False, 'SPF': False, 'SSHFP': False, 'SRV': False, 'TKEY': False, 'TSIG': False, 'TLSA': False, 'SMIMEA': False, 'TXT': True, 'URI': False}, } diff --git a/app/oauth.py b/app/oauth.py index 17fd045..bb8e7a9 100644 --- a/app/oauth.py +++ b/app/oauth.py @@ -1,7 +1,7 @@ from ast import literal_eval from flask import request, session, redirect, url_for -from app import app, oauth_client +from app import app, oauth_client, authlib_oauth_client from app.models import Setting # TODO: @@ -75,3 +75,36 @@ def google_oauth(): return session.get('google_token') return google + +def oidc_oauth(): + if not Setting().get('oidc_oauth_enabled'): + return None + + def fetch_oidc_token(): + return session.get('oidc_token') + + oidc = authlib_oauth_client.register( + 'oidc', + client_id = Setting().get('oidc_oauth_key'), + client_secret = Setting().get('oidc_oauth_secret'), + api_base_url = Setting().get('oidc_oauth_api_url'), + request_token_url = None, + access_token_url = Setting().get('oidc_oauth_token_url'), + authorize_url = Setting().get('oidc_oauth_authorize_url'), + client_kwargs={'scope': Setting().get('oidc_oauth_scope')}, + fetch_token=fetch_oidc_token, + ) + + @app.route('/oidc/authorized') + def oidc_authorized(): + session['oidc_oauthredir'] = url_for('.oidc_authorized', _external=True) + token = oidc.authorize_access_token() + if token is None: + return 'Access denied: reason=%s error=%s' % ( + request.args['error'], + request.args['error_description'] + ) + session['oidc_token'] = (token) + return redirect(url_for('.login')) + + return oidc \ No newline at end of file diff --git a/app/templates/admin_setting_authentication.html b/app/templates/admin_setting_authentication.html index 87c06a2..605f3de 100644 --- a/app/templates/admin_setting_authentication.html +++ b/app/templates/admin_setting_authentication.html @@ -37,6 +37,7 @@
  • LDAP
  • Google OAuth
  • Github OAuth
  • +
  • OpenID Connect OAuth
  • @@ -325,8 +326,63 @@ Help

    Fill in all the fields in the left form.

    +
    + +
    +
    +
    +
    + +
    + GENERAL +
    + + +
    +
    + + + +
    +
    + + + +
    +
    +
    + ADVANCE +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    +
    + +
    +
    +
    +
    + Help +

    Fill in all the fields in the left form.

    +
    -
    @@ -487,9 +543,8 @@ $('#github_oauth_authorize_url').prop('required', false); } }); - // init validation requirement at first time page load - {% if SETTING.get('google_oauth_enabled') %} + {% if SETTING.get('github_oauth_enabled') %} $('#github_oauth_key').prop('required', true); $('#github_oauth_secret').prop('required', true); $('#github_oauth_scope').prop('required', true); @@ -499,5 +554,38 @@ {% endif %} // END: Github tab js + // START: OIDC tab js + $('#oidc_oauth_enabled').iCheck({ + checkboxClass : 'icheckbox_square-blue', + increaseArea : '20%' + }).on('ifChanged', function(e) { + var is_enabled = e.currentTarget.checked; + if (is_enabled){ + $('#oidc_oauth_key').prop('required', true); + $('#oidc_oauth_secret').prop('required', true); + $('#oidc_oauth_scope').prop('required', true); + $('#oidc_oauth_api_url').prop('required', true); + $('#oidc_oauth_token_url').prop('required', true); + $('#oidc_oauth_authorize_url').prop('required', true); + } else { + $('#oidc_oauth_key').prop('required', false); + $('#oidc_oauth_secret').prop('required', false); + $('#oidc_oauth_scope').prop('required', false); + $('#oidc_oauth_api_url').prop('required', false); + $('#oidc_oauth_token_url').prop('required', false); + $('#oidc_oauth_authorize_url').prop('required', false); + } + }); + // init validation requirement at first time page load + {% if SETTING.get('oidc_oauth_enabled') %} + $('#oidc_oauth_key').prop('required', true); + $('#oidc_oauth_secret').prop('required', true); + $('#oidc_oauth_scope').prop('required', true); + $('#oidc_oauth_api_url').prop('required', true); + $('#oidc_oauth_token_url').prop('required', true); + $('#oidc_oauth_authorize_url').prop('required', true); + {% endif %} + //END: OIDC Tab JS + {% endblock %} diff --git a/app/templates/login.html b/app/templates/login.html index 54c24bc..46ae8c0 100644 --- a/app/templates/login.html +++ b/app/templates/login.html @@ -83,14 +83,17 @@ - {% if SETTING.get('google_oauth_enabled') or SETTING.get('github_oauth_enabled') %} + {% if SETTING.get('google_oauth_enabled') or SETTING.get('github_oauth_enabled') or SETTING.get('oidc_oauth_enabled') %}