django-project-core-settings 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_project_core_settings-0.1.0/MANIFEST.in +3 -0
- django_project_core_settings-0.1.0/PKG-INFO +241 -0
- django_project_core_settings-0.1.0/README.md +214 -0
- django_project_core_settings-0.1.0/django_project_core_settings/SETTINGS.md +148 -0
- django_project_core_settings-0.1.0/django_project_core_settings/__init__.py +13 -0
- django_project_core_settings-0.1.0/django_project_core_settings/__pycache__/__init__.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/__pycache__/base.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/__pycache__/dev.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/base.py +51 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/__init__.py +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/__pycache__/__init__.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/__pycache__/apps.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/__pycache__/auth.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/__pycache__/cache.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/__pycache__/core.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/__pycache__/csp.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/__pycache__/database.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/__pycache__/email.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/__pycache__/logging.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/__pycache__/middleware.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/__pycache__/rate_limit.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/__pycache__/sauth.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/__pycache__/security.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/__pycache__/static.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/apps.py +18 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/auth.py +14 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/cache.py +12 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/core.py +7 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/csp.py +10 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/database.py +17 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/email.py +12 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/logging.py +107 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/middleware.py +12 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/rate_limit.py +9 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/sauth.py +21 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/security.py +19 -0
- django_project_core_settings-0.1.0/django_project_core_settings/components/static.py +14 -0
- django_project_core_settings-0.1.0/django_project_core_settings/dev.py +23 -0
- django_project_core_settings-0.1.0/django_project_core_settings/local.py +9 -0
- django_project_core_settings-0.1.0/django_project_core_settings/prod.py +26 -0
- django_project_core_settings-0.1.0/django_project_core_settings/utils/__init__.py +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/utils/__pycache__/__init__.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/utils/__pycache__/env.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/utils/__pycache__/path_validator.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/utils/__pycache__/paths.cpython-314.pyc +0 -0
- django_project_core_settings-0.1.0/django_project_core_settings/utils/env.py +48 -0
- django_project_core_settings-0.1.0/django_project_core_settings/utils/path_validator.py +27 -0
- django_project_core_settings-0.1.0/django_project_core_settings/utils/paths.py +12 -0
- django_project_core_settings-0.1.0/django_project_core_settings.egg-info/PKG-INFO +241 -0
- django_project_core_settings-0.1.0/django_project_core_settings.egg-info/SOURCES.txt +53 -0
- django_project_core_settings-0.1.0/django_project_core_settings.egg-info/dependency_links.txt +1 -0
- django_project_core_settings-0.1.0/django_project_core_settings.egg-info/requires.txt +8 -0
- django_project_core_settings-0.1.0/django_project_core_settings.egg-info/top_level.txt +1 -0
- django_project_core_settings-0.1.0/pyproject.toml +42 -0
- django_project_core_settings-0.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django-project-core-settings
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Production-ready modular Django settings with strong security defaults
|
|
5
|
+
Author-email: Wilfred <wilfredpine9@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/wilfredpine/django-project-core-settings
|
|
8
|
+
Project-URL: Repository, https://github.com/wilfredpine/django-project-core-settings
|
|
9
|
+
Keywords: django,settings,security,modular
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Framework :: Django
|
|
12
|
+
Classifier: Framework :: Django :: 4.2
|
|
13
|
+
Classifier: Framework :: Django :: 5.0
|
|
14
|
+
Classifier: Framework :: Django :: 5.1
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
Requires-Dist: Django>=4.2
|
|
20
|
+
Requires-Dist: python-dotenv>=1.0
|
|
21
|
+
Requires-Dist: whitenoise>=6.0
|
|
22
|
+
Requires-Dist: django-axes>=6.0
|
|
23
|
+
Requires-Dist: django-ratelimit>=4.0
|
|
24
|
+
Requires-Dist: django-redis>=5.0
|
|
25
|
+
Requires-Dist: python-json-logger>=2.0
|
|
26
|
+
Requires-Dist: django-did-auth>=0.1
|
|
27
|
+
|
|
28
|
+
# django-project-core-settings
|
|
29
|
+
|
|
30
|
+
**Production-ready, modular, and secure Django settings package.**
|
|
31
|
+
|
|
32
|
+
This package provides a clean, maintainable, and highly secure base configuration for Django projects. It follows Django best practices and OWASP recommendations, making it easy to start new projects with strong security defaults.
|
|
33
|
+
|
|
34
|
+
## Features
|
|
35
|
+
|
|
36
|
+
- **Fully environment-driven** configuration using `.env`
|
|
37
|
+
- **Modular architecture** — settings split into logical components
|
|
38
|
+
- **Multiple environments** support: `dev`, `prod`, and `local`
|
|
39
|
+
- **Strong security defaults**:
|
|
40
|
+
- HSTS with preload
|
|
41
|
+
- Secure cookies (`HttpOnly`, `SameSite=Strict`)
|
|
42
|
+
- CSP (Content Security Policy)
|
|
43
|
+
- Argon2 password hashing
|
|
44
|
+
- Brute-force protection (`django-axes`)
|
|
45
|
+
- Rate limiting (`django-ratelimit`)
|
|
46
|
+
- **Structured JSON logging** (app, security, and error logs)
|
|
47
|
+
- **WhiteNoise** integration for static files
|
|
48
|
+
- **Redis cache** support
|
|
49
|
+
- **Easy extensibility** via `EXTRA_INSTALLED_APPS` and `EXTRA_MIDDLEWARE`
|
|
50
|
+
- **SAUTH** ready (custom authentication app)
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install django-project-core-settings
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
# Quick Start
|
|
59
|
+
Create your project settings file:
|
|
60
|
+
```python
|
|
61
|
+
# myproject/settings.py
|
|
62
|
+
from django_project_core_settings import *
|
|
63
|
+
|
|
64
|
+
from django_project_core_settings.utils.env import get_list_env
|
|
65
|
+
|
|
66
|
+
# === Extend with your apps ===
|
|
67
|
+
INSTALLED_APPS += [
|
|
68
|
+
'users',
|
|
69
|
+
# 'blog',
|
|
70
|
+
# 'portfolio',
|
|
71
|
+
# 'ckeditor',
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
MIDDLEWARE += [
|
|
75
|
+
# 'your.middleware.Class',
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
# === Common overrides ===
|
|
79
|
+
LOGIN_REDIRECT_URL = '/dashboard/'
|
|
80
|
+
ROOT_URLCONF = 'config.urls'
|
|
81
|
+
WSGI_APPLICATION = 'config.wsgi.application'
|
|
82
|
+
|
|
83
|
+
# === Security & Domain ===
|
|
84
|
+
ALLOWED_HOSTS = get_list_env("ALLOWED_HOSTS", ["localhost", "127.0.0.1"])
|
|
85
|
+
|
|
86
|
+
# Add frontend domains if needed
|
|
87
|
+
CSRF_TRUSTED_ORIGINS += [
|
|
88
|
+
"https://your-frontend.com",
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
# === default SAUTH config (can be overridden in dev/prod) ===
|
|
92
|
+
SAUTH = {
|
|
93
|
+
"LOGIN_REDIRECT": "/dashboard/",
|
|
94
|
+
"LOGOUT_REDIRECT": "/auth/login/",
|
|
95
|
+
"ROLES": {
|
|
96
|
+
"admin": "/dashboard/admin/",
|
|
97
|
+
"staff": "/dashboard/staff/",
|
|
98
|
+
"moderator": "/dashboard/moderator/",
|
|
99
|
+
"user": "/dashboard/",
|
|
100
|
+
},
|
|
101
|
+
"UI_FRAMEWORK": "tailwind",
|
|
102
|
+
"RATE_LIMIT": {
|
|
103
|
+
"LOGIN": "10/m",
|
|
104
|
+
"REGISTER": "5/m",
|
|
105
|
+
},
|
|
106
|
+
}
|
|
107
|
+
# =============================================
|
|
108
|
+
# === SAUTH Customization ===
|
|
109
|
+
SAUTH['ROLES'].update({
|
|
110
|
+
'editor': '/dashboard/editor/',
|
|
111
|
+
'author': '/dashboard/author/',
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
# Obscure admin URL
|
|
115
|
+
ADMIN_URL = 'hidden-admin-xyz123/'
|
|
116
|
+
# on your URL
|
|
117
|
+
# urlpatterns = [
|
|
118
|
+
# path(settings.ADMIN_URL, admin.site.urls),
|
|
119
|
+
# ]
|
|
120
|
+
|
|
121
|
+
# Additinal settings can be added here as needed
|
|
122
|
+
# E.g.
|
|
123
|
+
# Admin security
|
|
124
|
+
ADMIN_IP_WHITELIST = get_list_env("ADMIN_IP_WHITELIST", default=[])
|
|
125
|
+
mw = 'core.middleware.admin_security.AdminIPWhitelistMiddleware'
|
|
126
|
+
if mw not in MIDDLEWARE:
|
|
127
|
+
MIDDLEWARE.append(mw)
|
|
128
|
+
# Create these middleware and logic to restrict access to admin based on IP whitelist
|
|
129
|
+
# myproject/core/middleware/admin_security.py
|
|
130
|
+
'''
|
|
131
|
+
# core/middleware/admin_security.py
|
|
132
|
+
from django.conf import settings
|
|
133
|
+
from django.http import HttpResponseForbidden
|
|
134
|
+
from django_sauth.security.audit.logger import get_client_ip, audit_logger
|
|
135
|
+
class AdminIPWhitelistMiddleware:
|
|
136
|
+
def __init__(self, get_response):
|
|
137
|
+
self.get_response = get_response
|
|
138
|
+
self.admin_path = f"/{settings.ADMIN_URL.strip('/')}/"
|
|
139
|
+
def __call__(self, request):
|
|
140
|
+
# ✅ Skip in development
|
|
141
|
+
# if settings.DEBUG:
|
|
142
|
+
# return self.get_response(request)
|
|
143
|
+
path = request.path.rstrip("/") + "/"
|
|
144
|
+
if path.startswith(self.admin_path):
|
|
145
|
+
allowed_ips = [ip.strip() for ip in settings.ADMIN_IP_WHITELIST if ip.strip()]
|
|
146
|
+
if allowed_ips:
|
|
147
|
+
client_ip = get_client_ip(request)
|
|
148
|
+
if client_ip not in allowed_ips:
|
|
149
|
+
audit_logger.warning(
|
|
150
|
+
"admin_access_blocked",
|
|
151
|
+
extra={"ip": client_ip, "path": request.path}
|
|
152
|
+
)
|
|
153
|
+
return HttpResponseForbidden("Forbidden")
|
|
154
|
+
return self.get_response(request)'''
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Environment Variables (.env)
|
|
160
|
+
```env
|
|
161
|
+
# dev | prod | local
|
|
162
|
+
DJANGO_ENV=dev
|
|
163
|
+
SECRET_KEY='your-secret-key'
|
|
164
|
+
ALLOWED_HOSTS=localhost,127.0.0.1,yourdomain.com
|
|
165
|
+
CSRF_TRUSTED_ORIGINS=http://localhost:8000,https://yourdomain.com
|
|
166
|
+
REDIS_URL=redis://127.0.0.1:6379/1
|
|
167
|
+
|
|
168
|
+
EMAIL_HOST=smtp.gmail.com
|
|
169
|
+
EMAIL_USER=your-email@gmail.com
|
|
170
|
+
EMAIL_PASS=your-app-password
|
|
171
|
+
|
|
172
|
+
ADMIN_IP_WHITELIST=127.0.0.1,192.168.68.100
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Run Commands
|
|
176
|
+
```bash
|
|
177
|
+
# Development
|
|
178
|
+
DJANGO_ENV=dev python manage.py runserver
|
|
179
|
+
|
|
180
|
+
# Production check
|
|
181
|
+
DJANGO_ENV=prod python manage.py check
|
|
182
|
+
|
|
183
|
+
# Local development with debug tools
|
|
184
|
+
DJANGO_ENV=local python manage.py runserver
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Project Structure
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
django_project_core_settings/
|
|
191
|
+
├── base.py
|
|
192
|
+
├── dev.py
|
|
193
|
+
├── prod.py
|
|
194
|
+
├── local.py
|
|
195
|
+
├── components/
|
|
196
|
+
│ ├── apps.py
|
|
197
|
+
│ ├── auth.py
|
|
198
|
+
│ ├── security.py
|
|
199
|
+
│ ├── logging.py
|
|
200
|
+
│ └── ...
|
|
201
|
+
└── utils/
|
|
202
|
+
└── env.py
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
## What You Can Override
|
|
206
|
+
|
|
207
|
+
### Safe to override:
|
|
208
|
+
|
|
209
|
+
- `ALLOWED_HOSTS`, `CSRF_TRUSTED_ORIGINS`
|
|
210
|
+
- `SAUTH['ROLES']`
|
|
211
|
+
- `LOGIN_REDIRECT_URL`, `ROOT_URLCONF`, etc.
|
|
212
|
+
|
|
213
|
+
### Do NOT override directly:
|
|
214
|
+
|
|
215
|
+
- `SECRET_KEY`
|
|
216
|
+
- `AUTH_USER_MODEL`
|
|
217
|
+
- `AUTHENTICATION_BACKENDS`
|
|
218
|
+
- Core security headers (HSTS, secure cookies, etc.)
|
|
219
|
+
- `MIDDLEWARE` and `INSTALLED_APPS` base lists (use `MIDDLEWARE += []`, `INSTALLED_APPS += []` instead)
|
|
220
|
+
|
|
221
|
+
See full documentation: `SETTINGS.md`
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
## Logging
|
|
225
|
+
The package provides three log files in the `logs/` directory:
|
|
226
|
+
|
|
227
|
+
- `app.log` — General application logs
|
|
228
|
+
- `security.log` — Authentication, rate limiting, and security events (JSON in production)
|
|
229
|
+
- `error.log` — Error tracking
|
|
230
|
+
|
|
231
|
+
### Requirements
|
|
232
|
+
|
|
233
|
+
- Python 3.10+
|
|
234
|
+
- Django 4.2+
|
|
235
|
+
- `whitenoise`, `django-axes`, `django-ratelimit`, `django-redis`, `python-json-logger`
|
|
236
|
+
|
|
237
|
+
# License
|
|
238
|
+
MIT License
|
|
239
|
+
# Author
|
|
240
|
+
Wilfred
|
|
241
|
+
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# django-project-core-settings
|
|
2
|
+
|
|
3
|
+
**Production-ready, modular, and secure Django settings package.**
|
|
4
|
+
|
|
5
|
+
This package provides a clean, maintainable, and highly secure base configuration for Django projects. It follows Django best practices and OWASP recommendations, making it easy to start new projects with strong security defaults.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Fully environment-driven** configuration using `.env`
|
|
10
|
+
- **Modular architecture** — settings split into logical components
|
|
11
|
+
- **Multiple environments** support: `dev`, `prod`, and `local`
|
|
12
|
+
- **Strong security defaults**:
|
|
13
|
+
- HSTS with preload
|
|
14
|
+
- Secure cookies (`HttpOnly`, `SameSite=Strict`)
|
|
15
|
+
- CSP (Content Security Policy)
|
|
16
|
+
- Argon2 password hashing
|
|
17
|
+
- Brute-force protection (`django-axes`)
|
|
18
|
+
- Rate limiting (`django-ratelimit`)
|
|
19
|
+
- **Structured JSON logging** (app, security, and error logs)
|
|
20
|
+
- **WhiteNoise** integration for static files
|
|
21
|
+
- **Redis cache** support
|
|
22
|
+
- **Easy extensibility** via `EXTRA_INSTALLED_APPS` and `EXTRA_MIDDLEWARE`
|
|
23
|
+
- **SAUTH** ready (custom authentication app)
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
pip install django-project-core-settings
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
# Quick Start
|
|
32
|
+
Create your project settings file:
|
|
33
|
+
```python
|
|
34
|
+
# myproject/settings.py
|
|
35
|
+
from django_project_core_settings import *
|
|
36
|
+
|
|
37
|
+
from django_project_core_settings.utils.env import get_list_env
|
|
38
|
+
|
|
39
|
+
# === Extend with your apps ===
|
|
40
|
+
INSTALLED_APPS += [
|
|
41
|
+
'users',
|
|
42
|
+
# 'blog',
|
|
43
|
+
# 'portfolio',
|
|
44
|
+
# 'ckeditor',
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
MIDDLEWARE += [
|
|
48
|
+
# 'your.middleware.Class',
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
# === Common overrides ===
|
|
52
|
+
LOGIN_REDIRECT_URL = '/dashboard/'
|
|
53
|
+
ROOT_URLCONF = 'config.urls'
|
|
54
|
+
WSGI_APPLICATION = 'config.wsgi.application'
|
|
55
|
+
|
|
56
|
+
# === Security & Domain ===
|
|
57
|
+
ALLOWED_HOSTS = get_list_env("ALLOWED_HOSTS", ["localhost", "127.0.0.1"])
|
|
58
|
+
|
|
59
|
+
# Add frontend domains if needed
|
|
60
|
+
CSRF_TRUSTED_ORIGINS += [
|
|
61
|
+
"https://your-frontend.com",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
# === default SAUTH config (can be overridden in dev/prod) ===
|
|
65
|
+
SAUTH = {
|
|
66
|
+
"LOGIN_REDIRECT": "/dashboard/",
|
|
67
|
+
"LOGOUT_REDIRECT": "/auth/login/",
|
|
68
|
+
"ROLES": {
|
|
69
|
+
"admin": "/dashboard/admin/",
|
|
70
|
+
"staff": "/dashboard/staff/",
|
|
71
|
+
"moderator": "/dashboard/moderator/",
|
|
72
|
+
"user": "/dashboard/",
|
|
73
|
+
},
|
|
74
|
+
"UI_FRAMEWORK": "tailwind",
|
|
75
|
+
"RATE_LIMIT": {
|
|
76
|
+
"LOGIN": "10/m",
|
|
77
|
+
"REGISTER": "5/m",
|
|
78
|
+
},
|
|
79
|
+
}
|
|
80
|
+
# =============================================
|
|
81
|
+
# === SAUTH Customization ===
|
|
82
|
+
SAUTH['ROLES'].update({
|
|
83
|
+
'editor': '/dashboard/editor/',
|
|
84
|
+
'author': '/dashboard/author/',
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
# Obscure admin URL
|
|
88
|
+
ADMIN_URL = 'hidden-admin-xyz123/'
|
|
89
|
+
# on your URL
|
|
90
|
+
# urlpatterns = [
|
|
91
|
+
# path(settings.ADMIN_URL, admin.site.urls),
|
|
92
|
+
# ]
|
|
93
|
+
|
|
94
|
+
# Additinal settings can be added here as needed
|
|
95
|
+
# E.g.
|
|
96
|
+
# Admin security
|
|
97
|
+
ADMIN_IP_WHITELIST = get_list_env("ADMIN_IP_WHITELIST", default=[])
|
|
98
|
+
mw = 'core.middleware.admin_security.AdminIPWhitelistMiddleware'
|
|
99
|
+
if mw not in MIDDLEWARE:
|
|
100
|
+
MIDDLEWARE.append(mw)
|
|
101
|
+
# Create these middleware and logic to restrict access to admin based on IP whitelist
|
|
102
|
+
# myproject/core/middleware/admin_security.py
|
|
103
|
+
'''
|
|
104
|
+
# core/middleware/admin_security.py
|
|
105
|
+
from django.conf import settings
|
|
106
|
+
from django.http import HttpResponseForbidden
|
|
107
|
+
from django_sauth.security.audit.logger import get_client_ip, audit_logger
|
|
108
|
+
class AdminIPWhitelistMiddleware:
|
|
109
|
+
def __init__(self, get_response):
|
|
110
|
+
self.get_response = get_response
|
|
111
|
+
self.admin_path = f"/{settings.ADMIN_URL.strip('/')}/"
|
|
112
|
+
def __call__(self, request):
|
|
113
|
+
# ✅ Skip in development
|
|
114
|
+
# if settings.DEBUG:
|
|
115
|
+
# return self.get_response(request)
|
|
116
|
+
path = request.path.rstrip("/") + "/"
|
|
117
|
+
if path.startswith(self.admin_path):
|
|
118
|
+
allowed_ips = [ip.strip() for ip in settings.ADMIN_IP_WHITELIST if ip.strip()]
|
|
119
|
+
if allowed_ips:
|
|
120
|
+
client_ip = get_client_ip(request)
|
|
121
|
+
if client_ip not in allowed_ips:
|
|
122
|
+
audit_logger.warning(
|
|
123
|
+
"admin_access_blocked",
|
|
124
|
+
extra={"ip": client_ip, "path": request.path}
|
|
125
|
+
)
|
|
126
|
+
return HttpResponseForbidden("Forbidden")
|
|
127
|
+
return self.get_response(request)'''
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Environment Variables (.env)
|
|
133
|
+
```env
|
|
134
|
+
# dev | prod | local
|
|
135
|
+
DJANGO_ENV=dev
|
|
136
|
+
SECRET_KEY='your-secret-key'
|
|
137
|
+
ALLOWED_HOSTS=localhost,127.0.0.1,yourdomain.com
|
|
138
|
+
CSRF_TRUSTED_ORIGINS=http://localhost:8000,https://yourdomain.com
|
|
139
|
+
REDIS_URL=redis://127.0.0.1:6379/1
|
|
140
|
+
|
|
141
|
+
EMAIL_HOST=smtp.gmail.com
|
|
142
|
+
EMAIL_USER=your-email@gmail.com
|
|
143
|
+
EMAIL_PASS=your-app-password
|
|
144
|
+
|
|
145
|
+
ADMIN_IP_WHITELIST=127.0.0.1,192.168.68.100
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Run Commands
|
|
149
|
+
```bash
|
|
150
|
+
# Development
|
|
151
|
+
DJANGO_ENV=dev python manage.py runserver
|
|
152
|
+
|
|
153
|
+
# Production check
|
|
154
|
+
DJANGO_ENV=prod python manage.py check
|
|
155
|
+
|
|
156
|
+
# Local development with debug tools
|
|
157
|
+
DJANGO_ENV=local python manage.py runserver
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Project Structure
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
django_project_core_settings/
|
|
164
|
+
├── base.py
|
|
165
|
+
├── dev.py
|
|
166
|
+
├── prod.py
|
|
167
|
+
├── local.py
|
|
168
|
+
├── components/
|
|
169
|
+
│ ├── apps.py
|
|
170
|
+
│ ├── auth.py
|
|
171
|
+
│ ├── security.py
|
|
172
|
+
│ ├── logging.py
|
|
173
|
+
│ └── ...
|
|
174
|
+
└── utils/
|
|
175
|
+
└── env.py
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## What You Can Override
|
|
179
|
+
|
|
180
|
+
### Safe to override:
|
|
181
|
+
|
|
182
|
+
- `ALLOWED_HOSTS`, `CSRF_TRUSTED_ORIGINS`
|
|
183
|
+
- `SAUTH['ROLES']`
|
|
184
|
+
- `LOGIN_REDIRECT_URL`, `ROOT_URLCONF`, etc.
|
|
185
|
+
|
|
186
|
+
### Do NOT override directly:
|
|
187
|
+
|
|
188
|
+
- `SECRET_KEY`
|
|
189
|
+
- `AUTH_USER_MODEL`
|
|
190
|
+
- `AUTHENTICATION_BACKENDS`
|
|
191
|
+
- Core security headers (HSTS, secure cookies, etc.)
|
|
192
|
+
- `MIDDLEWARE` and `INSTALLED_APPS` base lists (use `MIDDLEWARE += []`, `INSTALLED_APPS += []` instead)
|
|
193
|
+
|
|
194
|
+
See full documentation: `SETTINGS.md`
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
## Logging
|
|
198
|
+
The package provides three log files in the `logs/` directory:
|
|
199
|
+
|
|
200
|
+
- `app.log` — General application logs
|
|
201
|
+
- `security.log` — Authentication, rate limiting, and security events (JSON in production)
|
|
202
|
+
- `error.log` — Error tracking
|
|
203
|
+
|
|
204
|
+
### Requirements
|
|
205
|
+
|
|
206
|
+
- Python 3.10+
|
|
207
|
+
- Django 4.2+
|
|
208
|
+
- `whitenoise`, `django-axes`, `django-ratelimit`, `django-redis`, `python-json-logger`
|
|
209
|
+
|
|
210
|
+
# License
|
|
211
|
+
MIT License
|
|
212
|
+
# Author
|
|
213
|
+
Wilfred
|
|
214
|
+
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
# django-project-core-settings - Configuration Guide
|
|
2
|
+
|
|
3
|
+
Production-ready modular Django settings with strong security defaults.
|
|
4
|
+
|
|
5
|
+
## Features Summary
|
|
6
|
+
|
|
7
|
+
- Environment-based configuration (`dev` / `prod` / `local`)
|
|
8
|
+
- Strong security hardening by default
|
|
9
|
+
- Plug-and-play extensibility
|
|
10
|
+
- Structured logging with JSON support
|
|
11
|
+
- SAUTH integration ready
|
|
12
|
+
|
|
13
|
+
## Recommended Usage Pattern
|
|
14
|
+
|
|
15
|
+
```python
|
|
16
|
+
# myproject/settings.py
|
|
17
|
+
from django_project_core_settings import *
|
|
18
|
+
|
|
19
|
+
from django_project_core_settings.utils.env import get_list_env
|
|
20
|
+
|
|
21
|
+
# === Extend with your apps ===
|
|
22
|
+
INSTALLED_APPS += [
|
|
23
|
+
'users',
|
|
24
|
+
# 'blog',
|
|
25
|
+
# 'portfolio',
|
|
26
|
+
# 'ckeditor',
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
MIDDLEWARE += [
|
|
30
|
+
# 'your.middleware.Class',
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
# === Common overrides ===
|
|
34
|
+
LOGIN_REDIRECT_URL = '/dashboard/'
|
|
35
|
+
ROOT_URLCONF = 'config.urls'
|
|
36
|
+
WSGI_APPLICATION = 'config.wsgi.application'
|
|
37
|
+
|
|
38
|
+
# === Security & Domain ===
|
|
39
|
+
ALLOWED_HOSTS = get_list_env("ALLOWED_HOSTS", ["localhost", "127.0.0.1"])
|
|
40
|
+
|
|
41
|
+
# Add frontend domains if needed
|
|
42
|
+
CSRF_TRUSTED_ORIGINS += [
|
|
43
|
+
"https://your-frontend.com",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
# === default SAUTH config (can be overridden in dev/prod) ===
|
|
47
|
+
SAUTH = {
|
|
48
|
+
"LOGIN_REDIRECT": "/dashboard/",
|
|
49
|
+
"LOGOUT_REDIRECT": "/auth/login/",
|
|
50
|
+
"ROLES": {
|
|
51
|
+
"admin": "/dashboard/admin/",
|
|
52
|
+
"staff": "/dashboard/staff/",
|
|
53
|
+
"moderator": "/dashboard/moderator/",
|
|
54
|
+
"user": "/dashboard/",
|
|
55
|
+
},
|
|
56
|
+
"UI_FRAMEWORK": "tailwind",
|
|
57
|
+
"RATE_LIMIT": {
|
|
58
|
+
"LOGIN": "10/m",
|
|
59
|
+
"REGISTER": "5/m",
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
# =============================================
|
|
63
|
+
# === SAUTH Customization ===
|
|
64
|
+
SAUTH['ROLES'].update({
|
|
65
|
+
'editor': '/dashboard/editor/',
|
|
66
|
+
'author': '/dashboard/author/',
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
# Obscure admin URL
|
|
70
|
+
ADMIN_URL = 'hidden-admin-xyz123/'
|
|
71
|
+
# on your URL
|
|
72
|
+
# urlpatterns = [
|
|
73
|
+
# path(settings.ADMIN_URL, admin.site.urls),
|
|
74
|
+
# ]
|
|
75
|
+
|
|
76
|
+
# Additinal settings can be added here as needed
|
|
77
|
+
# E.g.
|
|
78
|
+
# Admin security
|
|
79
|
+
ADMIN_IP_WHITELIST = get_list_env("ADMIN_IP_WHITELIST", default=[])
|
|
80
|
+
mw = 'core.middleware.admin_security.AdminIPWhitelistMiddleware'
|
|
81
|
+
if mw not in MIDDLEWARE:
|
|
82
|
+
MIDDLEWARE.append(mw)
|
|
83
|
+
# Create these middleware and logic to restrict access to admin based on IP whitelist
|
|
84
|
+
# myproject/core/middleware/admin_security.py
|
|
85
|
+
'''
|
|
86
|
+
# core/middleware/admin_security.py
|
|
87
|
+
from django.conf import settings
|
|
88
|
+
from django.http import HttpResponseForbidden
|
|
89
|
+
from django_sauth.security.audit.logger import get_client_ip, audit_logger
|
|
90
|
+
class AdminIPWhitelistMiddleware:
|
|
91
|
+
def __init__(self, get_response):
|
|
92
|
+
self.get_response = get_response
|
|
93
|
+
self.admin_path = f"/{settings.ADMIN_URL.strip('/')}/"
|
|
94
|
+
def __call__(self, request):
|
|
95
|
+
# ✅ Skip in development
|
|
96
|
+
# if settings.DEBUG:
|
|
97
|
+
# return self.get_response(request)
|
|
98
|
+
path = request.path.rstrip("/") + "/"
|
|
99
|
+
if path.startswith(self.admin_path):
|
|
100
|
+
allowed_ips = [ip.strip() for ip in settings.ADMIN_IP_WHITELIST if ip.strip()]
|
|
101
|
+
if allowed_ips:
|
|
102
|
+
client_ip = get_client_ip(request)
|
|
103
|
+
if client_ip not in allowed_ips:
|
|
104
|
+
audit_logger.warning(
|
|
105
|
+
"admin_access_blocked",
|
|
106
|
+
extra={"ip": client_ip, "path": request.path}
|
|
107
|
+
)
|
|
108
|
+
return HttpResponseForbidden("Forbidden")
|
|
109
|
+
return self.get_response(request)'''
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Environment Variables
|
|
114
|
+
See `.env.example` or use the following:
|
|
115
|
+
```env
|
|
116
|
+
# dev | prod | local
|
|
117
|
+
DJANGO_ENV=dev
|
|
118
|
+
SECRET_KEY='your-secret-key'
|
|
119
|
+
ALLOWED_HOSTS=localhost,127.0.0.1,yourdomain.com
|
|
120
|
+
CSRF_TRUSTED_ORIGINS=http://localhost:8000,https://yourdomain.com
|
|
121
|
+
REDIS_URL=redis://127.0.0.1:6379/1
|
|
122
|
+
|
|
123
|
+
EMAIL_HOST=smtp.gmail.com
|
|
124
|
+
EMAIL_USER=your-email@gmail.com
|
|
125
|
+
EMAIL_PASS=your-app-password
|
|
126
|
+
|
|
127
|
+
ADMIN_IP_WHITELIST=127.0.0.1,192.168.68.100
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## What Should NOT Be Overridden
|
|
131
|
+
- `SECRET_KEY`
|
|
132
|
+
- `DEBUG` (controlled by `DJANGO_ENV`)
|
|
133
|
+
- `AUTH_USER_MODEL`
|
|
134
|
+
- `AUTHENTICATION_BACKENDS`
|
|
135
|
+
- Core `MIDDLEWARE` order (use `MIDDLEWARE += []` )
|
|
136
|
+
- Security settings like `SECURE_HSTS_SECONDS`, `SESSION_COOKIE_SECURE`, etc.
|
|
137
|
+
|
|
138
|
+
## Testing Settings
|
|
139
|
+
```bash
|
|
140
|
+
DJANGO_ENV=dev python manage.py check
|
|
141
|
+
DJANGO_ENV=prod python manage.py check
|
|
142
|
+
```
|
|
143
|
+
## Logging Locations
|
|
144
|
+
|
|
145
|
+
- `logs/app.log`
|
|
146
|
+
- `logs/security.log` (important for login attempts, lockouts)
|
|
147
|
+
- `logs/error.log`
|
|
148
|
+
|
django_project_core_settings-0.1.0/django_project_core_settings/__pycache__/__init__.cpython-314.pyc
ADDED
|
Binary file
|
django_project_core_settings-0.1.0/django_project_core_settings/__pycache__/base.cpython-314.pyc
ADDED
|
Binary file
|
django_project_core_settings-0.1.0/django_project_core_settings/__pycache__/dev.cpython-314.pyc
ADDED
|
Binary file
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# settings/base.py
|
|
2
|
+
from .utils.paths import BASE_DIR
|
|
3
|
+
|
|
4
|
+
from .utils.path_validator import ensure_dirs
|
|
5
|
+
|
|
6
|
+
# 📁 Ensure core directories exist
|
|
7
|
+
ensure_dirs(
|
|
8
|
+
BASE_DIR / "logs",
|
|
9
|
+
BASE_DIR / "media",
|
|
10
|
+
BASE_DIR / "staticfiles",
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
# =============================================
|
|
14
|
+
# CORE SETTINGS
|
|
15
|
+
# =============================================
|
|
16
|
+
from .components.core import *
|
|
17
|
+
from .components.apps import *
|
|
18
|
+
from .components.middleware import *
|
|
19
|
+
from .components.auth import *
|
|
20
|
+
from .components.sauth import *
|
|
21
|
+
from .components.database import *
|
|
22
|
+
from .components.cache import *
|
|
23
|
+
from .components.rate_limit import *
|
|
24
|
+
from .components.security import *
|
|
25
|
+
from .components.csp import *
|
|
26
|
+
from .components.static import *
|
|
27
|
+
from .components.email import *
|
|
28
|
+
from .components.logging import *
|
|
29
|
+
|
|
30
|
+
# =============================================
|
|
31
|
+
# TEMPLATES
|
|
32
|
+
# =============================================
|
|
33
|
+
TEMPLATES = [
|
|
34
|
+
{
|
|
35
|
+
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
|
36
|
+
'DIRS': [BASE_DIR / "templates"],
|
|
37
|
+
'APP_DIRS': True,
|
|
38
|
+
'OPTIONS': {
|
|
39
|
+
'context_processors': [
|
|
40
|
+
'django.template.context_processors.request',
|
|
41
|
+
'django.contrib.auth.context_processors.auth',
|
|
42
|
+
'django.contrib.messages.context_processors.messages',
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
ROOT_URLCONF = "project_core.urls"
|
|
49
|
+
WSGI_APPLICATION = "project_core.wsgi.application"
|
|
50
|
+
SITE_ID = 1
|
|
51
|
+
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|