oua-auth 0.3.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.
- oua_auth-0.3.0/LICENSE +21 -0
- oua_auth-0.3.0/MANIFEST.in +5 -0
- oua_auth-0.3.0/PKG-INFO +533 -0
- oua_auth-0.3.0/README.md +469 -0
- oua_auth-0.3.0/SECURITY.md +156 -0
- oua_auth-0.3.0/docs/README.md +49 -0
- oua_auth-0.3.0/docs/configuration.md +450 -0
- oua_auth-0.3.0/docs/index.md +83 -0
- oua_auth-0.3.0/docs/integration_guide.md +1110 -0
- oua_auth-0.3.0/docs/quick_reference.md +569 -0
- oua_auth-0.3.0/docs/security_best_practices.md +324 -0
- oua_auth-0.3.0/docs/troubleshooting.md +922 -0
- oua_auth-0.3.0/oua_auth/__init__.py +57 -0
- oua_auth-0.3.0/oua_auth/admin.py +231 -0
- oua_auth-0.3.0/oua_auth/apps.py +66 -0
- oua_auth-0.3.0/oua_auth/authentication.py +1015 -0
- oua_auth-0.3.0/oua_auth/backend.py +177 -0
- oua_auth-0.3.0/oua_auth/logging_init.py +58 -0
- oua_auth-0.3.0/oua_auth/logging_utils.py +481 -0
- oua_auth-0.3.0/oua_auth/management/__init__.py +1 -0
- oua_auth-0.3.0/oua_auth/management/commands/__init__.py +1 -0
- oua_auth-0.3.0/oua_auth/management/commands/clean_expired_tokens.py +42 -0
- oua_auth-0.3.0/oua_auth/middleware.py +700 -0
- oua_auth-0.3.0/oua_auth/migrations/0001_initial.py +46 -0
- oua_auth-0.3.0/oua_auth/migrations/0002_suspicious_activity_and_user_security.py +109 -0
- oua_auth-0.3.0/oua_auth/migrations/__init__.py +1 -0
- oua_auth-0.3.0/oua_auth/models.py +233 -0
- oua_auth-0.3.0/oua_auth/security_middleware.py +96 -0
- oua_auth-0.3.0/oua_auth/token_blacklist.py +78 -0
- oua_auth-0.3.0/oua_auth.egg-info/PKG-INFO +533 -0
- oua_auth-0.3.0/oua_auth.egg-info/SOURCES.txt +59 -0
- oua_auth-0.3.0/oua_auth.egg-info/dependency_links.txt +1 -0
- oua_auth-0.3.0/oua_auth.egg-info/not-zip-safe +1 -0
- oua_auth-0.3.0/oua_auth.egg-info/requires.txt +26 -0
- oua_auth-0.3.0/oua_auth.egg-info/top_level.txt +2 -0
- oua_auth-0.3.0/pyproject.toml +3 -0
- oua_auth-0.3.0/setup.cfg +4 -0
- oua_auth-0.3.0/setup.py +69 -0
- oua_auth-0.3.0/tests/__init__.py +1 -0
- oua_auth-0.3.0/tests/conftest.py +296 -0
- oua_auth-0.3.0/tests/settings.py +82 -0
- oua_auth-0.3.0/tests/test_admin.py +343 -0
- oua_auth-0.3.0/tests/test_admin_integration.py +195 -0
- oua_auth-0.3.0/tests/test_api_integration.py +412 -0
- oua_auth-0.3.0/tests/test_apps.py +110 -0
- oua_auth-0.3.0/tests/test_authentication.py +539 -0
- oua_auth-0.3.0/tests/test_authentication_admin.py +192 -0
- oua_auth-0.3.0/tests/test_authentication_extended.py +1029 -0
- oua_auth-0.3.0/tests/test_backend.py +290 -0
- oua_auth-0.3.0/tests/test_command_clean_expired_tokens.py +129 -0
- oua_auth-0.3.0/tests/test_integration.py +393 -0
- oua_auth-0.3.0/tests/test_logging.py +184 -0
- oua_auth-0.3.0/tests/test_logging_init.py +115 -0
- oua_auth-0.3.0/tests/test_logging_utils.py +241 -0
- oua_auth-0.3.0/tests/test_middleware.py +510 -0
- oua_auth-0.3.0/tests/test_middleware_integration.py +213 -0
- oua_auth-0.3.0/tests/test_security_middleware.py +137 -0
- oua_auth-0.3.0/tests/test_token_blacklist.py +341 -0
- oua_auth-0.3.0/tests/test_token_blacklist_memory.py +80 -0
- oua_auth-0.3.0/tests/test_user_security_profile.py +119 -0
- oua_auth-0.3.0/tests/urls.py +37 -0
oua_auth-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Organization Unified Access
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
oua_auth-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: oua-auth
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: A Django authentication middleware package for integrating with OUA SSO server
|
|
5
|
+
Home-page: https://gitlab.com/lexnjugz/Organization_Unified_Access_Authentication
|
|
6
|
+
Author: Organization Unified Access
|
|
7
|
+
Author-email: alexmungai964@gmail.com
|
|
8
|
+
Classifier: Development Status :: 4 - Beta
|
|
9
|
+
Classifier: Environment :: Web Environment
|
|
10
|
+
Classifier: Framework :: Django
|
|
11
|
+
Classifier: Framework :: Django :: 3.2
|
|
12
|
+
Classifier: Framework :: Django :: 4.0
|
|
13
|
+
Classifier: Framework :: Django :: 4.1
|
|
14
|
+
Classifier: Framework :: Django :: 4.2
|
|
15
|
+
Classifier: Framework :: Django :: 5.0
|
|
16
|
+
Classifier: Framework :: Django :: 5.1
|
|
17
|
+
Classifier: Intended Audience :: Developers
|
|
18
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Internet :: WWW/HTTP
|
|
24
|
+
Classifier: Topic :: Security
|
|
25
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
26
|
+
Requires-Python: >=3.11
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
License-File: LICENSE
|
|
29
|
+
Requires-Dist: Django>=3.2
|
|
30
|
+
Requires-Dist: python-jose>=3.3.0
|
|
31
|
+
Requires-Dist: bleach>=5.0.0
|
|
32
|
+
Requires-Dist: requests>=2.25.0
|
|
33
|
+
Requires-Dist: djangorestframework>=3.12.0
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-django>=4.7.0; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-mock>=3.14.0; extra == "dev"
|
|
39
|
+
Requires-Dist: PyJWT>=2.6.0; extra == "dev"
|
|
40
|
+
Requires-Dist: cryptography>=41.0.0; extra == "dev"
|
|
41
|
+
Requires-Dist: black>=24.2.0; extra == "dev"
|
|
42
|
+
Requires-Dist: isort>=5.12.0; extra == "dev"
|
|
43
|
+
Requires-Dist: flake8>=7.0.0; extra == "dev"
|
|
44
|
+
Requires-Dist: build>=1.0.3; extra == "dev"
|
|
45
|
+
Requires-Dist: twine>=5.0.0; extra == "dev"
|
|
46
|
+
Provides-Extra: test
|
|
47
|
+
Requires-Dist: pytest>=8.0.0; extra == "test"
|
|
48
|
+
Requires-Dist: pytest-django>=4.7.0; extra == "test"
|
|
49
|
+
Requires-Dist: pytest-cov>=4.1.0; extra == "test"
|
|
50
|
+
Requires-Dist: pytest-mock>=3.14.0; extra == "test"
|
|
51
|
+
Requires-Dist: PyJWT>=2.6.0; extra == "test"
|
|
52
|
+
Requires-Dist: cryptography>=41.0.0; extra == "test"
|
|
53
|
+
Dynamic: author
|
|
54
|
+
Dynamic: author-email
|
|
55
|
+
Dynamic: classifier
|
|
56
|
+
Dynamic: description
|
|
57
|
+
Dynamic: description-content-type
|
|
58
|
+
Dynamic: home-page
|
|
59
|
+
Dynamic: license-file
|
|
60
|
+
Dynamic: provides-extra
|
|
61
|
+
Dynamic: requires-dist
|
|
62
|
+
Dynamic: requires-python
|
|
63
|
+
Dynamic: summary
|
|
64
|
+
|
|
65
|
+
# Organization Unified Access Authentication
|
|
66
|
+
|
|
67
|
+
A Django authentication middleware package for integrating with OrganizationUnifiedAccess (OUA) SSO server.
|
|
68
|
+
|
|
69
|
+
## Installation
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pip install oua-auth
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Configuration
|
|
76
|
+
|
|
77
|
+
Add the following settings to your Django settings.py:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
# OUA SSO Settings
|
|
81
|
+
OUA_SSO_URL = 'https://your-sso-server.com' # Your OUA SSO server URL
|
|
82
|
+
OUA_PUBLIC_KEY = '''
|
|
83
|
+
-----BEGIN PUBLIC KEY-----
|
|
84
|
+
Your SSO public key here
|
|
85
|
+
-----END PUBLIC KEY-----
|
|
86
|
+
'''
|
|
87
|
+
OUA_CLIENT_ID = 'your-client-id' # Your client ID from OUA SSO
|
|
88
|
+
|
|
89
|
+
# Optional: Paths to exclude from authentication
|
|
90
|
+
OUA_EXCLUDE_PATHS = [
|
|
91
|
+
'/public/',
|
|
92
|
+
'/api/health/',
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
# Security settings (recommended)
|
|
96
|
+
OUA_TRUSTED_ADMIN_DOMAINS = ['yourdomain.com'] # Domains allowed admin access
|
|
97
|
+
OUA_TRUSTED_ADMIN_EMAILS = ['admin@example.com'] # Specific emails allowed admin access
|
|
98
|
+
OUA_TOKEN_SIGNING_KEY = 'your-separate-signing-key' # For internal token generation
|
|
99
|
+
OUA_INTERNAL_TOKEN_LIFETIME = 3600 # 1 hour in seconds
|
|
100
|
+
OUA_REQUEST_TIMEOUT = 5 # Timeout for SSO requests in seconds
|
|
101
|
+
OUA_MAX_REQUESTS_PER_MINUTE = 60 # Rate limiting for SSO API requests
|
|
102
|
+
OUA_MAX_AUTH_FAILURES = 5 # Maximum number of authentication failures before rate limiting
|
|
103
|
+
OUA_AUTH_FAILURE_WINDOW = 300 # Time window for rate limiting (seconds)
|
|
104
|
+
|
|
105
|
+
# Rate limiting cache configuration (optional)
|
|
106
|
+
OUA_RATELIMIT_CACHE_PREFIX = "oua_auth_failure" # Prefix for cache keys
|
|
107
|
+
OUA_RATELIMIT_CACHE_TIMEOUT = 300 # Cache timeout for rate limit entries (seconds)
|
|
108
|
+
|
|
109
|
+
# User validation options (optional)
|
|
110
|
+
OUA_ALLOWED_DOMAINS = ['company.com', 'partner.org'] # Only these domains are allowed
|
|
111
|
+
OUA_RESTRICTED_DOMAINS = ['competitor.com', 'spam.org'] # These domains are blocked
|
|
112
|
+
OUA_REQUIRED_TOKEN_ATTRIBUTES = ['email', 'name', 'sub'] # Token must include these attributes
|
|
113
|
+
|
|
114
|
+
# Account locking (optional)
|
|
115
|
+
OUA_MAX_SUSPICIOUS_ACTIVITIES = 3 # Number of suspicious activities before account lock
|
|
116
|
+
OUA_SUSPICIOUS_ACTIVITY_WINDOW = 86400 # Time window for counting suspicious activities (seconds)
|
|
117
|
+
OUA_ACCOUNT_LOCK_DURATION = 86400 # How long accounts remain locked (seconds)
|
|
118
|
+
OUA_SUSPICIOUS_ACTIVITY_TYPES = [ # Activity types that count toward locking
|
|
119
|
+
'token_reuse',
|
|
120
|
+
'invalid_origin',
|
|
121
|
+
'unusual_location',
|
|
122
|
+
'multiple_failed_attempts'
|
|
123
|
+
]
|
|
124
|
+
|
|
125
|
+
# Add the authentication backend
|
|
126
|
+
AUTHENTICATION_BACKENDS = [
|
|
127
|
+
'oua_auth.OUAAuthBackend',
|
|
128
|
+
'django.contrib.auth.backends.ModelBackend', # Optional: Keep Django's default backend
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
# Add the middleware
|
|
132
|
+
MIDDLEWARE = [
|
|
133
|
+
# ... other middleware ...
|
|
134
|
+
'oua_auth.OUAAuthMiddleware',
|
|
135
|
+
'oua_auth.OUAUserMiddleware', # Optional: For user data sync
|
|
136
|
+
'oua_auth.SecurityHeadersMiddleware', # Optional: For security headers
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
# If using Django Rest Framework
|
|
140
|
+
REST_FRAMEWORK = {
|
|
141
|
+
'DEFAULT_AUTHENTICATION_CLASSES': [
|
|
142
|
+
'oua_auth.OUAJWTAuthentication',
|
|
143
|
+
'rest_framework.authentication.SessionAuthentication', # Optional
|
|
144
|
+
],
|
|
145
|
+
# ... other DRF settings
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
## Usage
|
|
150
|
+
|
|
151
|
+
### Authentication Flow
|
|
152
|
+
|
|
153
|
+
1. Your frontend obtains a JWT token from the OUA SSO server
|
|
154
|
+
2. Include the token in the Authorization header for API requests:
|
|
155
|
+
```
|
|
156
|
+
Authorization: Bearer <your-jwt-token>
|
|
157
|
+
```
|
|
158
|
+
3. The middleware will:
|
|
159
|
+
- Validate the JWT token
|
|
160
|
+
- Create/update the Django user based on the token claims
|
|
161
|
+
- Set request.user to the authenticated user
|
|
162
|
+
- Store the token and claims in request.oua_token and request.oua_claims
|
|
163
|
+
- Generate an internal token for added security
|
|
164
|
+
|
|
165
|
+
### Protecting Views
|
|
166
|
+
|
|
167
|
+
Use Django's standard authentication decorators:
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
from django.contrib.auth.decorators import login_required
|
|
171
|
+
|
|
172
|
+
@login_required
|
|
173
|
+
def protected_view(request):
|
|
174
|
+
# Only authenticated users can access this view
|
|
175
|
+
return HttpResponse("Hello " + request.user.email)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
For class-based views:
|
|
179
|
+
|
|
180
|
+
```python
|
|
181
|
+
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
182
|
+
|
|
183
|
+
class ProtectedView(LoginRequiredMixin, View):
|
|
184
|
+
def get(self, request):
|
|
185
|
+
return HttpResponse("Hello " + request.user.email)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### Accessing Token Claims
|
|
189
|
+
|
|
190
|
+
The middleware stores the decoded JWT claims in the request:
|
|
191
|
+
|
|
192
|
+
```python
|
|
193
|
+
def my_view(request):
|
|
194
|
+
if request.user.is_authenticated:
|
|
195
|
+
roles = request.oua_claims.get('roles', [])
|
|
196
|
+
if 'admin' in roles:
|
|
197
|
+
# Handle admin user
|
|
198
|
+
pass
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Using the Internal Token
|
|
202
|
+
|
|
203
|
+
For extra security, you can use the internal token for downstream services:
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
def api_call(request):
|
|
207
|
+
if request.user.is_authenticated:
|
|
208
|
+
# Use the internal token for internal service calls
|
|
209
|
+
internal_token = request.internal_token
|
|
210
|
+
response = requests.get(
|
|
211
|
+
'https://your-internal-service.com/api/resource',
|
|
212
|
+
headers={"Authorization": f"Bearer {internal_token}"},
|
|
213
|
+
)
|
|
214
|
+
return JsonResponse(response.json())
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Token Blacklisting
|
|
218
|
+
|
|
219
|
+
This package includes persistent token blacklisting to revoke access for specific tokens:
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
from oua_auth import OUAJWTAuthentication
|
|
223
|
+
|
|
224
|
+
def logout_user(request):
|
|
225
|
+
"""Revoke the current user's token and log them out."""
|
|
226
|
+
if hasattr(request, 'oua_token'):
|
|
227
|
+
# Blacklist the token
|
|
228
|
+
OUAJWTAuthentication.revoke_token(
|
|
229
|
+
token=request.oua_token,
|
|
230
|
+
blacklisted_by=request.user.email,
|
|
231
|
+
reason="User logout"
|
|
232
|
+
)
|
|
233
|
+
|
|
234
|
+
# Continue with standard Django logout
|
|
235
|
+
from django.contrib.auth import logout
|
|
236
|
+
logout(request)
|
|
237
|
+
return redirect('login')
|
|
238
|
+
|
|
239
|
+
def admin_revoke_token(request, user_id, token_id):
|
|
240
|
+
"""Admin functionality to revoke a specific user's token."""
|
|
241
|
+
if not request.user.is_staff:
|
|
242
|
+
return HttpResponseForbidden()
|
|
243
|
+
|
|
244
|
+
# Get the token from your token storage
|
|
245
|
+
token = get_token_by_id(token_id)
|
|
246
|
+
|
|
247
|
+
# Blacklist it
|
|
248
|
+
OUAJWTAuthentication.revoke_token(
|
|
249
|
+
token=token,
|
|
250
|
+
blacklisted_by=f"Admin: {request.user.email}",
|
|
251
|
+
reason=f"Admin revocation for user {user_id}"
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
return JsonResponse({"status": "success"})
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
The token blacklist is stored in the database using the `BlacklistedToken` model. Make sure to include `oua_auth` in your `INSTALLED_APPS` setting:
|
|
258
|
+
|
|
259
|
+
```python
|
|
260
|
+
INSTALLED_APPS = [
|
|
261
|
+
# ... other apps ...
|
|
262
|
+
'oua_auth',
|
|
263
|
+
# ... other apps ...
|
|
264
|
+
]
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
After adding the app, run migrations to create the token blacklist table:
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
python manage.py migrate oua_auth
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
The blacklist automatically cleans up expired tokens during validation checks to prevent database growth. You can also set up a periodic task to clean expired tokens:
|
|
274
|
+
|
|
275
|
+
```python
|
|
276
|
+
from django.core.management.base import BaseCommand
|
|
277
|
+
from oua_auth.models import BlacklistedToken
|
|
278
|
+
|
|
279
|
+
class Command(BaseCommand):
|
|
280
|
+
help = 'Clean expired tokens from the blacklist'
|
|
281
|
+
|
|
282
|
+
def handle(self, *args, **options):
|
|
283
|
+
count = BlacklistedToken.clean_expired_tokens()
|
|
284
|
+
self.stdout.write(self.style.SUCCESS(f'Removed {count} expired tokens from blacklist'))
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### Security Headers Middleware
|
|
288
|
+
|
|
289
|
+
The package includes a security headers middleware that adds recommended HTTP security headers to all responses:
|
|
290
|
+
|
|
291
|
+
```python
|
|
292
|
+
# Add the middleware to your MIDDLEWARE setting
|
|
293
|
+
MIDDLEWARE = [
|
|
294
|
+
# ... other middleware ...
|
|
295
|
+
'oua_auth.SecurityHeadersMiddleware',
|
|
296
|
+
]
|
|
297
|
+
|
|
298
|
+
# Optional: Configure security headers (these are the defaults)
|
|
299
|
+
OUA_CONTENT_SECURITY_POLICY = "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; script-src 'self'"
|
|
300
|
+
OUA_FRAME_OPTIONS = "SAMEORIGIN" # X-Frame-Options
|
|
301
|
+
OUA_XSS_PROTECTION = "1; mode=block" # X-XSS-Protection
|
|
302
|
+
OUA_CONTENT_TYPE_OPTIONS = "nosniff" # X-Content-Type-Options
|
|
303
|
+
OUA_REFERRER_POLICY = "strict-origin-when-cross-origin"
|
|
304
|
+
OUA_PERMISSIONS_POLICY = "geolocation=(), microphone=(), camera=(), payment=()"
|
|
305
|
+
|
|
306
|
+
# HSTS is disabled by default; enable and configure if your site uses HTTPS
|
|
307
|
+
OUA_ENABLE_HSTS = False # Set to True to enable HSTS
|
|
308
|
+
OUA_HSTS_SECONDS = 31536000 # 1 year
|
|
309
|
+
OUA_HSTS_INCLUDE_SUBDOMAINS = True
|
|
310
|
+
OUA_HSTS_PRELOAD = False
|
|
311
|
+
|
|
312
|
+
# Exclude paths from security headers (optional)
|
|
313
|
+
OUA_SECURITY_HEADERS_EXCLUDE_PATHS = ['/api/public/', '/healthcheck/']
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
This middleware helps protect against common web vulnerabilities:
|
|
317
|
+
|
|
318
|
+
- **Content Security Policy (CSP)**: Controls what resources can be loaded
|
|
319
|
+
- **X-Frame-Options**: Protects against clickjacking
|
|
320
|
+
- **X-XSS-Protection**: Enables browser's XSS filtering
|
|
321
|
+
- **X-Content-Type-Options**: Prevents MIME-type sniffing
|
|
322
|
+
- **Referrer-Policy**: Controls what information is sent in the Referer header
|
|
323
|
+
- **Permissions-Policy**: Restricts which browser features can be used
|
|
324
|
+
- **HTTP Strict Transport Security (HSTS)**: Forces secure connections
|
|
325
|
+
|
|
326
|
+
## Security Features
|
|
327
|
+
|
|
328
|
+
This package implements several security measures:
|
|
329
|
+
|
|
330
|
+
- **JWT Token Security**: RSA256 signature verification, expiration validation
|
|
331
|
+
- **Privilege Protection**: Admin roles only granted to trusted email domains/addresses
|
|
332
|
+
- **Input Validation**:
|
|
333
|
+
- Email format validation
|
|
334
|
+
- XSS protection using the `bleach` library to sanitize all user inputs
|
|
335
|
+
- HTML tag stripping and attribute filtering
|
|
336
|
+
- Input length limitations to prevent DoS attacks
|
|
337
|
+
- **Network Security**: HTTPS enforcement, connection pooling, timeout controls
|
|
338
|
+
- **Internal Tokens**: Separate signing key, unique token IDs, expiration control
|
|
339
|
+
- **Distributed Rate Limiting**:
|
|
340
|
+
- Cache-based tracking of authentication failures
|
|
341
|
+
- IP-based rate limiting that works across multiple servers/instances
|
|
342
|
+
- Configurable thresholds and time windows
|
|
343
|
+
- Automatic cleanup of old failure records
|
|
344
|
+
- **Token Blacklisting**: Persistent revocation of compromised tokens
|
|
345
|
+
- **Security Headers**: Protection against XSS, CSRF, clickjacking and other web vulnerabilities
|
|
346
|
+
- **Structured Logging**: Sanitized logging with sensitive data redaction
|
|
347
|
+
- **User Validation Rules**:
|
|
348
|
+
- Domain allowlisting and blocklisting for all users (not just admins)
|
|
349
|
+
- Required token attributes validation
|
|
350
|
+
- Automatic account locking after suspicious activity
|
|
351
|
+
- **Suspicious Activity Monitoring**:
|
|
352
|
+
- Tracking and logging of suspicious authentication activities
|
|
353
|
+
- Automatic account locking based on configurable thresholds
|
|
354
|
+
- Protection against brute force, token reuse, and unusual access patterns
|
|
355
|
+
|
|
356
|
+
See [SECURITY.md](SECURITY.md) for more details on security features and vulnerability reporting.
|
|
357
|
+
|
|
358
|
+
### User Validation and Security Configuration
|
|
359
|
+
|
|
360
|
+
The package includes enhanced user validation to control access and detect potentially malicious activities:
|
|
361
|
+
|
|
362
|
+
```python
|
|
363
|
+
# Domain Restrictions (Optional)
|
|
364
|
+
OUA_ALLOWED_DOMAINS = ['company.com', 'partner.org'] # Only these domains can access
|
|
365
|
+
OUA_RESTRICTED_DOMAINS = ['competitor.com'] # These domains are blocked
|
|
366
|
+
|
|
367
|
+
# Token Attribute Requirements (Optional)
|
|
368
|
+
OUA_REQUIRED_TOKEN_ATTRIBUTES = ['email', 'name', 'sub', 'groups']
|
|
369
|
+
|
|
370
|
+
# Account Locking Configuration
|
|
371
|
+
OUA_MAX_SUSPICIOUS_ACTIVITIES = 3 # Activities before locking
|
|
372
|
+
OUA_SUSPICIOUS_ACTIVITY_WINDOW = 86400 # 24 hour window
|
|
373
|
+
OUA_ACCOUNT_LOCK_DURATION = 86400 # Lock for 24 hours
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
These features provide several important security benefits:
|
|
377
|
+
|
|
378
|
+
1. **Domain Control**: Limit access to specific trusted domains or block known malicious domains
|
|
379
|
+
2. **Token Validation**: Ensure tokens contain all required claims for your application's needs
|
|
380
|
+
3. **Suspicious Activity Detection**: Identify and respond to unusual authentication patterns
|
|
381
|
+
4. **Account Protection**: Automatically lock accounts when suspicious behavior is detected
|
|
382
|
+
5. **Audit Trail**: Track all security events for compliance and forensic analysis
|
|
383
|
+
|
|
384
|
+
All security events are logged in a structured format and can be reviewed in the Django admin interface or forwarded to security information and event management (SIEM) systems.
|
|
385
|
+
|
|
386
|
+
### Rate Limiting Configuration
|
|
387
|
+
|
|
388
|
+
The package includes a distributed rate limiting system that uses Django's cache framework to prevent brute force attacks:
|
|
389
|
+
|
|
390
|
+
```python
|
|
391
|
+
# Rate Limiting Configuration (add to your settings.py)
|
|
392
|
+
OUA_MAX_AUTH_FAILURES = 5 # Maximum authentication failures before rate limiting
|
|
393
|
+
OUA_AUTH_FAILURE_WINDOW = 300 # Time window for counting failures (seconds)
|
|
394
|
+
|
|
395
|
+
# Cache backend settings (optional)
|
|
396
|
+
OUA_RATELIMIT_CACHE_PREFIX = "oua_auth_failure" # Prefix for cache keys
|
|
397
|
+
OUA_RATELIMIT_CACHE_TIMEOUT = 300 # Cache entry timeout (seconds)
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
For optimal security in production environments, configure Django's cache framework with a distributed backend:
|
|
401
|
+
|
|
402
|
+
```python
|
|
403
|
+
# Example: Redis cache backend (requires django-redis)
|
|
404
|
+
CACHES = {
|
|
405
|
+
"default": {
|
|
406
|
+
"BACKEND": "django_redis.cache.RedisCache",
|
|
407
|
+
"LOCATION": "redis://redis:6379/1",
|
|
408
|
+
"OPTIONS": {
|
|
409
|
+
"CLIENT_CLASS": "django_redis.client.DefaultClient",
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
# Example: Memcached backend
|
|
415
|
+
CACHES = {
|
|
416
|
+
'default': {
|
|
417
|
+
'BACKEND': 'django.core.cache.backends.memcached.PyMemcacheCache',
|
|
418
|
+
'LOCATION': '127.0.0.1:11211',
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
The rate limiting system:
|
|
424
|
+
|
|
425
|
+
- Tracks authentication failures by client IP address
|
|
426
|
+
- Blocks access after too many failed attempts
|
|
427
|
+
- Works across multiple server instances
|
|
428
|
+
- Automatically expires old failure records
|
|
429
|
+
- Provides detailed logging for security monitoring
|
|
430
|
+
|
|
431
|
+
### Structured Logging Configuration
|
|
432
|
+
|
|
433
|
+
The package includes a comprehensive logging system with structured log output and sensitive data redaction:
|
|
434
|
+
|
|
435
|
+
```python
|
|
436
|
+
# Logging Configuration (add to your settings.py)
|
|
437
|
+
OUA_LOG_LEVEL = "INFO" # Global log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
|
438
|
+
OUA_CONSOLE_LOG_LEVEL = "INFO" # Console-specific log level
|
|
439
|
+
OUA_FILE_LOG_LEVEL = "DEBUG" # File-specific log level
|
|
440
|
+
OUA_LOG_FILE = "/var/log/django/oua_auth.log" # Log file path (None for no file logging)
|
|
441
|
+
OUA_LOG_JSON = True # Output logs in JSON format for log aggregation systems
|
|
442
|
+
OUA_LOG_CONSOLE = True # Output logs to console
|
|
443
|
+
OUA_EAGER_LOGGING = False # Configure logging during import (vs. Django app initialization)
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
The logging system provides:
|
|
447
|
+
|
|
448
|
+
- **Structured JSON Output**: For better integration with log management systems like ELK, Splunk, or Graylog
|
|
449
|
+
- **Sensitive Data Redaction**: Automatically redacts tokens, passwords and other sensitive information
|
|
450
|
+
- **Contextual Information**: Includes request IDs, user information, and process details for easier debugging
|
|
451
|
+
- **Configurable Verbosity**: Control log level globally or per output channel
|
|
452
|
+
- **File Rotation**: Automatically rotates log files to prevent disk space issues
|
|
453
|
+
|
|
454
|
+
You can use the built-in logging utilities in your own code:
|
|
455
|
+
|
|
456
|
+
```python
|
|
457
|
+
from oua_auth import setup_logging
|
|
458
|
+
|
|
459
|
+
# Create a logger for your module
|
|
460
|
+
logger = setup_logging(__name__)
|
|
461
|
+
|
|
462
|
+
# Log with context data
|
|
463
|
+
logger.info("User action completed", extra={"user_id": user.id, "action": "login"})
|
|
464
|
+
|
|
465
|
+
# Create a logger with default context
|
|
466
|
+
user_logger = logger.with_context(user_id=user.id, user_email=user.email)
|
|
467
|
+
user_logger.info("Profile updated") # Will include user context automatically
|
|
468
|
+
|
|
469
|
+
# Use decorator to log requests (with timing)
|
|
470
|
+
from oua_auth import log_request
|
|
471
|
+
|
|
472
|
+
@log_request()
|
|
473
|
+
def my_view(request):
|
|
474
|
+
# Request start and end will be logged automatically with timing
|
|
475
|
+
return HttpResponse("Hello World")
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
The structured logs include consistent fields that make it easy to filter and analyze:
|
|
479
|
+
|
|
480
|
+
- **level**: Log level (INFO, WARNING, ERROR, etc.)
|
|
481
|
+
- **time**: ISO-8601 timestamp with timezone
|
|
482
|
+
- **message**: The log message
|
|
483
|
+
- **module**: Source module name
|
|
484
|
+
- **function**: Source function name
|
|
485
|
+
- **line**: Source line number
|
|
486
|
+
- **request_id**: Unique identifier for the request (for correlation)
|
|
487
|
+
- **user_id**: User ID if available
|
|
488
|
+
- **ip_address**: Client IP address if available
|
|
489
|
+
- **component**: Component name (e.g., "authentication", "middleware")
|
|
490
|
+
- **extra**: Additional context-specific information
|
|
491
|
+
|
|
492
|
+
## Features
|
|
493
|
+
|
|
494
|
+
- JWT token validation
|
|
495
|
+
- Automatic user creation and updates
|
|
496
|
+
- Role-based authorization with security controls
|
|
497
|
+
- User data synchronization with SSO server
|
|
498
|
+
- Path-based authentication exclusion
|
|
499
|
+
- Django admin integration
|
|
500
|
+
- Django Rest Framework support
|
|
501
|
+
|
|
502
|
+
## Contributing
|
|
503
|
+
|
|
504
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
505
|
+
|
|
506
|
+
## Testing
|
|
507
|
+
|
|
508
|
+
The package includes a comprehensive test suite to ensure its functionality and security:
|
|
509
|
+
|
|
510
|
+
```bash
|
|
511
|
+
# Install test dependencies
|
|
512
|
+
pip install -e ".[test]"
|
|
513
|
+
|
|
514
|
+
# Run the test suite
|
|
515
|
+
python -m pytest
|
|
516
|
+
|
|
517
|
+
# Run tests with coverage report
|
|
518
|
+
python -m pytest --cov=oua_auth --cov-report=term-missing
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
The test suite covers:
|
|
522
|
+
|
|
523
|
+
- JWT token validation and verification
|
|
524
|
+
- User creation and updates
|
|
525
|
+
- Admin privilege management
|
|
526
|
+
- Error handling
|
|
527
|
+
- Security features
|
|
528
|
+
|
|
529
|
+
See [tests/README.md](tests/README.md) for more details on the test suite.
|
|
530
|
+
|
|
531
|
+
## License
|
|
532
|
+
|
|
533
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|