From e09f3ca4fd1f7937fe381725d5043793f7e2fc10 Mon Sep 17 00:00:00 2001
From: BaiJiangJie <32935519+BaiJiangJie@users.noreply.github.com>
Date: Fri, 9 Nov 2018 14:54:38 +0800
Subject: [PATCH] =?UTF-8?q?[Update]=20=E6=94=AF=E6=8C=81=20OpenID=20?=
=?UTF-8?q?=E8=AE=A4=E8=AF=81=20(#2008)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* [Update] core支持openid登录,coco还不支持
* [Update] coco支持openid登录
* [Update] 修改注释
* [Update] 修改 OpenID Auth Code Backend 用户认证失败返回None, 不是Anonymoususer
* [Update] 修改OpenID Code用户认证异常捕获
* [Update] 修改OpenID Auth Middleware, check用户是否单点退出的异常捕获
* [Update] 修改config_example Auth OpenID 配置
* [Update] 登录页面添加 更多登录方式
* [Update] 重构OpenID认证架构
* [Update] 修改小细节
* [Update] OpenID用户认证成功后,更新用户来源
* [update] 添加OpenID用户登录成功日志
---
apps/authentication/__init__.py | 0
apps/authentication/admin.py | 1 +
apps/authentication/apps.py | 10 ++
apps/authentication/models.py | 1 +
apps/authentication/openid/__init__.py | 20 +++
apps/authentication/openid/backends.py | 90 +++++++++++++
apps/authentication/openid/middleware.py | 42 ++++++
apps/authentication/openid/models.py | 159 +++++++++++++++++++++++
apps/authentication/openid/tests.py | 0
apps/authentication/openid/views.py | 102 +++++++++++++++
apps/authentication/signals.py | 4 +
apps/authentication/signals_handlers.py | 33 +++++
apps/authentication/tests.py | 1 +
apps/authentication/urls/api_urls.py | 1 +
apps/authentication/urls/view_urls.py | 16 +++
apps/authentication/views.py | 1 +
apps/jumpserver/settings.py | 20 +++
apps/jumpserver/urls.py | 1 +
apps/locale/zh/LC_MESSAGES/django.mo | Bin 55705 -> 55767 bytes
apps/locale/zh/LC_MESSAGES/django.po | 54 ++++----
apps/users/models/user.py | 2 +
apps/users/templates/users/login.html | 20 ++-
apps/users/views/login.py | 4 +
config_example.py | 8 ++
24 files changed, 564 insertions(+), 26 deletions(-)
create mode 100644 apps/authentication/__init__.py
create mode 100644 apps/authentication/admin.py
create mode 100644 apps/authentication/apps.py
create mode 100644 apps/authentication/models.py
create mode 100644 apps/authentication/openid/__init__.py
create mode 100644 apps/authentication/openid/backends.py
create mode 100644 apps/authentication/openid/middleware.py
create mode 100644 apps/authentication/openid/models.py
create mode 100644 apps/authentication/openid/tests.py
create mode 100644 apps/authentication/openid/views.py
create mode 100644 apps/authentication/signals.py
create mode 100644 apps/authentication/signals_handlers.py
create mode 100644 apps/authentication/tests.py
create mode 100644 apps/authentication/urls/api_urls.py
create mode 100644 apps/authentication/urls/view_urls.py
create mode 100644 apps/authentication/views.py
diff --git a/apps/authentication/__init__.py b/apps/authentication/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/apps/authentication/admin.py b/apps/authentication/admin.py
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/apps/authentication/admin.py
@@ -0,0 +1 @@
+
diff --git a/apps/authentication/apps.py b/apps/authentication/apps.py
new file mode 100644
index 000000000..0869b64fd
--- /dev/null
+++ b/apps/authentication/apps.py
@@ -0,0 +1,10 @@
+from django.apps import AppConfig
+
+
+class AuthenticationConfig(AppConfig):
+ name = 'authentication'
+
+ def ready(self):
+ from . import signals_handlers
+ super().ready()
+
diff --git a/apps/authentication/models.py b/apps/authentication/models.py
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/apps/authentication/models.py
@@ -0,0 +1 @@
+
diff --git a/apps/authentication/openid/__init__.py b/apps/authentication/openid/__init__.py
new file mode 100644
index 000000000..bc4c753ca
--- /dev/null
+++ b/apps/authentication/openid/__init__.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+#
+
+from django.conf import settings
+from .models import Client
+
+
+def new_client():
+ """
+ :return: authentication.models.Client
+ """
+ return Client(
+ server_url=settings.AUTH_OPENID_SERVER_URL,
+ realm_name=settings.AUTH_OPENID_REALM_NAME,
+ client_id=settings.AUTH_OPENID_CLIENT_ID,
+ client_secret=settings.AUTH_OPENID_CLIENT_SECRET
+ )
+
+
+client = new_client()
diff --git a/apps/authentication/openid/backends.py b/apps/authentication/openid/backends.py
new file mode 100644
index 000000000..15a758acc
--- /dev/null
+++ b/apps/authentication/openid/backends.py
@@ -0,0 +1,90 @@
+# coding:utf-8
+#
+
+from django.contrib.auth import get_user_model
+from django.conf import settings
+
+from . import client
+from common.utils import get_logger
+from authentication.openid.models import OIDT_ACCESS_TOKEN
+
+UserModel = get_user_model()
+
+logger = get_logger(__file__)
+
+BACKEND_OPENID_AUTH_CODE = \
+ 'authentication.openid.backends.OpenIDAuthorizationCodeBackend'
+
+
+class BaseOpenIDAuthorizationBackend(object):
+
+ @staticmethod
+ def user_can_authenticate(user):
+ """
+ Reject users with is_active=False. Custom user models that don't have
+ that attribute are allowed.
+ """
+ is_active = getattr(user, 'is_active', None)
+ return is_active or is_active is None
+
+ def get_user(self, user_id):
+ try:
+ user = UserModel._default_manager.get(pk=user_id)
+ except UserModel.DoesNotExist:
+ return None
+
+ return user if self.user_can_authenticate(user) else None
+
+
+class OpenIDAuthorizationCodeBackend(BaseOpenIDAuthorizationBackend):
+
+ def authenticate(self, request, **kwargs):
+ logger.info('1.openid code backend')
+
+ code = kwargs.get('code')
+ redirect_uri = kwargs.get('redirect_uri')
+
+ if not code or not redirect_uri:
+ return None
+
+ try:
+ oidt_profile = client.update_or_create_from_code(
+ code=code,
+ redirect_uri=redirect_uri
+ )
+
+ except Exception as e:
+ logger.error(e)
+
+ else:
+ # Check openid user single logout or not with access_token
+ request.session[OIDT_ACCESS_TOKEN] = oidt_profile.access_token
+
+ user = oidt_profile.user
+
+ return user if self.user_can_authenticate(user) else None
+
+
+class OpenIDAuthorizationPasswordBackend(BaseOpenIDAuthorizationBackend):
+
+ def authenticate(self, request, username=None, password=None, **kwargs):
+ logger.info('2.openid password backend')
+
+ if not settings.AUTH_OPENID:
+ return None
+
+ elif not username:
+ return None
+
+ try:
+ oidt_profile = client.update_or_create_from_password(
+ username=username, password=password
+ )
+
+ except Exception as e:
+ logger.error(e)
+
+ else:
+ user = oidt_profile.user
+ return user if self.user_can_authenticate(user) else None
+
diff --git a/apps/authentication/openid/middleware.py b/apps/authentication/openid/middleware.py
new file mode 100644
index 000000000..128b20984
--- /dev/null
+++ b/apps/authentication/openid/middleware.py
@@ -0,0 +1,42 @@
+# coding:utf-8
+#
+
+from django.conf import settings
+from django.contrib.auth import logout
+from django.utils.deprecation import MiddlewareMixin
+from django.contrib.auth import BACKEND_SESSION_KEY
+
+from . import client
+from common.utils import get_logger
+from .backends import BACKEND_OPENID_AUTH_CODE
+from authentication.openid.models import OIDT_ACCESS_TOKEN
+
+logger = get_logger(__file__)
+
+
+class OpenIDAuthenticationMiddleware(MiddlewareMixin):
+ """
+ Check openid user single logout (with access_token)
+ """
+
+ def process_request(self, request):
+
+ # Don't need openid auth if AUTH_OPENID is False
+ if not settings.AUTH_OPENID:
+ return
+
+ # Don't need check single logout if user not authenticated
+ if not request.user.is_authenticated:
+ return
+
+ elif request.session[BACKEND_SESSION_KEY] != BACKEND_OPENID_AUTH_CODE:
+ return
+
+ # Check openid user single logout or not with access_token
+ try:
+ client.openid_connect_client.userinfo(
+ token=request.session.get(OIDT_ACCESS_TOKEN))
+
+ except Exception as e:
+ logout(request)
+ logger.error(e)
diff --git a/apps/authentication/openid/models.py b/apps/authentication/openid/models.py
new file mode 100644
index 000000000..e3c0a4842
--- /dev/null
+++ b/apps/authentication/openid/models.py
@@ -0,0 +1,159 @@
+# -*- coding: utf-8 -*-
+#
+
+from django.db import transaction
+from django.contrib.auth import get_user_model
+from keycloak.realm import KeycloakRealm
+from keycloak.keycloak_openid import KeycloakOpenID
+from ..signals import post_create_openid_user
+
+OIDT_ACCESS_TOKEN = 'oidt_access_token'
+
+
+class OpenIDTokenProfile(object):
+
+ def __init__(self, user, access_token, refresh_token):
+ """
+ :param user: User object
+ :param access_token:
+ :param refresh_token:
+ """
+ self.user = user
+ self.access_token = access_token
+ self.refresh_token = refresh_token
+
+ def __str__(self):
+ return "{}'s OpenID token profile".format(self.user.username)
+
+
+class Client(object):
+
+ def __init__(self, server_url, realm_name, client_id, client_secret):
+ self.server_url = server_url
+ self.realm_name = realm_name
+ self.client_id = client_id
+ self.client_secret = client_secret
+ self.realm = self.new_realm()
+ self.openid_client = self.new_openid_client()
+ self.openid_connect_client = self.new_openid_connect_client()
+
+ def new_realm(self):
+ """
+ :param authentication.openid.models.Realm realm:
+ :return keycloak.realm.Realm:
+ """
+ return KeycloakRealm(
+ server_url=self.server_url,
+ realm_name=self.realm_name,
+ headers={}
+ )
+
+ def new_openid_connect_client(self):
+ """
+ :rtype: keycloak.openid_connect.KeycloakOpenidConnect
+ """
+ openid_connect = self.realm.open_id_connect(
+ client_id=self.client_id,
+ client_secret=self.client_secret
+ )
+ return openid_connect
+
+ def new_openid_client(self):
+ """
+ :rtype: keycloak.keycloak_openid.KeycloakOpenID
+ """
+
+ return KeycloakOpenID(
+ server_url='%sauth/' % self.server_url,
+ realm_name=self.realm_name,
+ client_id=self.client_id,
+ client_secret_key=self.client_secret,
+ )
+
+ def update_or_create_from_password(self, username, password):
+ """
+ Update or create an user based on an authentication username and password.
+
+ :param str username: authentication username
+ :param str password: authentication password
+ :return: authentication.models.OpenIDTokenProfile
+ """
+ token_response = self.openid_client.token(
+ username=username, password=password
+ )
+
+ return self._update_or_create(token_response=token_response)
+
+ def update_or_create_from_code(self, code, redirect_uri):
+ """
+ Update or create an user based on an authentication code.
+ Response as specified in:
+
+ https://tools.ietf.org/html/rfc6749#section-4.1.4
+
+ :param str code: authentication code
+ :param str redirect_uri:
+ :rtype: authentication.models.OpenIDTokenProfile
+ """
+
+ token_response = self.openid_connect_client.authorization_code(
+ code=code, redirect_uri=redirect_uri)
+
+ return self._update_or_create(token_response=token_response)
+
+ def _update_or_create(self, token_response):
+ """
+ Update or create an user based on a token response.
+
+ `token_response` contains the items returned by the OpenIDConnect Token API
+ end-point:
+ - id_token
+ - access_token
+ - expires_in
+ - refresh_token
+ - refresh_expires_in
+
+ :param dict token_response:
+ :rtype: authentication.openid.models.OpenIDTokenProfile
+ """
+
+ userinfo = self.openid_connect_client.userinfo(
+ token=token_response['access_token'])
+
+ with transaction.atomic():
+ user, _ = get_user_model().objects.update_or_create(
+ username=userinfo.get('preferred_username', ''),
+ defaults={
+ 'email': userinfo.get('email', ''),
+ 'first_name': userinfo.get('given_name', ''),
+ 'last_name': userinfo.get('family_name', '')
+ }
+ )
+
+ oidt_profile = OpenIDTokenProfile(
+ user=user,
+ access_token=token_response['access_token'],
+ refresh_token=token_response['refresh_token'],
+ )
+
+ if user:
+ post_create_openid_user.send(sender=user.__class__, user=user)
+
+ return oidt_profile
+
+ def __str__(self):
+ return self.client_id
+
+
+class Nonce(object):
+ """
+ The openid-login is stored in cache as a temporary object, recording the
+ user's redirect_uri and next_pat
+ """
+
+ def __init__(self, redirect_uri, next_path):
+ import uuid
+ self.state = uuid.uuid4()
+ self.redirect_uri = redirect_uri
+ self.next_path = next_path
+
diff --git a/apps/authentication/openid/tests.py b/apps/authentication/openid/tests.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/apps/authentication/openid/views.py b/apps/authentication/openid/views.py
new file mode 100644
index 000000000..9aeb0bf7b
--- /dev/null
+++ b/apps/authentication/openid/views.py
@@ -0,0 +1,102 @@
+# -*- coding: utf-8 -*-
+#
+
+import logging
+
+from django.urls import reverse
+from django.conf import settings
+from django.core.cache import cache
+from django.views.generic.base import RedirectView
+from django.contrib.auth import authenticate, login
+from django.http.response import (
+ HttpResponseBadRequest,
+ HttpResponseServerError,
+ HttpResponseRedirect
+)
+
+from . import client
+from .models import Nonce
+from users.models import LoginLog
+from users.tasks import write_login_log_async
+from common.utils import get_request_ip
+
+logger = logging.getLogger(__name__)
+
+
+def get_base_site_url():
+ return settings.BASE_SITE_URL
+
+
+class LoginView(RedirectView):
+
+ def get_redirect_url(self, *args, **kwargs):
+ nonce = Nonce(
+ redirect_uri=get_base_site_url() + reverse(
+ "authentication:openid-login-complete"),
+
+ next_path=self.request.GET.get('next')
+ )
+
+ cache.set(str(nonce.state), nonce, 24*3600)
+
+ self.request.session['openid_state'] = str(nonce.state)
+
+ authorization_url = client.openid_connect_client.\
+ authorization_url(
+ redirect_uri=nonce.redirect_uri, scope='code',
+ state=str(nonce.state)
+ )
+
+ return authorization_url
+
+
+class LoginCompleteView(RedirectView):
+
+ def get(self, request, *args, **kwargs):
+ if 'error' in request.GET:
+ return HttpResponseServerError(self.request.GET['error'])
+
+ if 'code' not in self.request.GET and 'state' not in self.request.GET:
+ return HttpResponseBadRequest()
+
+ if self.request.GET['state'] != self.request.session['openid_state']:
+ return HttpResponseBadRequest()
+
+ nonce = cache.get(self.request.GET['state'])
+
+ if not nonce:
+ return HttpResponseBadRequest()
+
+ user = authenticate(
+ request=self.request,
+ code=self.request.GET['code'],
+ redirect_uri=nonce.redirect_uri
+ )
+
+ cache.delete(str(nonce.state))
+
+ if not user:
+ return HttpResponseBadRequest()
+
+ login(self.request, user)
+
+ data = {
+ 'username': user.username,
+ 'mfa': int(user.otp_enabled),
+ 'reason': LoginLog.REASON_NOTHING,
+ 'status': True
+ }
+ self.write_login_log(data)
+
+ return HttpResponseRedirect(nonce.next_path or '/')
+
+ def write_login_log(self, data):
+ login_ip = get_request_ip(self.request)
+ user_agent = self.request.META.get('HTTP_USER_AGENT', '')
+ tmp_data = {
+ 'ip': login_ip,
+ 'type': 'W',
+ 'user_agent': user_agent
+ }
+ data.update(tmp_data)
+ write_login_log_async.delay(**data)
diff --git a/apps/authentication/signals.py b/apps/authentication/signals.py
new file mode 100644
index 000000000..f33a3b821
--- /dev/null
+++ b/apps/authentication/signals.py
@@ -0,0 +1,4 @@
+from django.dispatch import Signal
+
+
+post_create_openid_user = Signal(providing_args=('user',))
diff --git a/apps/authentication/signals_handlers.py b/apps/authentication/signals_handlers.py
new file mode 100644
index 000000000..7cf240386
--- /dev/null
+++ b/apps/authentication/signals_handlers.py
@@ -0,0 +1,33 @@
+from django.http.request import QueryDict
+from django.contrib.auth.signals import user_logged_out
+from django.dispatch import receiver
+from django.conf import settings
+from .openid import client
+from .signals import post_create_openid_user
+
+
+@receiver(user_logged_out)
+def on_user_logged_out(sender, request, user, **kwargs):
+ if not settings.AUTH_OPENID:
+ return
+
+ query = QueryDict('', mutable=True)
+ query.update({
+ 'redirect_uri': settings.BASE_SITE_URL
+ })
+
+ openid_logout_url = "%s?%s" % (
+ client.openid_connect_client.get_url(
+ name='end_session_endpoint'),
+ query.urlencode()
+ )
+
+ request.COOKIES['next'] = openid_logout_url
+
+
+@receiver(post_create_openid_user)
+def on_post_create_openid_user(sender, user=None, **kwargs):
+ if user and user.username != 'admin':
+ user.source = user.SOURCE_OPENID
+ user.save()
+
diff --git a/apps/authentication/tests.py b/apps/authentication/tests.py
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/apps/authentication/tests.py
@@ -0,0 +1 @@
+
diff --git a/apps/authentication/urls/api_urls.py b/apps/authentication/urls/api_urls.py
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/apps/authentication/urls/api_urls.py
@@ -0,0 +1 @@
+
diff --git a/apps/authentication/urls/view_urls.py b/apps/authentication/urls/view_urls.py
new file mode 100644
index 000000000..4d4e6753a
--- /dev/null
+++ b/apps/authentication/urls/view_urls.py
@@ -0,0 +1,16 @@
+# coding:utf-8
+#
+
+from django.urls import path
+from authentication.openid import views
+
+app_name = 'authentication'
+
+urlpatterns = [
+ # openid
+ path('openid/login/', views.LoginView.as_view(), name='openid-login'),
+ path('openid/login/complete/', views.LoginCompleteView.as_view(),
+ name='openid-login-complete'),
+
+ # other
+]
diff --git a/apps/authentication/views.py b/apps/authentication/views.py
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/apps/authentication/views.py
@@ -0,0 +1 @@
+
diff --git a/apps/jumpserver/settings.py b/apps/jumpserver/settings.py
index 6635b35e6..212878386 100644
--- a/apps/jumpserver/settings.py
+++ b/apps/jumpserver/settings.py
@@ -64,6 +64,7 @@ INSTALLED_APPS = [
'common.apps.CommonConfig',
'terminal.apps.TerminalConfig',
'audits.apps.AuditsConfig',
+ 'authentication.apps.AuthenticationConfig', # authentication
'rest_framework',
'rest_framework_swagger',
'drf_yasg',
@@ -94,6 +95,7 @@ MIDDLEWARE = [
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
+ 'authentication.openid.middleware.OpenIDAuthenticationMiddleware', # openid
'jumpserver.middleware.TimezoneMiddleware',
'jumpserver.middleware.DemoMiddleware',
'jumpserver.middleware.RequestMiddleware',
@@ -389,6 +391,24 @@ AUTH_LDAP_BACKEND = 'django_auth_ldap.backend.LDAPBackend'
if AUTH_LDAP:
AUTHENTICATION_BACKENDS.insert(0, AUTH_LDAP_BACKEND)
+# openid
+# Auth OpenID settings
+BASE_SITE_URL = CONFIG.BASE_SITE_URL
+AUTH_OPENID = CONFIG.AUTH_OPENID
+AUTH_OPENID_SERVER_URL = CONFIG.AUTH_OPENID_SERVER_URL
+AUTH_OPENID_REALM_NAME = CONFIG.AUTH_OPENID_REALM_NAME
+AUTH_OPENID_CLIENT_ID = CONFIG.AUTH_OPENID_CLIENT_ID
+AUTH_OPENID_CLIENT_SECRET = CONFIG.AUTH_OPENID_CLIENT_SECRET
+AUTH_OPENID_BACKENDS = [
+ 'authentication.openid.backends.OpenIDAuthorizationPasswordBackend',
+ 'authentication.openid.backends.OpenIDAuthorizationCodeBackend',
+]
+
+if AUTH_OPENID:
+ LOGIN_URL = reverse_lazy("authentication:openid-login")
+ AUTHENTICATION_BACKENDS.insert(0, AUTH_OPENID_BACKENDS[0])
+ AUTHENTICATION_BACKENDS.insert(0, AUTH_OPENID_BACKENDS[1])
+
# Celery using redis as broker
CELERY_BROKER_URL = 'redis://:%(password)s@%(host)s:%(port)s/%(db)s' % {
'password': CONFIG.REDIS_PASSWORD if CONFIG.REDIS_PASSWORD else '',
diff --git a/apps/jumpserver/urls.py b/apps/jumpserver/urls.py
index 22351e509..2319d81e5 100644
--- a/apps/jumpserver/urls.py
+++ b/apps/jumpserver/urls.py
@@ -75,6 +75,7 @@ app_view_patterns = [
path('ops/', include('ops.urls.view_urls', namespace='ops')),
path('audits/', include('audits.urls.view_urls', namespace='audits')),
path('orgs/', include('orgs.urls.views_urls', namespace='orgs')),
+ path('auth/', include('authentication.urls.view_urls'), name='auth'),
]
if settings.XPACK_ENABLED:
diff --git a/apps/locale/zh/LC_MESSAGES/django.mo b/apps/locale/zh/LC_MESSAGES/django.mo
index 9f41c1d67939c0a96cc3a11a618c509fd2a70610..bb3a0102676cdcc8f6fff601e97337378be1ec37 100644
GIT binary patch
delta 17218
zcmZA82b@jU+Q;#2X3Q|kjL~};ZA2$(q9r;(^dZq^f?$XeBr#hTCDDmal<0{zq6g7i
zf)EiUN=TxGM3j*G`=9m9`|)}A=Uu+*c~;$P?{g0KzIWD!;IkWo{fki{(><=-!Jd~3
zL$Z5bkr2B%`-%7zZ7cCHxx*M9#Pd(gbFNQfjdg5{KhxMB
zdtq$~zf*dV^m}tfF;NThdo7Wkw)d#-Aou2qqf&u>t1uRIJ*7RGl7{+U_>ND*cT^@|
zc}!2k&(^s(v95P1W2mpib+mP%d~Iz5)PZY_jrp7WR^pGWJ
{% trans "More login options" %}
+diff --git a/apps/users/views/login.py b/apps/users/views/login.py index 4f2308d04..971b1cf2d 100644 --- a/apps/users/views/login.py +++ b/apps/users/views/login.py @@ -132,6 +132,7 @@ class UserLoginView(FormView): def get_context_data(self, **kwargs): context = { 'demo_mode': os.environ.get("DEMO_MODE"), + 'AUTH_OPENID': settings.AUTH_OPENID, } kwargs.update(context) return super().get_context_data(**kwargs) @@ -200,6 +201,9 @@ class UserLogoutView(TemplateView): def get(self, request, *args, **kwargs): auth_logout(request) + next_uri = request.COOKIES.get("next") + if next_uri: + return redirect(next_uri) response = super().get(request, *args, **kwargs) return response diff --git a/config_example.py b/config_example.py index a96f0d7c9..d0fc4bff9 100644 --- a/config_example.py +++ b/config_example.py @@ -54,6 +54,14 @@ class Config: REDIS_DB_CELERY = os.environ.get('REDIS_DB') or 3 REDIS_DB_CACHE = os.environ.get('REDIS_DB') or 4 + # Use OpenID authorization + # BASE_SITE_URL = 'http://localhost:8080' + # AUTH_OPENID = False # True or False + # AUTH_OPENID_SERVER_URL = 'https://openid-auth-server.com/' + # AUTH_OPENID_REALM_NAME = 'realm-name' + # AUTH_OPENID_CLIENT_ID = 'client-id' + # AUTH_OPENID_CLIENT_SECRET = 'client-secret' + def __init__(self): pass