mirror of
https://github.com/YunoHost-Apps/pyinventory_ynh.git
synced 2024-09-03 20:16:09 +02:00
Authenticate via SSO and nginx 'HTTP_REMOTE_USER' header
This commit is contained in:
parent
473d508cc9
commit
3b8b01f73f
12 changed files with 281 additions and 107 deletions
11
README.md
11
README.md
|
@ -26,9 +26,16 @@ You can edit the file `$final_path/local_settings.py` to enable or disable featu
|
||||||
|
|
||||||
# Miscellaneous
|
# Miscellaneous
|
||||||
|
|
||||||
## LDAP connection
|
|
||||||
|
|
||||||
Supported by https://github.com/django-auth-ldap/django-auth-ldap
|
## SSO authentication
|
||||||
|
|
||||||
|
[SSOwat](https://github.com/YunoHost/SSOwat) is fully supported:
|
||||||
|
|
||||||
|
* First user (`$YNH_APP_ARG_ADMIN`) will be created as Django's super user
|
||||||
|
* All new users will be created as normal users
|
||||||
|
* Login via SSO is fully supported
|
||||||
|
* User Email, First / Last name will be updated from SSO data
|
||||||
|
|
||||||
|
|
||||||
## Links
|
## Links
|
||||||
|
|
||||||
|
|
|
@ -24,12 +24,15 @@ def main():
|
||||||
|
|
||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
super_user = User.objects.filter(username=username).first()
|
user = User.objects.filter(username=username).first()
|
||||||
if super_user:
|
if user:
|
||||||
print('Update existing super user and set his password.', file=sys.stderr)
|
print('Update existing user and set his password.', file=sys.stderr)
|
||||||
super_user.set_password(password)
|
user.is_active = True
|
||||||
super_user.email=email
|
user.is_staff = True
|
||||||
super_user.save()
|
user.is_superuser = True
|
||||||
|
user.set_password(password)
|
||||||
|
user.email = email
|
||||||
|
user.save()
|
||||||
else:
|
else:
|
||||||
print('Create new super user', file=sys.stderr)
|
print('Create new super user', file=sys.stderr)
|
||||||
User.objects.create_superuser(
|
User.objects.create_superuser(
|
||||||
|
|
|
@ -31,7 +31,4 @@ location / {
|
||||||
proxy_redirect off;
|
proxy_redirect off;
|
||||||
|
|
||||||
proxy_pass http://127.0.0.1:__PORT__/;
|
proxy_pass http://127.0.0.1:__PORT__/;
|
||||||
|
|
||||||
# Include SSOWAT user panel.
|
|
||||||
#include conf.d/yunohost_panel.conf.inc;
|
|
||||||
}
|
}
|
||||||
|
|
185
conf/ynh_authenticate.py
Normal file
185
conf/ynh_authenticate.py
Normal file
|
@ -0,0 +1,185 @@
|
||||||
|
"""
|
||||||
|
* remote user authentication backend
|
||||||
|
* remote user middleware
|
||||||
|
|
||||||
|
Note: SSOwat/nginx add authentication headers:
|
||||||
|
|
||||||
|
'HTTP_AUTHORIZATION': 'Basic XXXXXXXXXXXXXXXX='
|
||||||
|
'HTTP_AUTH_USER': 'username'
|
||||||
|
'HTTP_REMOTE_USER': 'username'
|
||||||
|
|
||||||
|
Basic auth contains "{username}:{plaintext-password}"
|
||||||
|
|
||||||
|
and we get SSOwat cookies like:
|
||||||
|
|
||||||
|
'HTTP_COOKIE': 'SSOwAuthUser=username; '
|
||||||
|
'SSOwAuthHash=593876aa66...99e69f88af1e; '
|
||||||
|
'SSOwAuthExpire=1609227697.998; '
|
||||||
|
|
||||||
|
* Login a user via HTTP_REMOTE_USER header, but check also username in:
|
||||||
|
* SSOwAuthUser
|
||||||
|
* HTTP_AUTH_USER
|
||||||
|
* HTTP_AUTHORIZATION (Basic auth)
|
||||||
|
* Create new users
|
||||||
|
* Update Email, First / Last name for existing users
|
||||||
|
"""
|
||||||
|
import base64
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from axes.exceptions import AxesBackendPermissionDenied
|
||||||
|
from django.contrib.auth.backends import RemoteUserBackend as OriginRemoteUserBackend
|
||||||
|
from django.contrib.auth.middleware import RemoteUserMiddleware as OriginRemoteUserMiddleware
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
from inventory.permissions import get_or_create_normal_user_group
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def update_user_profile(request):
|
||||||
|
"""
|
||||||
|
Update existing user information:
|
||||||
|
* Email
|
||||||
|
* First / Last name
|
||||||
|
"""
|
||||||
|
user = request.user
|
||||||
|
assert user.is_authenticated
|
||||||
|
|
||||||
|
update_fields = []
|
||||||
|
|
||||||
|
if not user.password:
|
||||||
|
# Empty password is not valid, so we can't save the model, because of full_clean() call
|
||||||
|
logger.info('Set unusable password for user: %s', user)
|
||||||
|
user.set_unusable_password()
|
||||||
|
update_fields.append('password')
|
||||||
|
|
||||||
|
email = request.META.get('HTTP_EMAIL')
|
||||||
|
if email and user.email != email:
|
||||||
|
logger.info('Update email: %r -> %r', user.email, email)
|
||||||
|
user.email = email
|
||||||
|
update_fields.append('email')
|
||||||
|
|
||||||
|
raw_username = request.META.get('HTTP_NAME')
|
||||||
|
if raw_username:
|
||||||
|
if ' ' in raw_username:
|
||||||
|
first_name, last_name = raw_username.split(' ', 1)
|
||||||
|
else:
|
||||||
|
first_name = ''
|
||||||
|
last_name = raw_username
|
||||||
|
|
||||||
|
if user.first_name != first_name:
|
||||||
|
logger.info('Update first name: %r -> %r', user.first_name, first_name)
|
||||||
|
user.first_name = first_name
|
||||||
|
update_fields.append('first_name')
|
||||||
|
|
||||||
|
if user.last_name != last_name:
|
||||||
|
logger.info('Update last name: %r -> %r', user.last_name, last_name)
|
||||||
|
user.last_name = last_name
|
||||||
|
update_fields.append('last_name')
|
||||||
|
|
||||||
|
if update_fields:
|
||||||
|
try:
|
||||||
|
user.full_clean()
|
||||||
|
except ValidationError:
|
||||||
|
logger.exception('Can not update user: %s', user)
|
||||||
|
else:
|
||||||
|
user.save(update_fields=update_fields)
|
||||||
|
|
||||||
|
|
||||||
|
class RemoteUserMiddleware(OriginRemoteUserMiddleware):
|
||||||
|
"""
|
||||||
|
Middleware to login a user HTTP_REMOTE_USER header.
|
||||||
|
Use Django Axes if something is wrong.
|
||||||
|
Update exising user informations.
|
||||||
|
"""
|
||||||
|
header = 'HTTP_REMOTE_USER'
|
||||||
|
force_logout_if_no_header = True
|
||||||
|
|
||||||
|
def process_request(self, request):
|
||||||
|
# Keep the information if the user is already logged in
|
||||||
|
was_authenticated = request.user.is_authenticated
|
||||||
|
|
||||||
|
super().process_request(request) # login remote user
|
||||||
|
|
||||||
|
if not request.user.is_authenticated:
|
||||||
|
# Not logged in -> nothing to verify here
|
||||||
|
return
|
||||||
|
|
||||||
|
# Check SSOwat cookie informations:
|
||||||
|
try:
|
||||||
|
username = request.COOKIES['SSOwAuthUser']
|
||||||
|
except KeyError:
|
||||||
|
logger.error('SSOwAuthUser cookie missing!')
|
||||||
|
|
||||||
|
# emits a signal indicating user login failed, which is processed by
|
||||||
|
# axes.signals.log_user_login_failed which logs and flags the failed request.
|
||||||
|
raise AxesBackendPermissionDenied('Cookie missing')
|
||||||
|
|
||||||
|
logger.info('SSOwat username from cookies: %r', username)
|
||||||
|
if username != request.user.username:
|
||||||
|
raise AxesBackendPermissionDenied('Wrong username')
|
||||||
|
|
||||||
|
# Compare with HTTP_AUTH_USER
|
||||||
|
try:
|
||||||
|
username = request.META['HTTP_AUTH_USER']
|
||||||
|
except KeyError:
|
||||||
|
logger.error('HTTP_AUTH_USER missing!')
|
||||||
|
raise AxesBackendPermissionDenied('No HTTP_AUTH_USER')
|
||||||
|
|
||||||
|
if username != request.user.username:
|
||||||
|
raise AxesBackendPermissionDenied('Wrong HTTP_AUTH_USER username')
|
||||||
|
|
||||||
|
# Also check 'HTTP_AUTHORIZATION', but only the username ;)
|
||||||
|
try:
|
||||||
|
auth = request.META['HTTP_AUTHORIZATION']
|
||||||
|
except KeyError:
|
||||||
|
logger.error('HTTP_AUTHORIZATION missing!')
|
||||||
|
raise AxesBackendPermissionDenied('No HTTP_AUTHORIZATION')
|
||||||
|
|
||||||
|
scheme, creds = auth.split(' ', 1)
|
||||||
|
if scheme.lower() != 'basic':
|
||||||
|
logger.error('HTTP_AUTHORIZATION with %r not supported', scheme)
|
||||||
|
raise AxesBackendPermissionDenied('HTTP_AUTHORIZATION scheme not supported')
|
||||||
|
|
||||||
|
creds = str(base64.b64decode(creds), encoding='utf-8')
|
||||||
|
username = creds.split(':', 1)[0]
|
||||||
|
if username != request.user.username:
|
||||||
|
raise AxesBackendPermissionDenied('Wrong HTTP_AUTHORIZATION username')
|
||||||
|
|
||||||
|
if not was_authenticated:
|
||||||
|
# First request, after login -> update user informations
|
||||||
|
logger.info('Remote used was logged in')
|
||||||
|
update_user_profile(request)
|
||||||
|
|
||||||
|
|
||||||
|
class RemoteUserBackend(OriginRemoteUserBackend):
|
||||||
|
"""
|
||||||
|
Authentication backend via SSO/nginx header
|
||||||
|
"""
|
||||||
|
create_unknown_user = True
|
||||||
|
|
||||||
|
def authenticate(self, request, remote_user):
|
||||||
|
logger.info('Remote user authenticate: %r', remote_user)
|
||||||
|
return super().authenticate(request, remote_user)
|
||||||
|
|
||||||
|
def configure_user(self, request, user):
|
||||||
|
"""
|
||||||
|
Configure a user after creation and return the updated user.
|
||||||
|
Setup a normal, non-superuser
|
||||||
|
"""
|
||||||
|
logger.warning('Configure user %s', user)
|
||||||
|
|
||||||
|
user.set_unusable_password() # Always login via SSO
|
||||||
|
user.is_staff = True
|
||||||
|
user.is_superuser = False
|
||||||
|
user.save()
|
||||||
|
|
||||||
|
pyinventory_user_group = get_or_create_normal_user_group()[0]
|
||||||
|
user.groups.set([pyinventory_user_group])
|
||||||
|
|
||||||
|
update_user_profile(request)
|
||||||
|
|
||||||
|
return user
|
||||||
|
|
||||||
|
def user_can_authenticate(self, user):
|
||||||
|
logger.warning('Remote user login: %s', user)
|
||||||
|
return True
|
|
@ -11,8 +11,6 @@
|
||||||
|
|
||||||
from pathlib import Path as __Path
|
from pathlib import Path as __Path
|
||||||
|
|
||||||
import ldap
|
|
||||||
from django_auth_ldap.config import LDAPSearch
|
|
||||||
from inventory_project.settings.base import * # noqa
|
from inventory_project.settings.base import * # noqa
|
||||||
|
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
@ -36,43 +34,30 @@ PATH_URL = PATH_URL.strip('/')
|
||||||
ROOT_URLCONF = 'ynh_urls' # /opt/yunohost/pyinventory/ynh_urls.py
|
ROOT_URLCONF = 'ynh_urls' # /opt/yunohost/pyinventory/ynh_urls.py
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
# https://github.com/django-auth-ldap/django-auth-ldap
|
|
||||||
|
|
||||||
LDAP_SERVER_URI = 'ldap://localhost:389'
|
|
||||||
LDAP_START_TLS = True
|
|
||||||
|
|
||||||
# enable anonymous searches
|
|
||||||
# https://django-auth-ldap.readthedocs.io/en/latest/authentication.html?highlight=anonymous#search-bind
|
|
||||||
LDAP_BIND_DN = ''
|
|
||||||
LDAP_BIND_PASSWORD = ''
|
|
||||||
|
|
||||||
LDAP_ROOT_DN = 'ou=users,dc=yunohost,dc=org'
|
|
||||||
|
|
||||||
AUTH_LDAP_USER_SEARCH = LDAPSearch(LDAP_ROOT_DN, ldap.SCOPE_SUBTREE, '(uid=%(user)s)')
|
|
||||||
|
|
||||||
# Populate the Django user from the LDAP directory.
|
|
||||||
AUTH_LDAP_USER_ATTR_MAP = {
|
|
||||||
'username': 'uid',
|
|
||||||
'first_name': 'givenName',
|
|
||||||
'last_name': 'sn',
|
|
||||||
'email': 'mail',
|
|
||||||
}
|
|
||||||
|
|
||||||
AUTH_LDAP_ALWAYS_UPDATE_USER = True
|
|
||||||
|
|
||||||
# Don't use LDAP group membership to calculate group permissions
|
|
||||||
AUTH_LDAP_FIND_GROUP_PERMS = False
|
|
||||||
|
|
||||||
AUTH_LDAP_GROUP_TYPE = 'normal user' # Same as: inventory.permissions.NORMAL_USER_GROUP_NAME
|
|
||||||
|
|
||||||
# Cache distinguished names and group memberships for an hour to minimize LDAP traffic
|
|
||||||
AUTH_LDAP_CACHE_TIMEOUT = 3600
|
|
||||||
|
|
||||||
# Keep ModelBackend around for per-user permissions and superuser
|
# Keep ModelBackend around for per-user permissions and superuser
|
||||||
AUTHENTICATION_BACKENDS = (
|
AUTHENTICATION_BACKENDS = (
|
||||||
'django_auth_ldap.backend.LDAPBackend',
|
'axes.backends.AxesBackend', # AxesBackend should be the first backend!
|
||||||
|
|
||||||
|
# Authenticate via SSO and nginx 'HTTP_REMOTE_USER' header:
|
||||||
|
'ynh_authenticate.RemoteUserBackend',
|
||||||
|
|
||||||
|
# Fallback to normal Django model backend:
|
||||||
'django.contrib.auth.backends.ModelBackend',
|
'django.contrib.auth.backends.ModelBackend',
|
||||||
)
|
)
|
||||||
|
LOGIN_REDIRECT_URL = None
|
||||||
|
LOGIN_URL = '/yunohost/sso/'
|
||||||
|
LOGOUT_REDIRECT_URL = '/yunohost/sso/'
|
||||||
|
# /yunohost/sso/?action=logout
|
||||||
|
|
||||||
|
# -----------------------------------------------------------------------------
|
||||||
|
# https://docs.djangoproject.com/en/2.2/howto/auth-remote-user/
|
||||||
|
# Add RemoteUserMiddleware after AuthenticationMiddleware
|
||||||
|
|
||||||
|
MIDDLEWARE.insert(
|
||||||
|
MIDDLEWARE.index('django.contrib.auth.middleware.AuthenticationMiddleware') + 1,
|
||||||
|
'ynh_authenticate.RemoteUserMiddleware',
|
||||||
|
)
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -153,7 +138,7 @@ CKEDITOR_BASEPATH = STATIC_URL + 'ckeditor/ckeditor/'
|
||||||
# _____________________________________________________________________________
|
# _____________________________________________________________________________
|
||||||
# Django-dbbackup
|
# Django-dbbackup
|
||||||
|
|
||||||
DBBACKUP_STORAGE_OPTIONS['location']=str(FINAL_HOME_PATH / 'backups')
|
DBBACKUP_STORAGE_OPTIONS['location'] = str(FINAL_HOME_PATH / 'backups')
|
||||||
|
|
||||||
# -----------------------------------------------------------------------------
|
# -----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
@ -173,7 +158,7 @@ LOGGING = {
|
||||||
'class': 'django.utils.log.AdminEmailHandler',
|
'class': 'django.utils.log.AdminEmailHandler',
|
||||||
'include_html': True,
|
'include_html': True,
|
||||||
},
|
},
|
||||||
'syslog': {
|
'log_file': {
|
||||||
'level': 'DEBUG',
|
'level': 'DEBUG',
|
||||||
'class': 'logging.handlers.WatchedFileHandler',
|
'class': 'logging.handlers.WatchedFileHandler',
|
||||||
'formatter': 'verbose',
|
'formatter': 'verbose',
|
||||||
|
@ -181,12 +166,12 @@ LOGGING = {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'loggers': {
|
'loggers': {
|
||||||
'': {'handlers': ['syslog', 'mail_admins'], 'level': 'INFO', 'propagate': False},
|
'': {'handlers': ['log_file', 'mail_admins'], 'level': 'INFO', 'propagate': False},
|
||||||
'django': {'handlers': ['syslog', 'mail_admins'], 'level': 'INFO', 'propagate': False},
|
'django': {'handlers': ['log_file', 'mail_admins'], 'level': 'INFO', 'propagate': False},
|
||||||
'axes': {'handlers': ['syslog', 'mail_admins'], 'level': 'WARNING', 'propagate': False},
|
'axes': {'handlers': ['log_file', 'mail_admins'], 'level': 'WARNING', 'propagate': False},
|
||||||
'django_tools': {'handlers': ['syslog', 'mail_admins'], 'level': 'INFO', 'propagate': False},
|
'django_tools': {'handlers': ['log_file', 'mail_admins'], 'level': 'INFO', 'propagate': False},
|
||||||
'django_auth_ldap': {'handlers': ['syslog', 'mail_admins'], 'level': 'DEBUG', 'propagate': False},
|
'django_auth_ldap': {'handlers': ['log_file', 'mail_admins'], 'level': 'DEBUG', 'propagate': False},
|
||||||
'inventory': {'handlers': ['syslog', 'mail_admins'], 'level': 'INFO', 'propagate': False},
|
'inventory': {'handlers': ['log_file', 'mail_admins'], 'level': 'INFO', 'propagate': False},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
from django_auth_ldap.backend import LDAPBackend
|
|
||||||
from inventory.permissions import get_or_create_normal_user_group
|
|
||||||
|
|
||||||
|
|
||||||
class PyInventoryYunohostLdapBackend(LDAPBackend):
|
|
||||||
def get_or_build_user(self, username, ldap_user):
|
|
||||||
user, built = super().get_or_build_user(username, ldap_user)
|
|
||||||
|
|
||||||
if built:
|
|
||||||
user.is_staff = True
|
|
||||||
user.is_superuser = False
|
|
||||||
user.save()
|
|
||||||
|
|
||||||
pyinventory_user_group = get_or_create_normal_user_group()[0]
|
|
||||||
user.groups.set([pyinventory_user_group])
|
|
||||||
|
|
||||||
return user, built
|
|
|
@ -4,12 +4,27 @@ from django.contrib import admin
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from django.views.generic import RedirectView
|
from django.views.generic import RedirectView
|
||||||
|
|
||||||
|
|
||||||
|
# def debug_view(request):
|
||||||
|
# """ debug request.META """
|
||||||
|
# if not request.user.is_authenticated:
|
||||||
|
# from django.shortcuts import redirect
|
||||||
|
# return redirect('admin:index')
|
||||||
|
#
|
||||||
|
# import pprint
|
||||||
|
# meta = pprint.pformat(request.META)
|
||||||
|
# html = f'<html><body>request.META: <pre>{meta}</pre></body></html>'
|
||||||
|
# from django.http import HttpResponse
|
||||||
|
# return HttpResponse(html)
|
||||||
|
|
||||||
|
|
||||||
# settings.PATH_URL is the $YNH_APP_ARG_PATH
|
# settings.PATH_URL is the $YNH_APP_ARG_PATH
|
||||||
if settings.PATH_URL:
|
if settings.PATH_URL:
|
||||||
# Prefix all urls with "PATH_URL":
|
# Prefix all urls with "PATH_URL":
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path(f'{settings.PATH_URL}/admin/', admin.site.urls),
|
path(f'{settings.PATH_URL}/admin/', admin.site.urls),
|
||||||
|
|
||||||
|
# path(f'{settings.PATH_URL}/', debug_view),
|
||||||
path(f'{settings.PATH_URL}/', RedirectView.as_view(pattern_name='admin:index')),
|
path(f'{settings.PATH_URL}/', RedirectView.as_view(pattern_name='admin:index')),
|
||||||
|
|
||||||
path(f'{settings.PATH_URL}/ckeditor/', include('ckeditor_uploader.urls')),
|
path(f'{settings.PATH_URL}/ckeditor/', include('ckeditor_uploader.urls')),
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"description": {
|
"description": {
|
||||||
"en": "Web based management to catalog things including state and location etc."
|
"en": "Web based management to catalog things including state and location etc."
|
||||||
},
|
},
|
||||||
"version": "0.8.2~ynh1",
|
"version": "0.8.2~ynh2",
|
||||||
"url": "https://github.com/jedie/PyInventory",
|
"url": "https://github.com/jedie/PyInventory",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"maintainer": {
|
"maintainer": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "pyinventory_ynh"
|
name = "pyinventory_ynh"
|
||||||
version = "0.8.1~ynh7"
|
version = "0.8.2~ynh2"
|
||||||
description = "Test pyinventory_ynh via local_test.py"
|
description = "Test pyinventory_ynh via local_test.py"
|
||||||
authors = ["JensDiemer <git@jensdiemer.de>"]
|
authors = ["JensDiemer <git@jensdiemer.de>"]
|
||||||
license = "GPL"
|
license = "GPL"
|
||||||
|
@ -8,7 +8,6 @@ license = "GPL"
|
||||||
[tool.poetry.dependencies]
|
[tool.poetry.dependencies]
|
||||||
python = ">=3.7,<4.0.0"
|
python = ">=3.7,<4.0.0"
|
||||||
pyinventory = "*"
|
pyinventory = "*"
|
||||||
django-auth-ldap = "*"
|
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.dev-dependencies]
|
||||||
|
|
||||||
|
|
|
@ -25,13 +25,13 @@ log_file="${log_path}/pyinventory.log"
|
||||||
|
|
||||||
# dependencies used by the app
|
# dependencies used by the app
|
||||||
pkg_dependencies="build-essential python3-dev python3-pip python3-venv git \
|
pkg_dependencies="build-essential python3-dev python3-pip python3-venv git \
|
||||||
postgresql postgresql-contrib python3-ldap libldap2-dev libsasl2-dev"
|
postgresql postgresql-contrib"
|
||||||
|
|
||||||
# PyInventory's version for PIP and settings file
|
# PyInventory's version for PIP and settings file
|
||||||
pyinventory_version="0.8.2"
|
pyinventory_version="0.8.2"
|
||||||
|
|
||||||
# Extra python packages:
|
# Extra python packages:
|
||||||
pypi_extras="django-redis django-auth-ldap"
|
pypi_extras="django-redis"
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
# Redis HELPERS
|
# Redis HELPERS
|
||||||
|
|
|
@ -157,7 +157,7 @@ ynh_app_setting_set --app="$app" --key=redis_db --value="$redis_db"
|
||||||
|
|
||||||
touch "$final_path/local_settings.py"
|
touch "$final_path/local_settings.py"
|
||||||
|
|
||||||
cp "../conf/ynh_sso_ldap_backend.py" "$final_path/ynh_sso_ldap_backend.py"
|
cp "../conf/ynh_authenticate.py" "$final_path/ynh_authenticate.py"
|
||||||
cp "../conf/ynh_urls.py" "$final_path/ynh_urls.py"
|
cp "../conf/ynh_urls.py" "$final_path/ynh_urls.py"
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
|
|
|
@ -147,7 +147,7 @@ ynh_store_file_checksum --file="$settings"
|
||||||
|
|
||||||
touch "$final_path/local_settings.py"
|
touch "$final_path/local_settings.py"
|
||||||
|
|
||||||
cp "../conf/ynh_sso_ldap_backend.py" "$final_path/ynh_sso_ldap_backend.py"
|
cp "../conf/ynh_authenticate.py" "$final_path/ynh_authenticate.py"
|
||||||
cp "../conf/ynh_urls.py" "$final_path/ynh_urls.py"
|
cp "../conf/ynh_urls.py" "$final_path/ynh_urls.py"
|
||||||
|
|
||||||
#=================================================
|
#=================================================
|
||||||
|
|
Loading…
Reference in a new issue