snok / django-auth-adfs

A Django authentication backend for Microsoft ADFS and AzureAD
http://django-auth-adfs.readthedocs.io/
BSD 2-Clause "Simplified" License
270 stars 100 forks source link

Adfs fails to login if served with gunicorn #207

Closed NikPiermafrost closed 2 years ago

NikPiermafrost commented 2 years ago

When i serve my django application through runserver, the application behaves as expected and everything works. the moment i serve the application through gunicorn (i set 2 processes, 2 threads, 60 for timeout) the application is able to autenticate to one process only but failw with the others (django logs the following error message, "django_auth_adfs authentication backend was called but no authorization code was received"

Is there something am i missing in my configuration?

JonasKs commented 2 years ago

Hi,

What you describe sound weird, gunicorn loads the same configuration no matter how many workers or processes you run. In other words, please provide exact commands you run, configuration, logs etc.

NikPiermafrost commented 2 years ago

Command: gunicorn -b 0.0.0.0:8080 --workers=4 portal_web.wsgi

wsgi.py

import os

from django.core.wsgi import get_wsgi_application
from django.conf import settings

class CustomProxyFix(object):
    def __init__(self, app):
        self.app = app

    def __call__(self, environ, start_response):
        environ['HTTP_HOST'] = settings.PORTAL['HOST']
        environ['wsgi.url_scheme'] = settings.PORTAL['PROTOCOL']
        return self.app(environ, start_response)

os.environ.setdefault("DJANGO_SETTINGS_MODULE", "portal_web.settings")

application = get_wsgi_application()

application = CustomProxyFix(application)

settings.py

"""
Django settings for portal project.

Generated by 'django-admin startproject' using Django 2.0.

For more information on this file, see
https://docs.djangoproject.com/en/2.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/2.0/ref/settings/
"""

import datetime
import os
import sys
import ast

import environ

env = environ.Env(
    # Mandatory Variables
    SECRET_KEY=(str),
    POSTGRES_HOST=(str),
    POSTGRES_USER=(str),
    POSTGRES_PASSWORD=(str),
    POSTGRES_NAME=(str),
    INFLUXDB_HOST=(str),
    INFLUXDB_USER=(str),
    INFLUXDB_DATABASE=(str),
    INFLUXDB_PASSWORD=(str),
    EMAIL_HOST=(str),
    DEFAULT_FROM_EMAIL=(str),
    EMAIL_HOST_USER=(str),
    EMAIL_HOST_PASSWORD=(str),
    PORTAL_PROTOCOL=(str),
    PORTAL_HOST=(str),
    CAR_RESERVATION_TO_NOTIFY_EMAILS=(str),
    UBIQUITY_PROTOCOL=(str),
    UBIQUITY_HOST=(str),
    UBIQUITY_DOMAIN=(str),
    UBIQUITY_USERNAME=(str),
    UBIQUITY_PASSWORD=(str),
    GOOGLE_API_KEY=(str),
    SAP_API_HOST=(str),
    SAP_API_PORT=(str),
    SAP_SIMULATION=(bool),
    SAP_CONNECTION_ACTIVE=(bool),
    # Optional Variables
    DEBUG=(int, 1),
    DJANGO_LOG_LEVEL=(str, "INFO"),
    POSTGRES_PORT=(int, 5432),
    INFLUXDB_PORT=(int, 8086),
    INFLUXDB_TIMEOUT=(int, 18000),
    INFLUXDB_DB_SIZE=(int, 3650),
    INFLUXDB_SHARD_SIZE_MINUTE_RP=(int, 72),
    INFLUXDB_SHARD_SIZE_HOUR_RP=(int, 168),
    INFLUXDB_SHARD_SIZE_DAY_RP=(int, 168),
    INFLUXDB_SSL=(bool, False),
    INFLUXDB_VERIFY_SSL=(bool, False),
    REDIS_HOST=(str),
    REDIS_PORT=(int, 6379),
    REDIS_DB=(int, 0),
    REDIS_PASSWORD=(str),
    SBB_PORTABLE_BACKUPS_STORAGE_DIRECTORY=(str, "/tmp"),
    SBB_PORTABLE_BACKUPS_EXTRACTION_DIRECTORY=(str, "/extracted"),
    JWT_EXPIRATION_DELTA=(int, 60 * 60),
    JWT_REFRESH_EXPIRATION_DELTA=(int, 1),
    EMAIL_PORT=(int, 25),
    EMAIL_USE_TLS=(bool, True),
    HTTP_REQUEST_TIMEOUT=(int, 180),
    BASIC_OBJECTS=(str, ""),
    ACTIVE_DIRECTORY_DOMAIN=(str),
    INTERNALS_DOMAIN=(str),
    TASKS_RETRY_COUNTDOWN=(int, 60),
    TASKS_MAX_RETRIES=(int, 3),
)

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

# reading .env file
env_file = os.path.join(BASE_DIR, ".env")
if os.path.isfile(env_file):
    env.read_env(env_file)

# SAP
SAP_API_HOST = env("SAP_API_HOST")
SAP_API_PORT = env("SAP_API_PORT")
SAP_SIMULATION = bool(env("SAP_SIMULATION"))
SAP_CONNECTION_ACTIVE = bool(env("SAP_CONNECTION_ACTIVE"))
SAP_LANG_MAP = {"E": "en-BR", "I": "it-IT", "F": "fr-FR", "R": "ru-RU", "S": "es-ES"}

# Fix to have all apps inside the apps folder
PROJECT_ROOT = os.path.dirname(__file__)
sys.path.insert(0, os.path.join(PROJECT_ROOT, "apps"))

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = env("SECRET_KEY")

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = bool(env("DEBUG"))

ALLOWED_HOSTS = ["*"]

# BASIC_OBJECTS
BASIC_OBJECTS = ast.literal_eval(env("BASIC_OBJECTS"))

# REDIS
REDIS = {
    "HOST": env("REDIS_HOST"),
    "PORT": env("REDIS_PORT"),
    "PASSWORD": env("REDIS_PASSWORD"),
    "DB": env("REDIS_DB"),
}

SESSION_ENGINE = 'redis_sessions.session'

SESSION_REDIS = {
    'host': REDIS['HOST'],
    'port': REDIS['PORT'],
    'db': 0,
    'password': REDIS['PASSWORD'],
    'prefix': 'session',
    'socket_timeout': 1,
    'retry_on_timeout': True
}

AUTH_ADFS = {
    "AUDIENCE": "...",
    "CLIENT_ID": "...",
    "CLIENT_SECRET": "...",
    "CLAIM_MAPPING": {
        "first_name": "given_name",
        "last_name": "family_name",
        "email": "email",
        "active_directory_id": "oid",
        "user_principal_name": "upn",
    },
    "GROUPS_CLAIM": "groups",
    "MIRROR_GROUPS": False,
    "USERNAME_CLAIM": "email",
    "TENANT_ID": "...",
    "RELYING_PARTY_ID": "...",
    "LOGIN_EXEMPT_URLS": ["^api/", "^static/", ""],
    "CREATE_NEW_USERS": False
}

REDIS_AD_USERS_EMAIL_LIST_VAR_NAME = "ad_users_email_list"

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": f"redis://default:{REDIS['PASSWORD']}@{REDIS['HOST']}:{REDIS['PORT']}/",
        "OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient"},
    }
}
CACHE_TTL = 300
CELERY_BROKER_URL = f"redis://default:{REDIS['PASSWORD']}@{REDIS['HOST']}:{REDIS['PORT']}/{REDIS['DB']}"

CELERY_RESULT_BACKEND = "django-db"
CELERY_CACHE_BACKEND = "django-cache"

CELERY_TIMEZONE = "Europe/Warsaw"
CELERY_TRACK_STARTED = True

CELERY_IMPORTS = ["backoffice.tasks", "sbbs.tasks", "main.tasks", "users.tasks"]

TASKS = {"COUNTDOWN": int(env("TASKS_RETRY_COUNTDOWN")), "MAX_RETRIES": int(env("TASKS_MAX_RETRIES"))}

DJANGO_LOG_LEVEL = env("DJANGO_LOG_LEVEL")

PORTAL = {
    "PROTOCOL": env("PORTAL_PROTOCOL"),
    "HOST": env("PORTAL_HOST"),
}

LOGGING = {
    "version": 1,
    "disable_existing_loggers": False,
    "handlers": {
        "sbbs": {
            "class": "logging.handlers.RotatingFileHandler",
            "filename": os.path.join(BASE_DIR, "logs", "sbbs.log"),
            "maxBytes": 1024 * 1024 * 10,
            "backupCount": 10,
            "formatter": "main",
            "level": env("DJANGO_LOG_LEVEL"),
        },
        "backoffice": {
            "class": "logging.handlers.RotatingFileHandler",
            "filename": os.path.join(BASE_DIR, "logs", "backoffice.log"),
            "maxBytes": 1024 * 1024 * 10,
            "backupCount": 10,
            "formatter": "main",
            "level": env("DJANGO_LOG_LEVEL"),
        },
        "console": {"class": "logging.StreamHandler", "formatter": "main"},
        "main_logfile": {
            "class": "logging.handlers.RotatingFileHandler",
            "filename": os.path.join(BASE_DIR, "logs", "portal.log"),
            "maxBytes": 1024 * 1024 * 10,
            "backupCount": 10,
            "formatter": "main",
            "level": env("DJANGO_LOG_LEVEL"),
        },
        "error_logfile": {
            "class": "logging.handlers.RotatingFileHandler",
            "filename": os.path.join(BASE_DIR, "logs", "error.log"),
            "maxBytes": 1024 * 1024 * 10,
            "backupCount": 10,
            "formatter": "main",
            "level": "WARNING",
        },
    },
    "formatters": {
        "main": {
            "format": "%(asctime)-20s%(levelname)-10s%(module)-20s%(lineno)-20s%(message)s",
            "datefmt": "%d.%m.%y %H:%M:%S",
        }
    },
    "loggers": {
        "sbbs": {"handlers": ["sbbs"]},
        "backoffice": {"handlers": ["backoffice"]},
        "django": {"handlers": ["console", "main_logfile", "error_logfile"], "propagate": True, "level": "WARNING"},
        "apscheduler": {
            "handlers": ["console", "main_logfile", "error_logfile"],
            "propagate": True,
            "level": "WARNING",
        },
        "django.template": {
            "handlers": ["console", "main_logfile", "error_logfile"],
            "propagate": False,
            "level": "WARNING",
        },
        "django.db.backends": {
            "handlers": ["console", "main_logfile", "error_logfile"],
            "propagate": False,
            "level": "ERROR",
        },
        "portal": {
            "handlers": ["console", "main_logfile", "error_logfile"],
            "propagate": True,
            "level": env("DJANGO_LOG_LEVEL"),
        },
        "influx": {
            "handlers": ["console", "main_logfile", "error_logfile"],
            "propagate": True,
            "level": env("DJANGO_LOG_LEVEL"),
        },
        "queue": {
            "handlers": ["console", "main_logfile", "error_logfile"],
            "propagate": True,
            "level": env("DJANGO_LOG_LEVEL"),
        },
        "django_auth_adfs": {"handlers": ["console"], "level": "DEBUG",},
    },
}

# Application definition

INSTALLED_APPS = [
    "grappelli",
    "django_auth_adfs",
    "django_pgviews",
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django_extensions",
    # "django.contrib.sites",
    "django.contrib.staticfiles",
    "django_filters",
    "import_export",
    "rest_framework",
    "rest_framework_jwt",
    "django_nose",
    "martor",
    "tinymce",
    "taggit",
    "taggit_serializer",
    "taggit_helpers",
    "taggit_labels",
    "taggit_anywhere",
    "django_cleanup.apps.CleanupConfig",
    "django_inlinecss",
    "guardian",
    "taggit_autosuggest",
    "colorfield",
    "multi_email_field",
    "portal_web.apps.main.apps.MainConfig",
    "portal_web.apps.users.apps.UsersConfig",
    "portal_web.apps.sbbs.apps.HostsConfig",
    "portal_web.apps.companies.apps.CustomersConfig",
    "portal_web.apps.farms.apps.FarmsConfig",
    "portal_web.apps.backoffice.apps.BackofficeConfig",
    "portal_web.apps.facco.apps.FaccoConfig",
    "portal_web.apps.custom_notifications.apps.CustomNotificationsConfig",
    "pwa",
    "django_celery_beat",
    "django_celery_results",
    "portal_web.apps.ticketing.apps.TicketingConfig",
]

MIDDLEWARE = [
    "django.middleware.security.SecurityMiddleware",
    "django.contrib.sessions.middleware.SessionMiddleware",
    "django.middleware.common.CommonMiddleware",
    "django.middleware.csrf.CsrfViewMiddleware",
    "django.contrib.auth.middleware.AuthenticationMiddleware",
    "django.contrib.messages.middleware.MessageMiddleware",
    "django.middleware.clickjacking.XFrameOptionsMiddleware",
    "django_auth_adfs.middleware.LoginRequiredMiddleware",
]

# manifest.json settings
PWA_APP_NAME = "Facco Portal"
PWA_APP_DESCRIPTION = "Facco Portal"
PWA_APP_THEME_COLOR = "#e20713"
PWA_APP_BACKGROUND_COLOR = "#e20713"
PWA_APP_DISPLAY = "standalone"
PWA_APP_SCOPE = "/"
PWA_APP_ORIENTATION = "any"
PWA_APP_START_URL = "/"
PWA_APP_ICONS = [{"src": "/static/images/icons/facco-icon.png", "sizes": "512x512", "type": "image/png"}]
PWA_APP_ICONS_APPLE = [{"src": "/static/images/icons/facco-icon.png", "sizes": "512x512", "type": "image/png"}]
PWA_APP_SPLASH_SCREEN = [
    {
        "src": "/static/images/icons/facco-icon.png",
        "media": "(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)",
    }
]

ROOT_URLCONF = "portal_web.urls"

SESSION_SAVE_EVERY_REQUEST = True
SESSION_COOKIE_AGE = 5 * 60 * 60 * 2

TEMPLATES = [
    {
        "DIRS": [
            (os.path.join(BASE_DIR, "templates")),
            (os.path.join(BASE_DIR, "portal_web", "apps", "main", "templates")),
        ],
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ]
        },
    }
]

WSGI_APPLICATION = "portal_web.wsgi.application"

# Database
# https://docs.djangoproject.com/en/2.0/ref/settings/#databases

DATABASES = {
    "default": {
        "ENGINE": os.environ.get("DB_ENGINE", "django.db.backends.postgresql"),
        "HOST": env("POSTGRES_HOST"),
        "PORT": env("POSTGRES_PORT"),
        "NAME": env("POSTGRES_DATABASE"),
        "USER": env("POSTGRES_USER"),
        "PASSWORD": env("POSTGRES_PASSWORD"),
    }
}

INFLUXDB = {
    "HOST": env("INFLUXDB_HOST"),
    "PORT": env("INFLUXDB_PORT"),
    "USER": env("INFLUXDB_USER"),
    "PASSWORD": env("INFLUXDB_PASSWORD"),
    "DATABASE": env("INFLUXDB_DATABASE"),
    "TIMEOUT": env("INFLUXDB_TIMEOUT"),
    "DB_SIZE": env("INFLUXDB_DB_SIZE"),
    "SHARD_SIZE_MINUTE_RP": env("INFLUXDB_SHARD_SIZE_MINUTE_RP"),
    "SHARD_SIZE_HOUR_RP": env("INFLUXDB_SHARD_SIZE_HOUR_RP"),
    "SHARD_SIZE_DAY_RP": env("INFLUXDB_SHARD_SIZE_DAY_RP"),
    "SSL": env("INFLUXDB_SSL"),
    "VERIFY_SSL": env("INFLUXDB_VERIFY_SSL"),
}

# Password validation
# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators

AUTH_PASSWORD_VALIDATORS = [
    {"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator"},
    {"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator"},
    {"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator"},
    {"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator"},
]

# Internationalization
# https://docs.djangoproject.com/en/2.0/topics/i18n/

LANGUAGE_CODE = "en-us"

LANGUAGE_CODE_DEFAULT = "en-US"
LANGUAGE_CODES = [
    ("en-US", "English (US)"),
    ("en-BR", "English (BR)"),
    ("es-ES", "Spanish"),
    ("fr-FR", "French"),
    ("it-IT", "Italian"),
    ("ja-JP", "Japanese"),
    ("ru-RU", "Russian"),
    ("tr-TR", "Turkish"),
    ("zh-CN", "Chinese"),
]

TIME_ZONE = "UTC"

USE_I18N = True

USE_L10N = True

USE_TZ = True

DATA_UPLOAD_MAX_NUMBER_FIELDS = 10240

# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/2.0/howto/static-files/

STATIC_URL = "/static/"

STATICFILES_DIRS = [os.path.join(BASE_DIR, "assets")]

STATIC_ROOT = os.path.join(BASE_DIR, "static")

# only copression
STATICFILES_STORAGE = "whitenoise.storage.CompressedStaticFilesStorage"

MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/v1/media/"

ARTICLE_IMAGES_FOLDER = "uploads/article-images/"
ARTICLE_ATTACHMENTS_FOLDER = "uploads/article-attachments/"
MESSAGE_ATTACHMENTS_FOLDER = "uploads/message-attachments/"
DOCUMENTS_FOLDER = "uploads/documents/"
DOCUMENTS_PREVIEW_FOLDER = "uploads/document-previews/"
CARS_FOLDER = "uploads/cars/"
USERS_IMAGES_FOLDER = "uploads/users/"
TICKET_ATTACHMENTS_FOLDER = "uploads/ticket-attachments/"
TICKET_ATTACHMENTS_PREVIEW_FOLDER = "uploads/ticket-attachment-previews/"
CARS_FOLDER = "uploads/cars/"

IMAGE_NOT_FOUND_PATH = os.path.join(STATIC_ROOT, "images", "not_found.png")

# Custom User Model definition
# (see https://docs.djangoproject.com/en/3.1/topics/auth/customizing/#substituting-a-custom-user-model)

# Rest Framework settings
REST_FRAMEWORK = {
    "DEFAULT_SCHEMA_CLASS": "rest_framework.schemas.coreapi.AutoSchema",
    "DEFAULT_PERMISSION_CLASSES": ("main.libraries.rest_framework.IsAuthenticated",),
    "DEFAULT_AUTHENTICATION_CLASSES": (
        "django_auth_adfs.rest_framework.AdfsAccessTokenAuthentication",
        "rest_framework.authentication.SessionAuthentication",
    ),
}

# JWT token settings
JWT_AUTH = {
    ...toRemove, it is currently not used
}

AUTH_USER_MODEL = "users.User"

# Email settings
EMAIL_HOST = env("EMAIL_HOST")
EMAIL_PORT = env("EMAIL_PORT")
EMAIL_HOST_USER = env("EMAIL_HOST_USER")
EMAIL_HOST_PASSWORD = env("EMAIL_HOST_PASSWORD")
EMAIL_USE_TLS = env("EMAIL_USE_TLS")
DEFAULT_FROM_EMAIL = env("DEFAULT_FROM_EMAIL")
CAR_RESERVATION_TO_NOTIFY_EMAILS = env("CAR_RESERVATION_TO_NOTIFY_EMAILS").split()

# requests.session() timeout -- more info here:
# https://requests.readthedocs.io/projects/it/it/latest/user/advanced.html#timeout
HTTP_REQUEST_TIMEOUT = env("HTTP_REQUEST_TIMEOUT")

ALLOWED_TASK_METHODS = [
    "sbbs.tasks.SbbTasks.request_create_backup",
    "sbbs.tasks.SbbTasks.request_all_create_backup",
    "sbbs.tasks.SbbTasks.request_sbb_status",
    "sbbs.tasks.SbbTasks.request_all_sbb_status",
    "sbbs.tasks.SbbTasks.request_get_backup",
    "sbbs.tasks.SbbTasks.restore_backup",
    "sbbs.tasks.SbbTasks.request_influx_status",
    "sbbs.tasks.SbbTasks.request_status_backup",
    "sbbs.tasks.SbbTasks.sbb_portable_backup_import",
    "users.tasks.UserTasks.request_users_updates",
    "facco.tasks.FaccoTasks.sync",
]

HOST_USER_CREDENTIALS = {"USER": "influxbk", "PASSWORD": "B@ckup2021!"}

# For testing
TEST_RUNNER = "django_nose.NoseTestSuiteRunner"
NOSE_ARGS = [
    "--with-spec",
    "--spec-color",
    "--with-coverage",
    "--cover-html",
    "--cover-package=.",
    "--cover-html-dir=reports/cover",
]

# SBB portable backups
SBB = {
    "PORTABLE_BACKUPS_STORAGE_DIRECTORY": env("SBB_PORTABLE_BACKUPS_STORAGE_DIRECTORY"),
    "PORTABLE_BACKUPS_EXTRACTION_DIRECTORY": env("SBB_PORTABLE_BACKUPS_EXTRACTION_DIRECTORY"),
}

# Global martor settings
MARTOR_ENABLE_CONFIGS = {
    "jquery": "true",  # to include/revoke jquery (require for admin default django)
    "living": "false",  # to enable/disable live updates in preview
    "hljs": "true",  # to enable/disable hljs highlighting in preview
}

# Markdownify
MARTOR_MARKDOWNIFY_FUNCTION = "martor.utils.markdownify"
MARTOR_MARKDOWNIFY_URL = "/v1/martor/markdownify/"

AUTHENTICATION_BACKENDS = (
    "django_auth_adfs.backend.AdfsAuthCodeBackend",
    # "django.contrib.auth.backends.ModelBackend",
    "guardian.backends.ObjectPermissionBackend",
)
AUTH_USER_MODEL = "users.User"

# Azure Active Directory
ACTIVE_DIRECTORY_DOMAIN = env("ACTIVE_DIRECTORY_DOMAIN")
INTERNALS_DOMAIN = env("INTERNALS_DOMAIN")

MSAL_AUTHORITY = "https://login.microsoftonline.com/{}".format(AUTH_ADFS["TENANT_ID"])

DERIVED_PERMISSIONS_PATH = os.path.join(
    BASE_DIR, "portal_web", "apps", "users", "permissions", "derived_permissions.yml"
)

ANONYMOUS_USER_NAME = "AnonymousUser"

PERM_TYPES = {
    "ADD": "add",
    "CHANGE": "change",
    "DELETE": "delete",
    "VIEW": "view",
}

GRAPPELLI_ADMIN_TITLE = "..."

# Notification will be updated field deleted=True and the Notification will not removed from db:
DJANGO_NOTIFICATIONS_CONFIG = {
    "SOFT_DELETE": True,
    "USE_JSONFIELD": True,
}

NOTIFICATIONS_NOTIFICATION_MODEL = "custom_notifications.Notification"

UBIQUITY = {
    "PROTOCOL": env("UBIQUITY_PROTOCOL"),
    "HOST": env("UBIQUITY_HOST"),
    "DOMAIN": env("UBIQUITY_DOMAIN"),
    "USERNAME": env("UBIQUITY_USERNAME"),
    "PASSWORD": env("UBIQUITY_PASSWORD"),
}

GOOGLE_API_KEY = env("GOOGLE_API_KEY")

INLINECSS_CSS_LOADER = "django_inlinecss.css_loaders.StaticfilesFinderCSSLoader"

# Overrides (keep imports here otherwise overrides gets messy)
from rest_framework.test import APITestCase
from django.test import TestCase

APITestCase.__doc__ = ""
TestCase.__doc__ = ""
sys.modules["rest_framework.test"].APITestCase = APITestCase
sys.modules["rest_framework.test.APITestCase"] = APITestCase
sys.modules["django.test"].TestCase = TestCase
sys.modules["django.test.TestCase"] = TestCase

TINYMCE_DEFAULT_CONFIG = {
    "theme": "silver",
    "height": 400,
    "width": 1200,
    "menubar": False,
    "plugins": "advlist, autosave, autolink, lists, link, image, imagetools, charmap, print, preview, anchor, searchreplace, "
    "visualblocks, emoticons, code, fullscreen, insertdatetime, media, paste, help, pagebreak, wordcount",
    "toolbar": "undo redo | formatselect | bold italic underline forecolor backcolor removeformat "
    "| alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | image media emoticons "
    "charmap visualblocks pagebreak | preview | fullscreen | help",
    "language": "it_IT",
    "content_css": "/static/css/article-detail.css",
    "images_upload_url": "/upload_image/",
}
TINYMCE_SPELLCHECKER = True
X_FRAME_OPTIONS = "SAMEORIGIN"

LOGIN_URL = "django_auth_adfs:login"
LOGIN_REDIRECT_URL = "/"
LOGOUT_REDIRECT_URL = "/login"

I yet have t provide some logs, i will provide them asap

JonasKs commented 2 years ago

Please use 3x ` to wrap code.

bilde equals

MY_DICT = {}
NikPiermafrost commented 2 years ago

Sorry, i edited the comment to have the code. It should be ok now and thanks for the response

NikPiermafrost commented 2 years ago

So! After further research, it was not the librery which caused the issue, it actually behaved as intended! What was missing instead was the whitenoise middleware for static content serving (which gunicorn doesn't do by default), So it treated all content requests as unautorized requests redirecting all my requests to index (as intended)

Putting the whitenoise middleware to action solved the issue immediately, thanks for your time anyway!

JonasKs commented 2 years ago

Awesome! Glad you got it working. Have a nice weekend 😊