- Check for consent before allowing users to perform activities in the administrative app.
This commit is contained in:
@@ -6,6 +6,7 @@ from common.models.entitlements import License
|
||||
from common.utils.database import Database
|
||||
from common.utils.eveai_exceptions import EveAITenantNotFound, EveAITenantInvalid, EveAINoActiveLicense
|
||||
from datetime import datetime as dt, timezone as tz
|
||||
from common.services.user import TenantServices
|
||||
|
||||
|
||||
# Definition of Trigger Handlers
|
||||
@@ -19,12 +20,15 @@ def set_tenant_session_data(sender, user, **kwargs):
|
||||
# Remove partner from session if it exists
|
||||
session.pop('partner', None)
|
||||
|
||||
session['consent_status'] = str(TenantServices.get_consent_status(user.tenant_id))
|
||||
|
||||
|
||||
def clear_tenant_session_data(sender, user, **kwargs):
|
||||
session.pop('tenant', None)
|
||||
session.pop('default_language', None)
|
||||
session.pop('default_llm_model', None)
|
||||
session.pop('partner', None)
|
||||
session.pop('consent_status', None)
|
||||
|
||||
|
||||
def is_valid_tenant(tenant_id):
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
from flask import current_app, render_template
|
||||
from flask import current_app, render_template, request, redirect, session, flash
|
||||
from flask_security import current_user
|
||||
from itsdangerous import URLSafeTimedSerializer
|
||||
|
||||
from common.models.user import Role
|
||||
from common.models.user import Role, ConsentStatus
|
||||
from common.utils.nginx_utils import prefixed_url_for
|
||||
from common.utils.mail_utils import send_email
|
||||
|
||||
@@ -96,3 +96,94 @@ def current_user_roles():
|
||||
|
||||
def all_user_roles():
|
||||
roles = [(role.id, role.name) for role in Role.query.all()]
|
||||
|
||||
|
||||
def is_exempt_endpoint(endpoint: str) -> bool:
|
||||
"""Check if the endpoint is exempt from consent guard"""
|
||||
if not endpoint:
|
||||
return False
|
||||
cfg = current_app.config or {}
|
||||
endpoints_cfg = set(cfg.get('CONSENT_GUARD_EXEMPT_ENDPOINTS', []))
|
||||
prefix_cfg = list(cfg.get('CONSENT_GUARD_EXEMPT_PREFIXES', []))
|
||||
|
||||
default_endpoints = {
|
||||
'security_bp.login',
|
||||
'security_bp.logout',
|
||||
'security_bp.confirm_email',
|
||||
'security_bp.forgot_password',
|
||||
'security_bp.reset_password',
|
||||
'security_bp.reset_password_request',
|
||||
'user_bp.tenant_consent',
|
||||
'user_bp.no_consent',
|
||||
'user_bp.tenant_consent_renewal',
|
||||
'user_bp.consent_renewal',
|
||||
'security_bp.consent_sign',
|
||||
}
|
||||
default_prefixes = [
|
||||
'security_bp.',
|
||||
'healthz_bp.',
|
||||
]
|
||||
endpoints = default_endpoints.union(endpoints_cfg)
|
||||
prefixes = default_prefixes + [p for p in prefix_cfg if isinstance(p, str)]
|
||||
for p in prefixes:
|
||||
if endpoint.startswith(p):
|
||||
return True
|
||||
if endpoint in endpoints:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def enforce_tenant_consent_ui():
|
||||
"""Check if the user has consented to the terms of service"""
|
||||
path = getattr(request, 'path', '') or ''
|
||||
if path.startswith('/healthz') or path.startswith('/_healthz'):
|
||||
current_app.logger.debug(f'Health check request, bypassing consent guard: {path}')
|
||||
return None
|
||||
|
||||
if not current_user.is_authenticated:
|
||||
current_app.logger.debug('Not authenticated, bypassing consent guard')
|
||||
return None
|
||||
|
||||
endpoint = request.endpoint or ''
|
||||
if is_exempt_endpoint(endpoint) or request.method == 'OPTIONS':
|
||||
current_app.logger.debug(f'Endpoint exempt from consent guard: {endpoint}')
|
||||
return None
|
||||
|
||||
# Global bypass: Super User and Partner Admin always allowed
|
||||
if current_user.has_roles('Super User') or current_user.has_roles('Partner Admin'):
|
||||
current_app.logger.debug('Global bypass: Super User or Partner Admin')
|
||||
return None
|
||||
|
||||
tenant_id = getattr(current_user, 'tenant_id', None)
|
||||
if not tenant_id:
|
||||
tenant_id = session.get('tenant', {}).get('id') if session.get('tenant') else None
|
||||
if not tenant_id:
|
||||
return redirect(prefixed_url_for('security_bp.login', for_redirect=True))
|
||||
|
||||
status = session.get('consent_status', ConsentStatus.NOT_CONSENTED)
|
||||
if status == ConsentStatus.CONSENTED:
|
||||
current_app.logger.debug('User has consented')
|
||||
return None
|
||||
|
||||
if status == ConsentStatus.NOT_CONSENTED:
|
||||
current_app.logger.debug('User has not consented')
|
||||
if current_user.has_roles('Tenant Admin'):
|
||||
return redirect(prefixed_url_for('user_bp.tenant_consent', for_redirect=True))
|
||||
return redirect(prefixed_url_for('user_bp.no_consent', for_redirect=True))
|
||||
if status == ConsentStatus.RENEWAL_REQUIRED:
|
||||
current_app.logger.debug('Consent renewal required')
|
||||
if current_user.has_roles('Tenant Admin'):
|
||||
flash(
|
||||
"You need to renew your consent to our DPA or T&Cs. Failing to do so in time will stop you from accessing our services.",
|
||||
"danger")
|
||||
elif current_user.has_roles('Partner Admin'):
|
||||
flash(
|
||||
"Please ensure renewal of our DPA or T&Cs for the current Tenant. Failing to do so in time will stop the tenant from accessing our services.",
|
||||
"danger")
|
||||
else:
|
||||
flash(
|
||||
"Please inform your administrator or partner to renew your consent to our DPA or T&Cs. Failing to do so in time will stop you from accessing our services.",
|
||||
"danger")
|
||||
return None
|
||||
current_app.logger.debug('Unknown consent status')
|
||||
return redirect(prefixed_url_for('user_bp.no_consent', for_redirect=True))
|
||||
|
||||
Reference in New Issue
Block a user