Skip to content

Commit 05414f6

Browse files
authored
feat: RBAC + SAML support
1 parent 8fecccc commit 05414f6

File tree

158 files changed

+6423
-106
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

158 files changed

+6423
-106
lines changed

Dockerfile

+2-2
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ ENV PATH="$VIRTUAL_ENV/bin:$PATH"
3737
# Install runtime system dependencies
3838
RUN apt-get update -y && \
3939
apt-get -y upgrade && \
40-
apt-get install --no-install-recommends supervisor nginx imagemagick procps -y && \
40+
apt-get install --no-install-recommends supervisor nginx imagemagick procps libxml2-dev libxmlsec1-dev libxmlsec1-openssl -y && \
4141
rm -rf /var/lib/apt/lists/* && \
4242
apt-get purge --auto-remove && \
4343
apt-get clean
@@ -85,4 +85,4 @@ EXPOSE 9000 80
8585
RUN chmod +x ./deploy/docker/entrypoint.sh
8686

8787
ENTRYPOINT ["./deploy/docker/entrypoint.sh"]
88-
CMD ["./deploy/docker/start.sh"]
88+
CMD ["./deploy/docker/start.sh"]

README.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,13 @@ A demo is available at https://demo.mediacms.io
2323

2424
## Features
2525
- **Complete control over your data**: host it yourself!
26-
- **Support for multiple publishing workflows**: public, private, unlisted and custom
2726
- **Modern technologies**: Django/Python/Celery, React.
27+
- **Support for multiple publishing workflows**: public, private, unlisted and custom
2828
- **Multiple media types support**: video, audio, image, pdf
2929
- **Multiple media classification options**: categories, tags and custom
3030
- **Multiple media sharing options**: social media share, videos embed code generation
31+
- **Role-Based Access Control (RBAC)
32+
- **SAML support
3133
- **Easy media searching**: enriched with live search functionality
3234
- **Playlists for audio and video content**: create playlists, add and reorder content
3335
- **Responsive design**: including light and dark themes

admin_customizations/__init__.py

Whitespace-only changes.

admin_customizations/admin.py

Whitespace-only changes.

admin_customizations/apps.py

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
from django.apps import AppConfig
2+
from django.conf import settings
3+
from django.contrib import admin
4+
5+
6+
class AdminCustomizationsConfig(AppConfig):
7+
default_auto_field = 'django.db.models.BigAutoField'
8+
name = 'admin_customizations'
9+
10+
def ready(self):
11+
original_get_app_list = admin.AdminSite.get_app_list
12+
13+
def get_app_list(self, request, app_label=None):
14+
"""Custom get_app_list"""
15+
app_list = original_get_app_list(self, request, app_label)
16+
# To see the list:
17+
# print([a.get('app_label') for a in app_list])
18+
19+
email_model = None
20+
rbac_group_model = None
21+
identity_providers_user_log_model = None
22+
identity_providers_login_option = None
23+
auth_app = None
24+
rbac_app = None
25+
socialaccount_app = None
26+
27+
for app in app_list:
28+
if app['app_label'] == 'users':
29+
auth_app = app
30+
31+
elif app['app_label'] == 'account':
32+
for model in app['models']:
33+
if model['object_name'] == 'EmailAddress':
34+
email_model = model
35+
elif app['app_label'] == 'rbac':
36+
if not getattr(settings, 'USE_RBAC', False):
37+
continue
38+
rbac_app = app
39+
for model in app['models']:
40+
if model['object_name'] == 'RBACGroup':
41+
rbac_group_model = model
42+
elif app['app_label'] == 'identity_providers':
43+
if not getattr(settings, 'USE_IDENTITY_PROVIDERS', False):
44+
continue
45+
46+
models_to_check = list(app['models'])
47+
48+
for model in models_to_check:
49+
if model['object_name'] == 'IdentityProviderUserLog':
50+
identity_providers_user_log_model = model
51+
if model['object_name'] == 'LoginOption':
52+
identity_providers_login_option = model
53+
elif app['app_label'] == 'socialaccount':
54+
socialaccount_app = app
55+
56+
if email_model and auth_app:
57+
auth_app['models'].append(email_model)
58+
if rbac_group_model and rbac_app and auth_app:
59+
auth_app['models'].append(rbac_group_model)
60+
if identity_providers_login_option and socialaccount_app:
61+
socialaccount_app['models'].append(identity_providers_login_option)
62+
if identity_providers_user_log_model and socialaccount_app:
63+
socialaccount_app['models'].append(identity_providers_user_log_model)
64+
65+
# 2. don't include the following apps
66+
apps_to_hide = ['authtoken', 'auth', 'account', 'saml_auth', 'rbac']
67+
if not getattr(settings, 'USE_RBAC', False):
68+
apps_to_hide.append('rbac')
69+
if not getattr(settings, 'USE_IDENTITY_PROVIDERS', False):
70+
apps_to_hide.append('socialaccount')
71+
72+
app_list = [app for app in app_list if app['app_label'] not in apps_to_hide]
73+
74+
# 3. change the ordering
75+
app_order = {
76+
'files': 1,
77+
'users': 2,
78+
'socialaccount': 3,
79+
'rbac': 5,
80+
}
81+
82+
app_list.sort(key=lambda x: app_order.get(x['app_label'], 999))
83+
84+
return app_list
85+
86+
admin.AdminSite.get_app_list = get_app_list

admin_customizations/migrations/__init__.py

Whitespace-only changes.

admin_customizations/models.py

Whitespace-only changes.

admin_customizations/tests.py

Whitespace-only changes.

admin_customizations/views.py

Whitespace-only changes.

cms/dev_settings.py

+29-23
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,36 @@
44
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
55

66
INSTALLED_APPS = [
7-
'django.contrib.admin',
8-
'django.contrib.auth',
9-
'allauth',
10-
'allauth.account',
11-
'allauth.socialaccount',
12-
'django.contrib.contenttypes',
13-
'django.contrib.sessions',
14-
'django.contrib.messages',
15-
'django.contrib.staticfiles',
16-
'django.contrib.sites',
17-
'rest_framework',
18-
'rest_framework.authtoken',
19-
'imagekit',
20-
'files.apps.FilesConfig',
21-
'users.apps.UsersConfig',
22-
'actions.apps.ActionsConfig',
23-
'debug_toolbar',
24-
'mptt',
25-
'crispy_forms',
7+
"admin_customizations",
8+
"django.contrib.auth",
9+
"allauth",
10+
"allauth.account",
11+
"allauth.socialaccount",
12+
"django.contrib.contenttypes",
13+
"django.contrib.sessions",
14+
"django.contrib.messages",
15+
"django.contrib.staticfiles",
16+
"jazzmin",
17+
"django.contrib.admin",
18+
"django.contrib.sites",
19+
"rest_framework",
20+
"rest_framework.authtoken",
21+
"imagekit",
22+
"files.apps.FilesConfig",
23+
"users.apps.UsersConfig",
24+
"actions.apps.ActionsConfig",
25+
"rbac.apps.RbacConfig",
26+
"identity_providers.apps.IdentityProvidersConfig",
27+
"debug_toolbar",
28+
"mptt",
29+
"crispy_forms",
2630
"crispy_bootstrap5",
27-
'uploader.apps.UploaderConfig',
28-
'djcelery_email',
29-
'drf_yasg',
30-
'corsheaders',
31+
"uploader.apps.UploaderConfig",
32+
"djcelery_email",
33+
"drf_yasg",
34+
"allauth.socialaccount.providers.saml",
35+
"saml_auth.apps.SamlAuthConfig",
36+
"corsheaders",
3137
]
3238

3339
MIDDLEWARE = [

cms/settings.py

+46-32
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@
115115
ACCOUNT_EMAIL_REQUIRED = True # new users need to specify email
116116
ACCOUNT_EMAIL_VERIFICATION = "optional" # 'mandatory' 'none'
117117
ACCOUNT_LOGIN_ON_EMAIL_CONFIRMATION = True
118-
ACCOUNT_USERNAME_MIN_LENGTH = "4"
118+
ACCOUNT_USERNAME_MIN_LENGTH = 4
119119
ACCOUNT_ADAPTER = "users.adapter.MyAccountAdapter"
120120
ACCOUNT_SIGNUP_FORM_CLASS = "users.forms.SignupForm"
121121
ACCOUNT_USERNAME_VALIDATORS = "users.validators.custom_username_validators"
@@ -256,7 +256,7 @@
256256
)
257257

258258
INSTALLED_APPS = [
259-
"django.contrib.admin",
259+
"admin_customizations",
260260
"django.contrib.auth",
261261
"allauth",
262262
"allauth.account",
@@ -265,20 +265,26 @@
265265
"django.contrib.sessions",
266266
"django.contrib.messages",
267267
"django.contrib.staticfiles",
268+
"jazzmin",
269+
"django.contrib.admin",
268270
"django.contrib.sites",
269271
"rest_framework",
270272
"rest_framework.authtoken",
271273
"imagekit",
272274
"files.apps.FilesConfig",
273275
"users.apps.UsersConfig",
274276
"actions.apps.ActionsConfig",
277+
"rbac.apps.RbacConfig",
278+
"identity_providers.apps.IdentityProvidersConfig",
275279
"debug_toolbar",
276280
"mptt",
277281
"crispy_forms",
278282
"crispy_bootstrap5",
279283
"uploader.apps.UploaderConfig",
280284
"djcelery_email",
281285
"drf_yasg",
286+
"allauth.socialaccount.providers.saml",
287+
"saml_auth.apps.SamlAuthConfig",
282288
]
283289

284290
MIDDLEWARE = [
@@ -440,26 +446,6 @@
440446
CELERY_TASK_ALWAYS_EAGER = True
441447

442448

443-
try:
444-
# keep a local_settings.py file for local overrides
445-
from .local_settings import * # noqa
446-
447-
# ALLOWED_HOSTS needs a url/ip
448-
ALLOWED_HOSTS.append(FRONTEND_HOST.replace("http://", "").replace("https://", ""))
449-
except ImportError:
450-
# local_settings not in use
451-
pass
452-
453-
454-
if "http" not in FRONTEND_HOST:
455-
# FRONTEND_HOST needs a http:// preffix
456-
FRONTEND_HOST = f"http://{FRONTEND_HOST}" # noqa
457-
458-
if LOCAL_INSTALL:
459-
SSL_FRONTEND_HOST = FRONTEND_HOST.replace("http", "https")
460-
else:
461-
SSL_FRONTEND_HOST = FRONTEND_HOST
462-
463449
if GLOBAL_LOGIN_REQUIRED:
464450
# this should go after the AuthenticationMiddleware middleware
465451
MIDDLEWARE.insert(6, "login_required.middleware.LoginRequiredMiddleware")
@@ -477,16 +463,6 @@
477463

478464
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
479465

480-
# the following is related to local development using docker
481-
# and docker-compose-dev.yaml
482-
try:
483-
DEVELOPMENT_MODE = os.environ.get("DEVELOPMENT_MODE")
484-
if DEVELOPMENT_MODE:
485-
# keep a dev_settings.py file for local overrides
486-
from .dev_settings import * # noqa
487-
except ImportError:
488-
pass
489-
490466
LANGUAGES = [
491467
('ar', _('Arabic')),
492468
('bn', _('Bengali')),
@@ -526,7 +502,45 @@
526502
# keep the trailing slash
527503
DJANGO_ADMIN_URL = "admin/"
528504

505+
# this are used around a number of places and will need to be well documented!!!
506+
507+
USE_SAML = False
508+
USE_RBAC = False
509+
USE_IDENTITY_PROVIDERS = False
510+
JAZZMIN_UI_TWEAKS = {"theme": "flatly"}
511+
512+
513+
try:
514+
# keep a local_settings.py file for local overrides
515+
from .local_settings import * # noqa
516+
517+
# ALLOWED_HOSTS needs a url/ip
518+
ALLOWED_HOSTS.append(FRONTEND_HOST.replace("http://", "").replace("https://", ""))
519+
except ImportError:
520+
# local_settings not in use
521+
pass
522+
523+
if "http" not in FRONTEND_HOST:
524+
# FRONTEND_HOST needs a http:// preffix
525+
FRONTEND_HOST = f"http://{FRONTEND_HOST}" # noqa
526+
527+
if LOCAL_INSTALL:
528+
SSL_FRONTEND_HOST = FRONTEND_HOST.replace("http", "https")
529+
else:
530+
SSL_FRONTEND_HOST = FRONTEND_HOST
531+
532+
529533
# CSRF_COOKIE_SECURE = True
530534
# SESSION_COOKIE_SECURE = True
531535

532536
PYSUBS_COMMAND = "pysubs2"
537+
538+
# the following is related to local development using docker
539+
# and docker-compose-dev.yaml
540+
try:
541+
DEVELOPMENT_MODE = os.environ.get("DEVELOPMENT_MODE")
542+
if DEVELOPMENT_MODE:
543+
# keep a dev_settings.py file for local overrides
544+
from .dev_settings import * # noqa
545+
except ImportError:
546+
pass

cms/urls.py

+4
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,7 @@
3131
re_path(r'^swagger/$', schema_view.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
3232
path('docs/api/', schema_view.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
3333
]
34+
35+
admin.site.site_header = "MediaCMS Admin"
36+
admin.site.site_title = "MediaCMS"
37+
admin.site.index_title = "Admin"

cms/version.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
VERSION = "5.0.0"

conftest.py

-5
This file was deleted.

0 commit comments

Comments
 (0)