This commit is contained in:
Iliyan Angelov
2025-09-19 11:58:53 +03:00
parent 306b20e24a
commit 6b247e5b9f
11423 changed files with 1500615 additions and 778 deletions

View File

@@ -0,0 +1 @@
# Views for security API endpoints

View File

@@ -0,0 +1,533 @@
"""
Security API views for authentication, authorization, and audit
"""
import base64
from datetime import datetime, timedelta
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.utils import timezone
from django.db.models import Q
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from rest_framework import status, generics, permissions
from rest_framework.decorators import api_view, permission_classes, action
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from rest_framework.authtoken.models import Token
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from ..models import (
DataClassification, Role, User, MFADevice,
AuditLog, SSOProvider, AccessPolicy
)
from ..serializers.security import (
DataClassificationSerializer, RoleSerializer, UserSerializer,
MFADeviceSerializer, MFASetupSerializer, MFAVerificationSerializer,
AuditLogSerializer, SSOProviderSerializer, AccessPolicySerializer,
LoginSerializer, PasswordChangeSerializer, UserProfileSerializer
)
from ..mfa.totp import MFAProvider
from ..authentication.sso import SSOAuthentication
class DataClassificationViewSet(ModelViewSet):
"""ViewSet for data classification management"""
queryset = DataClassification.objects.all()
serializer_class = DataClassificationSerializer
permission_classes = [IsAdminUser]
def get_queryset(self):
"""Filter classifications based on user clearance"""
user = self.request.user
if user.is_superuser:
return DataClassification.objects.all()
# Filter based on user's clearance level
if user.clearance_level:
return DataClassification.objects.filter(
level__lte=user.clearance_level.level
)
return DataClassification.objects.filter(level__lte=1)
class RoleViewSet(ModelViewSet):
"""ViewSet for role management"""
queryset = Role.objects.all()
serializer_class = RoleSerializer
permission_classes = [IsAdminUser]
def get_queryset(self):
"""Filter roles based on user permissions"""
user = self.request.user
if user.is_superuser:
return Role.objects.all()
# Users can only see roles they have permissions for
return Role.objects.filter(
permissions__in=user.get_effective_permissions()
).distinct()
class UserViewSet(ModelViewSet):
"""ViewSet for user management"""
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes = [IsAdminUser]
def get_queryset(self):
"""Filter users based on data classification access"""
user = self.request.user
if user.is_superuser:
return User.objects.all()
# Filter based on clearance level
if user.clearance_level:
return User.objects.filter(
clearance_level__level__lte=user.clearance_level.level
)
return User.objects.filter(clearance_level__level__lte=1)
@action(detail=True, methods=['post'])
def lock_account(self, request, pk=None):
"""Lock user account"""
user = self.get_object()
duration = request.data.get('duration_minutes', 30)
user.lock_account(duration)
# Log the action
AuditLog.objects.create(
user=request.user,
action_type='ACCOUNT_LOCKED',
resource_type='User',
resource_id=str(user.id),
ip_address=self._get_client_ip(request),
user_agent=request.META.get('HTTP_USER_AGENT', ''),
details={'locked_user': user.username, 'duration_minutes': duration},
severity='HIGH'
)
return Response({'message': f'Account locked for {duration} minutes'})
@action(detail=True, methods=['post'])
def unlock_account(self, request, pk=None):
"""Unlock user account"""
user = self.get_object()
user.unlock_account()
# Log the action
AuditLog.objects.create(
user=request.user,
action_type='ACCOUNT_UNLOCKED',
resource_type='User',
resource_id=str(user.id),
ip_address=self._get_client_ip(request),
user_agent=request.META.get('HTTP_USER_AGENT', ''),
details={'unlocked_user': user.username},
severity='MEDIUM'
)
return Response({'message': 'Account unlocked'})
@action(detail=True, methods=['patch'])
def update_roles(self, request, pk=None):
"""Update user roles"""
user = self.get_object()
role_ids = request.data.get('role_ids', [])
# Validate role IDs
roles = Role.objects.filter(id__in=role_ids)
if len(roles) != len(role_ids):
return Response(
{'error': 'Invalid role IDs provided'},
status=status.HTTP_400_BAD_REQUEST
)
# Update user roles
user.roles.set(roles)
# Log the action
AuditLog.objects.create(
user=request.user,
action_type='ROLES_UPDATED',
resource_type='User',
resource_id=str(user.id),
ip_address=self._get_client_ip(request),
user_agent=request.META.get('HTTP_USER_AGENT', ''),
details={'updated_user': user.username, 'new_roles': [role.name for role in roles]},
severity='MEDIUM'
)
return Response({'message': 'User roles updated successfully'})
@action(detail=True, methods=['patch'])
def update_clearance(self, request, pk=None):
"""Update user clearance level"""
user = self.get_object()
clearance_level_id = request.data.get('clearance_level_id')
if not clearance_level_id:
return Response(
{'error': 'clearance_level_id is required'},
status=status.HTTP_400_BAD_REQUEST
)
try:
clearance_level = DataClassification.objects.get(id=clearance_level_id)
except DataClassification.DoesNotExist:
return Response(
{'error': 'Invalid clearance level ID'},
status=status.HTTP_400_BAD_REQUEST
)
old_clearance = user.clearance_level.name if user.clearance_level else 'None'
user.clearance_level = clearance_level
user.save()
# Log the action
AuditLog.objects.create(
user=request.user,
action_type='CLEARANCE_UPDATED',
resource_type='User',
resource_id=str(user.id),
ip_address=self._get_client_ip(request),
user_agent=request.META.get('HTTP_USER_AGENT', ''),
details={
'updated_user': user.username,
'old_clearance': old_clearance,
'new_clearance': clearance_level.name
},
severity='HIGH'
)
return Response({'message': 'User clearance level updated successfully'})
@action(detail=False, methods=['get'])
def dashboard_permissions(self, request):
"""Get dashboard permission mapping for admin"""
dashboard_components = {
'Dashboard (Overview)': {'permissions': [], 'clearance_level': None},
'Incidents': {'permissions': ['view_incident'], 'clearance_level': None},
'Monitoring': {'permissions': ['view_monitoringdashboard', 'view_alert', 'view_healthcheck'], 'clearance_level': None},
'SLA & On-Call': {'permissions': ['view_sladefinition', 'view_slainstance', 'view_oncallassignment'], 'clearance_level': None},
'Security': {'permissions': ['view_user', 'view_role', 'view_auditlog', 'view_securityevent'], 'clearance_level': 2},
'Automation': {'permissions': ['view_runbook', 'view_autoremediation', 'view_integration'], 'clearance_level': None},
'War Rooms': {'permissions': ['view_warroom', 'view_warroommessage', 'view_conferencebridge'], 'clearance_level': None},
'Analytics': {'permissions': ['view_kpimetric', 'view_anomalydetection', 'view_dashboardconfiguration'], 'clearance_level': None},
'Knowledge': {'permissions': ['view_knowledgebasearticle', 'view_postmortem', 'view_learningpattern'], 'clearance_level': None},
'Compliance': {'permissions': ['view_compliancereport', 'view_regulatoryframework', 'view_legalhold'], 'clearance_level': 3},
}
return Response(dashboard_components)
def _get_client_ip(self, request):
"""Get client IP address"""
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
return ip
class MFADeviceViewSet(ModelViewSet):
"""ViewSet for MFA device management"""
serializer_class = MFADeviceSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
"""Users can only manage their own MFA devices"""
return MFADevice.objects.filter(user=self.request.user)
def perform_create(self, serializer):
"""Create MFA device for current user"""
serializer.save(user=self.request.user)
@action(detail=False, methods=['post'])
def setup_totp(self, request):
"""Setup TOTP device"""
serializer = MFASetupSerializer(data=request.data, context={'request': request})
if serializer.is_valid():
device_name = serializer.validated_data['device_name']
# Create TOTP device
device, qr_data = MFAProvider.create_totp_device(request.user, device_name)
# Generate QR code image
qr_image = MFAProvider.generate_qr_code_image(qr_data)
qr_base64 = base64.b64encode(qr_image).decode('utf-8')
return Response({
'device_id': str(device.id),
'qr_code_data': qr_data,
'qr_code_image': f"data:image/png;base64,{qr_base64}",
'message': 'TOTP device created. Scan QR code with authenticator app.'
})
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@action(detail=True, methods=['post'])
def verify_totp(self, request, pk=None):
"""Verify TOTP token"""
device = self.get_object()
serializer = MFAVerificationSerializer(data=request.data)
if serializer.is_valid():
token = serializer.validated_data['token']
if MFAProvider.verify_totp_token(request.user, token, str(device.id)):
return Response({'message': 'TOTP token verified successfully'})
else:
return Response(
{'error': 'Invalid TOTP token'},
status=status.HTTP_400_BAD_REQUEST
)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@action(detail=False, methods=['post'])
def enable_mfa(self, request):
"""Enable MFA for user"""
if MFAProvider.enable_mfa_for_user(request.user):
return Response({'message': 'MFA enabled successfully'})
else:
return Response(
{'error': 'No active MFA devices found'},
status=status.HTTP_400_BAD_REQUEST
)
@action(detail=False, methods=['post'])
def disable_mfa(self, request):
"""Disable MFA for user"""
MFAProvider.disable_mfa_for_user(request.user)
return Response({'message': 'MFA disabled successfully'})
class AuditLogViewSet(ModelViewSet):
"""ViewSet for audit log viewing"""
queryset = AuditLog.objects.all()
serializer_class = AuditLogSerializer
permission_classes = [IsAdminUser]
http_method_names = ['get', 'head', 'options'] # Read-only
def get_queryset(self):
"""Filter audit logs based on user permissions"""
queryset = AuditLog.objects.all()
# Filter by date range
start_date = self.request.query_params.get('start_date')
end_date = self.request.query_params.get('end_date')
if start_date:
queryset = queryset.filter(timestamp__gte=start_date)
if end_date:
queryset = queryset.filter(timestamp__lte=end_date)
# Filter by action type
action_type = self.request.query_params.get('action_type')
if action_type:
queryset = queryset.filter(action_type=action_type)
# Filter by severity
severity = self.request.query_params.get('severity')
if severity:
queryset = queryset.filter(severity=severity)
# Filter by user
user_id = self.request.query_params.get('user_id')
if user_id:
queryset = queryset.filter(user_id=user_id)
return queryset.order_by('-timestamp')
class SSOProviderViewSet(ModelViewSet):
"""ViewSet for SSO provider management"""
queryset = SSOProvider.objects.all()
serializer_class = SSOProviderSerializer
permission_classes = [IsAdminUser]
class AccessPolicyViewSet(ModelViewSet):
"""ViewSet for access policy management"""
queryset = AccessPolicy.objects.all()
serializer_class = AccessPolicySerializer
permission_classes = [IsAdminUser]
@api_view(['POST'])
@permission_classes([])
def login_view(request):
"""User login with MFA support"""
serializer = LoginSerializer(data=request.data)
if serializer.is_valid():
username = serializer.validated_data['username']
password = serializer.validated_data['password']
mfa_token = serializer.validated_data.get('mfa_token', '')
remember_me = serializer.validated_data.get('remember_me', False)
# Authenticate user
user = authenticate(request, username=username, password=password)
if user is None:
# Log failed login attempt
AuditLog.objects.create(
action_type='LOGIN_FAILED',
ip_address=_get_client_ip(request),
user_agent=request.META.get('HTTP_USER_AGENT', ''),
details={'username': username},
severity='MEDIUM'
)
return Response(
{'error': 'Invalid credentials'},
status=status.HTTP_401_UNAUTHORIZED
)
# Check if account is locked
if user.is_account_locked():
return Response(
{'error': 'Account is locked'},
status=status.HTTP_423_LOCKED
)
# Check MFA if enabled
if user.mfa_enabled:
if not mfa_token:
return Response(
{'error': 'MFA token required', 'mfa_required': True},
status=status.HTTP_400_BAD_REQUEST
)
if not MFAProvider.verify_totp_token(user, mfa_token):
return Response(
{'error': 'Invalid MFA token'},
status=status.HTTP_401_UNAUTHORIZED
)
# Login successful
login(request, user)
# Update user login info
user.last_login_ip = _get_client_ip(request)
user.failed_login_attempts = 0
user.save(update_fields=['last_login_ip', 'failed_login_attempts'])
# Generate or get token
token, created = Token.objects.get_or_create(user=user)
# Set session expiry
if not remember_me:
request.session.set_expiry(3600) # 1 hour
# Log successful login
AuditLog.objects.create(
user=user,
action_type='LOGIN',
ip_address=_get_client_ip(request),
user_agent=request.META.get('HTTP_USER_AGENT', ''),
details={'remember_me': remember_me, 'mfa_used': user.mfa_enabled}
)
return Response({
'token': token.key,
'user': UserSerializer(user).data,
'message': 'Login successful'
})
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def logout_view(request):
"""User logout"""
# Log logout
AuditLog.objects.create(
user=request.user,
action_type='LOGOUT',
ip_address=_get_client_ip(request),
user_agent=request.META.get('HTTP_USER_AGENT', '')
)
# Delete token
try:
request.user.auth_token.delete()
except:
pass
logout(request)
return Response({'message': 'Logout successful'})
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def user_profile(request):
"""Get current user profile"""
serializer = UserProfileSerializer(request.user)
return Response(serializer.data)
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def change_password(request):
"""Change user password"""
serializer = PasswordChangeSerializer(data=request.data)
if serializer.is_valid():
user = request.user
current_password = serializer.validated_data['current_password']
new_password = serializer.validated_data['new_password']
# Verify current password
if not user.check_password(current_password):
return Response(
{'error': 'Current password is incorrect'},
status=status.HTTP_400_BAD_REQUEST
)
# Set new password
user.set_password(new_password)
user.save()
# Log password change
AuditLog.objects.create(
user=user,
action_type='PASSWORD_CHANGE',
ip_address=_get_client_ip(request),
user_agent=request.META.get('HTTP_USER_AGENT', ''),
severity='MEDIUM'
)
return Response({'message': 'Password changed successfully'})
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def mfa_status(request):
"""Get MFA status for current user"""
devices = MFAProvider.get_user_mfa_devices(request.user)
return Response({
'mfa_enabled': request.user.mfa_enabled,
'devices': devices,
'device_count': len(devices)
})
def _get_client_ip(request):
"""Get client IP address from request"""
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0]
else:
ip = request.META.get('REMOTE_ADDR')
return ip

View File

@@ -0,0 +1,374 @@
"""
Zero Trust API Views
Provides endpoints for device registration, risk assessment, and Zero Trust management
"""
import logging
from rest_framework import status, generics, permissions
from rest_framework.decorators import api_view, permission_classes, action
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import IsAuthenticated, IsAdminUser
from django.utils import timezone
from django.db import models
from ..models import (
DevicePosture, GeolocationRule, RiskAssessment,
AdaptiveAuthentication, UserBehaviorProfile
)
from ..serializers.zero_trust import (
DevicePostureSerializer, GeolocationRuleSerializer,
RiskAssessmentSerializer, AdaptiveAuthenticationSerializer,
UserBehaviorProfileSerializer, DeviceRegistrationSerializer,
RiskAssessmentRequestSerializer
)
from ..services.zero_trust import zero_trust_service
logger = logging.getLogger(__name__)
class DevicePostureViewSet(ModelViewSet):
"""ViewSet for device posture management"""
queryset = DevicePosture.objects.all()
serializer_class = DevicePostureSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
"""Users can only see their own devices"""
return DevicePosture.objects.filter(user=self.request.user)
def perform_create(self, serializer):
"""Create device posture for current user"""
serializer.save(user=self.request.user)
@action(detail=True, methods=['post'])
def update_posture(self, request, pk=None):
"""Update device posture information"""
device = self.get_object()
# Update device posture data
device_data = request.data
for field, value in device_data.items():
if hasattr(device, field) and field not in ['id', 'user', 'created_at']:
setattr(device, field, value)
# Recalculate risk score and trust level
device.risk_score = device.calculate_risk_score()
device.update_trust_level()
device.save()
return Response({
'message': 'Device posture updated',
'risk_score': device.risk_score,
'trust_level': device.trust_level,
'is_compliant': device.is_compliant
})
@action(detail=False, methods=['post'])
def register_device(self, request):
"""Register a new device"""
serializer = DeviceRegistrationSerializer(data=request.data)
if serializer.is_valid():
try:
device = zero_trust_service.register_device(
request.user,
serializer.validated_data
)
return Response({
'success': True,
'device_id': device.device_id,
'trust_level': device.trust_level,
'risk_score': device.risk_score,
'is_compliant': device.is_compliant,
'message': 'Device registered successfully'
}, status=status.HTTP_201_CREATED)
except Exception as e:
logger.error(f"Device registration failed: {e}")
return Response({
'error': 'Device registration failed',
'details': str(e)
}, status=status.HTTP_400_BAD_REQUEST)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class GeolocationRuleViewSet(ModelViewSet):
"""ViewSet for geolocation rule management"""
queryset = GeolocationRule.objects.all()
serializer_class = GeolocationRuleSerializer
permission_classes = [IsAdminUser]
@action(detail=True, methods=['post'])
def test_rule(self, request, pk=None):
"""Test geolocation rule against provided location data"""
rule = self.get_object()
location_data = request.data
result = rule.evaluate_location(**location_data)
return Response({
'rule_name': rule.name,
'rule_type': rule.rule_type,
'test_result': result,
'location_data': location_data
})
class RiskAssessmentViewSet(ModelViewSet):
"""ViewSet for risk assessment management"""
queryset = RiskAssessment.objects.all()
serializer_class = RiskAssessmentSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
"""Users can only see their own risk assessments"""
return RiskAssessment.objects.filter(user=self.request.user)
@action(detail=False, methods=['post'])
def assess_access(self, request):
"""Perform risk assessment for access request"""
serializer = RiskAssessmentRequestSerializer(data=request.data)
if serializer.is_valid():
try:
# Collect request context
request_context = {
'ip_address': self._get_client_ip(request),
'user_agent': request.META.get('HTTP_USER_AGENT', ''),
'device_id': request.headers.get('X-Device-ID'),
'timestamp': timezone.now(),
**serializer.validated_data
}
# Perform assessment
assessment_result = zero_trust_service.assess_access_request(
request.user,
request_context
)
return Response(assessment_result)
except Exception as e:
logger.error(f"Risk assessment failed: {e}")
return Response({
'error': 'Risk assessment failed',
'details': str(e)
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
@action(detail=False, methods=['get'])
def my_risk_profile(self, request):
"""Get user's current risk profile"""
try:
# Get latest risk assessment
latest_assessment = RiskAssessment.objects.filter(
user=request.user
).order_by('-assessed_at').first()
# Get behavior profile
try:
behavior_profile = UserBehaviorProfile.objects.get(user=request.user)
except UserBehaviorProfile.DoesNotExist:
behavior_profile = None
# Get device postures
devices = DevicePosture.objects.filter(
user=request.user,
is_active=True
).order_by('-last_seen')
return Response({
'latest_assessment': RiskAssessmentSerializer(latest_assessment).data if latest_assessment else None,
'behavior_profile': UserBehaviorProfileSerializer(behavior_profile).data if behavior_profile else None,
'devices': DevicePostureSerializer(devices, many=True).data,
'risk_summary': {
'total_devices': devices.count(),
'trusted_devices': devices.filter(is_trusted=True).count(),
'compliant_devices': devices.filter(is_compliant=True).count(),
'average_risk_score': devices.aggregate(avg_risk=models.Avg('risk_score'))['avg_risk'] or 0
}
})
except Exception as e:
logger.error(f"Failed to get risk profile: {e}")
return Response({
'error': 'Failed to get risk profile',
'details': str(e)
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def _get_client_ip(self, request):
"""Get client IP address from request"""
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0].strip()
else:
ip = request.META.get('REMOTE_ADDR')
return ip
class AdaptiveAuthenticationViewSet(ModelViewSet):
"""ViewSet for adaptive authentication management"""
queryset = AdaptiveAuthentication.objects.all()
serializer_class = AdaptiveAuthenticationSerializer
permission_classes = [IsAdminUser]
@action(detail=True, methods=['post'])
def test_auth_requirements(self, request, pk=None):
"""Test authentication requirements for given risk score"""
adaptive_auth = self.get_object()
risk_score = request.data.get('risk_score', 0)
required_methods = adaptive_auth.get_required_auth_methods(risk_score)
return Response({
'risk_score': risk_score,
'required_auth_methods': required_methods,
'adaptive_auth_name': adaptive_auth.name
})
class UserBehaviorProfileViewSet(ModelViewSet):
"""ViewSet for user behavior profile management"""
queryset = UserBehaviorProfile.objects.all()
serializer_class = UserBehaviorProfileSerializer
permission_classes = [IsAuthenticated]
def get_queryset(self):
"""Users can only see their own behavior profile"""
return UserBehaviorProfile.objects.filter(user=self.request.user)
@action(detail=True, methods=['post'])
def calculate_anomaly(self, request, pk=None):
"""Calculate anomaly score for current behavior"""
profile = self.get_object()
current_behavior = request.data
anomaly_score = profile.calculate_anomaly_score(current_behavior)
return Response({
'anomaly_score': anomaly_score,
'is_anomalous': anomaly_score > 0.7, # Threshold
'current_behavior': current_behavior
})
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def zero_trust_status(request):
"""Get Zero Trust system status and configuration"""
try:
# Get user's Zero Trust status
user_devices = DevicePosture.objects.filter(user=request.user, is_active=True)
latest_assessment = RiskAssessment.objects.filter(user=request.user).order_by('-assessed_at').first()
# Get system configuration
adaptive_auth = AdaptiveAuthentication.objects.filter(is_active=True).first()
geo_rules = GeolocationRule.objects.filter(is_active=True).count()
return Response({
'zero_trust_enabled': True,
'user_status': {
'registered_devices': user_devices.count(),
'trusted_devices': user_devices.filter(is_trusted=True).count(),
'latest_risk_level': latest_assessment.risk_level if latest_assessment else 'UNKNOWN',
'latest_risk_score': latest_assessment.overall_risk_score if latest_assessment else 0
},
'system_configuration': {
'adaptive_auth_enabled': adaptive_auth is not None,
'geolocation_rules_count': geo_rules,
'behavioral_analysis_enabled': True,
'device_posture_enabled': True
},
'recommendations': _get_security_recommendations(request.user, user_devices, latest_assessment)
})
except Exception as e:
logger.error(f"Failed to get Zero Trust status: {e}")
return Response({
'error': 'Failed to get Zero Trust status',
'details': str(e)
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def perform_risk_assessment(request):
"""Perform a comprehensive risk assessment"""
try:
# Collect request context
request_context = {
'ip_address': _get_client_ip(request),
'user_agent': request.META.get('HTTP_USER_AGENT', ''),
'device_id': request.headers.get('X-Device-ID'),
'timestamp': timezone.now(),
**request.data
}
# Perform assessment
assessment_result = zero_trust_service.assess_access_request(
request.user,
request_context
)
return Response(assessment_result)
except Exception as e:
logger.error(f"Risk assessment failed: {e}")
return Response({
'error': 'Risk assessment failed',
'details': str(e)
}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
def _get_security_recommendations(user, devices, latest_assessment):
"""Get security recommendations based on user's current status"""
recommendations = []
# Device recommendations
if devices.count() == 0:
recommendations.append({
'type': 'device',
'priority': 'high',
'message': 'Register your device for enhanced security',
'action': 'register_device'
})
untrusted_devices = devices.filter(is_trusted=False)
if untrusted_devices.exists():
recommendations.append({
'type': 'device',
'priority': 'medium',
'message': f'{untrusted_devices.count()} untrusted devices detected',
'action': 'improve_device_security'
})
# Risk recommendations
if latest_assessment and latest_assessment.risk_level in ['HIGH', 'CRITICAL']:
recommendations.append({
'type': 'risk',
'priority': 'high',
'message': f'High risk level detected: {latest_assessment.risk_level}',
'action': 'review_security_settings'
})
# MFA recommendations
if not user.mfa_enabled:
recommendations.append({
'type': 'authentication',
'priority': 'medium',
'message': 'Enable Multi-Factor Authentication',
'action': 'enable_mfa'
})
return recommendations
def _get_client_ip(request):
"""Get client IP address from request"""
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
if x_forwarded_for:
ip = x_forwarded_for.split(',')[0].strip()
else:
ip = request.META.get('REMOTE_ADDR')
return ip