a
    0ig^                     @   s   d dl Z d dlZd dlmZmZ d dlmZ d dlmZmZm	Z	m
Z
mZmZ d dlmZmZmZmZ d dlZG dd dZdd	 ZdS )
    N)datetime	timedelta)	lru_cache)requestrender_templateredirecturl_forjsonifysession)get_ModuleID
get_RoleIDget_permiso.get_CompanyID_DivisionID_DepartamentID_Profilec                   @   s~   e Zd ZdZg dZdd Zdd Zdd Zdd
dZe	dddd Z
dd Zdd Zdd Zdd Zdd ZdddZd	S )AccessControllerz5Controlador de acceso con logging profesional y cache)ZCLIEZEXTERNOSZPROVEEDORESc                 C   s0   t dd| _|  | _| jdkr&dnd| _d S )NZ	FLASK_ENVdevelopment
productioni,  <   )osgetenvenv_setup_loggerloggerZcache_duration)self r   3/var/www/html/src/App/Security_Module/UserAccess.py__init__   s    
zAccessController.__init__c              
      sN  ddl }ddl}ddl ddl}|d}|jr4|S | jdkrD|jn|j}|	| |
d}z\|j|jtddd}|j|dd	 |j|d
}|j|dd}	|	| ||	 W n2 ty }
 ztd|
  W Y d}
~
n
d}
~
0 0 |j|jd}|| G  fddd|j}|jdkr@| jdkr@||  || |S )ui   Configura el sistema de logging según el entorno (UTF-8 seguro y compatible con Windows, VSCode y Flask)r   Nuser_accessr   z:%(asctime)s - ACCESS_CONTROL - %(levelname)s - %(message)sz..ZlogsT)exist_okzaccess_control.logzutf-8)encodingz$No se pudo crear el archivo de log: )streamc                       s   e Zd Z fddZdS )z5AccessController._setup_logger.<locals>.NoEmojiFilterc                    s     ddt|j|_dS )Nz[^\x00-\x7F]+ T)substrmsg)r   recordrer   r   filterD   s    z<AccessController._setup_logger.<locals>.NoEmojiFilter.filterN)__name__
__module____qualname__r'   r   r%   r   r   NoEmojiFilterC   s   r+   ntr   )r   loggingr&   sys	getLoggerhandlersr   INFODEBUGsetLevel	Formatterpathjoindirname__file__makedirsFileHandlersetFormatter
addHandler	ExceptionprintStreamHandlerstdoutFiltername	addFilter)r   r   r-   r.   r   level	formatterZlog_dirZlog_fileZfile_handlereZconsole_handlerr+   r   r%   r   r      s8    


$

zAccessController._setup_loggerc                 C   sj   g }g }|s| d n|d du r.| d |s>| d n|d du rT| d |sb| d ||fS )z5Valida la integridad de los datos de la base de datosu    Datos del módulo no encontradosr   Nz$ModuloID es NULL en la base de datoszPerfil de usuario no encontradozCompanyID del usuario es NULLzUserID no proporcionado)append)r   user_idmodule_dataprofile_dataerrorswarningsr   r   r   _validate_database_integrityQ   s    


z-AccessController._validate_database_integrityNc                 C   s\  ||||t   | jd}|r(||d< |r8t||d< |dkrd| d| d| }d| d| d| }	| j| | jd	kr|rd
| }
| j|
 n|dkrd| d| d| }d| d| d| }	| j| |rd| }| j| n^|dkrXd| d| d| }d| d| d| }	| j	| |rXd| }| j	| dS )u6   Registra intentos de acceso con información detallada)rH   rutastepresult	timestampr   dataerrorSUCCESSu   ✅ ACCESO CONCEDIDO | User: 	 | Ruta: u    | Método: zACCESO CONCEDIDO | User: r   z   Datos utilizados: ZDENIEDu   🚫 ACCESO DENEGADO | User: z | Paso fallido: zACCESO DENEGADO | User: z   Datos del fallo: ERRORu!   ❌ ERROR EN VALIDACIÓN | User: z	 | Paso:    ERROR EN VALIDACIÓN | User: z
   Error: N)
r   now	isoformatr   r"   r   infodebugwarningrS   )r   rH   rN   rO   rP   rR   rS   Zlog_dataZfile_msgZconsole_msgZ	debug_msgZwarning_msg	error_msgr   r   r   _log_access_attemptj   s@    
	



z$AccessController._log_access_attemptd   )maxsizec              
   C   sJ   zt ||W S  tyD } z | jd|  W Y d}~dS d}~0 0 dS )zCache de permisos con TTLz"Error obteniendo permisos cached: N)r   r=   r   rS   )r   role_id	module_idrF   r   r   r   _get_cached_permissions   s
    z(AccessController._get_cached_permissionsc              
   C   s   | j d zPt|}| j d| d |dkrH| j d d|fW S | j d d|fW S  ty } z | j d	|  W Y d
}~dS d
}~0 0 d
S )u   Validación 1: Superusuarioz(>>> METODO 1: VALIDACION DE SUPERUSUARIOz    Datos obtenidos: RoleID = ''ZSUz1    RESULTADO: ACCESO CONCEDIDO - Es SUPERUSUARIOTz1    RESULTADO: No es superusuario, continuando...Fu!       ✗ ERROR obteniendo RoleID: N)FN)r   rZ   r   r=   rS   )r   rH   rN   ra   rF   r   r   r   _validate_superuser   s    

z$AccessController._validate_superuserc                 C   sL   | j d | j d |dkr0| j d dS | j d| d dS d	S )
u+   Validación 2: Acceso especial a index.htmlz,>>> METODO 2: VALIDACION ESPECIAL INDEX.HTMLz'    Verificando si ruta = '/index.html'/index.htmlzC    RESULTADO: ACCESO CONCEDIDO - Ruta es index.html (acceso libre)Tz    RESULTADO: Ruta 'z"' no es index.html, continuando...FN)r   rZ   )r   rH   rN   r   r   r   _validate_index_access   s    z'AccessController._validate_index_accessc              	   C   s  | j d |dkr0| j d | j d dS |d durD|d nd}|d dur\|d nd}|d	 durt|d	 nd}|d
 dur|d
 nd}	|d dur|d nd}
|d dur|d nd}|d	 dur|d	 nd}| j d | j d| d| d|	 d | j d | j d|
 d| d| d || jv rH| j d| d | j d| j  | j d ||
kr||kr|	|kr|r|dkr|	r|	dkr| j d dS | j d | j d||
k  | j d||k  | j d|	|k  | j d|o |dk  | j d|	o<|	dk  nr| j d| d |rl|dkr| j d ||
kr| j d dS | j d  | j d||
k  n|	r|	dkr2| j d! ||
kr||kr| j d" dS | j d# | j d||
k  | j d||k  n| j d$ ||
krl||krl|	|krl| j d% dS | j d& | j d||
k  | j d||k  | j d|	|k  | j d' dS )(u;   Validación 3: Acceso por departamento/división/compañíaz)>>> METODO 3: VALIDACION POR DEPARTAMENTOTz@    Restricted_Access = True - SALTANDO validacion departamentalzE    RESULTADO: Validacion departamental deshabilitada, continuando...Fr   N         z    DATOS DEL MODULO:z      Company: 'z' | Division: 'z' | Department: 'rd   z    DATOS DE TU PERFIL:z%    DIVISION RESTRINGIDA detectada: 'z    Divisiones restringidas: zN    RESULTADO: Solo se permite acceso especifico (Company+Division+Department)r    zV    RESULTADO: ACCESO CONCEDIDO - Acceso especifico completo para division restringidazY    RESULTADO: ACCESO DENEGADO - Division restringida requiere acceso especifico completoz      Company coincide: z      Division coincide: z      Department coincide: z(      Modulo tiene Division especifica: z*      Modulo tiene Department especifico: z    Division normal: 'z&' - Aplicando logica jerarquica normalzH    Modulo sin division especifica (vacio/None) - Validando solo Companyz2    RESULTADO: ACCESO CONCEDIDO - Company coincidez"    RESULTADO: Company no coincidezR    Modulo sin departamento especifico (vacio/None) - Validando Company + Divisionz>    RESULTADO: ACCESO CONCEDIDO - Company y Division coincidenz.    RESULTADO: Company o Division no coincidenzR    Modulo con departamento especifico - Validando Company + Division + DepartmentzJ    RESULTADO: ACCESO CONCEDIDO - Company, Division y Department coincidenz-    RESULTADO: No todos los valores coincidenz&    Continuando al siguiente metodo...)r   rZ   RESTRICTED_DIVISIONS)r   rH   rN   rI   rJ   Restricted_AccessModuloIDZM_CompanyIDZM_DivisionIDZM_DepartamentIDZP_CompanyIDZP_DivisionIDZP_DepartamentIDr   r   r   _validate_department_access   s      
 

z,AccessController._validate_department_accessc              
   C   s
  | j d |s(| j d| d dS z| ||}| j d | j d| d| d | j d	| d |d
urt|}| j d|  |dkr| j d W dS | j d n| j d W dS  ty } z | j d|  W Y d
}~dS d
}~0 0 d
S )u$   Validación 4: Permisos específicosz1>>> METODO 4: VALIDACION POR PERMISOS ESPECIFICOSzRoleID no definido para UserID=u-   , no se pueden validar permisos específicos.Fz    DATOS DE PERMISOS:z      Tu RoleID: 'z' | ModuloID: 'rd   z"      Valor de permiso obtenido: 'Nz#      Permiso convertido a entero: r   z-    RESULTADO: ACCESO CONCEDIDO - Permiso > 0Tz9    RESULTADO: ACCESO DENEGADO - Permiso = 0 (sin acceso)z>    RESULTADO: ACCESO DENEGADO - No se encontro permiso (NULL)u#       ✗ ERROR obteniendo permisos: )r   rZ   r\   rc   intr=   rS   )r   rH   rN   ra   rb   Z
permissionZpermission_levelrF   r   r   r   _validate_permission_access  s*    z,AccessController._validate_permission_accessc           	      C   sx   |  ||\}}|rdd|fS | ||r4dd|fS | |||||rPdd|fS |rn| ||||rndd|fS dd|fS )u   
        Ejecuta los 4 métodos de validación en cascada.
        Retorna:
            (resultado: bool, metodo: str, role_id: str | None)
        TzMETODO 1 - SUPERUSUARIOzMETODO 2 - INDEX.HTMLzMETODO 3 - DEPARTAMENTOzMETODO 4 - PERMISOS ESPECIFICOSFZNINGUNO)re   rg   rn   rp   )	r   UserIDrN   rI   rJ   rl   rm   Zis_superuserra   r   r   r   _validate_access_cascade>  s    



z)AccessController._validate_access_cascadec              	   C   sb   |rt  |  nd}| jd| d| d|dd |dkrZtdd	}t||d
S t|S )zFRenderiza el template exitosamente con manejo especial para index.htmlr   zRENDERIZANDO TEMPLATE | User: rU   z | Tiempo ejecucion: .3fsrf   emailUsuario)
user_email)r   rX   total_secondsr   rZ   r
   getr   )r   rN   rH   
start_timeexecution_timerw   r   r   r   _render_success_templateY  s    z)AccessController._render_success_template)NN)N)r(   r)   r*   __doc__rk   r   r   rM   r^   r   rc   re   rg   rn   rp   rr   r|   r   r   r   r   r      s   5
-
\!r   c                 C   s>  ddl m}m} ddlm}m}m}m} ddlm}	 ddl	}
|	
 }t }z<| st|jd |  ||dW S |sd}|j| |d	d
|d |d|dW S |jd |jd|  d| d|  |jd z||}W nv tyV   |	
 |  }d| }|j| |dd
|d |jd|  d| d|dd|  |ddd Y W S 0 || }|| ||\}}|D ]}|jd|  qv|r|	
 |  }dd| }|j| |dd
|d |jd|  d| d|dd|  |dddW S |r|d dur|d nd}|| |||||\}}}|	
 |  }|r|jd| d|  d |pjd! d"|pvd! d| d#|dd$ ||| |W S |rd%|d  d&|d'  d(|d)  d |pd! }nd*}|rd+|d  d,|d'  d&|d)  d(|d-  }nd.}|jd/|  d |p&d! d| d#|dd$	 |jd0| d1|  |j| |d2d
d3| d4| d5d |dd6dW S W n ty8 } z|	
 |  }|jd7|  d| d|dd8t|  |jd9kr|jd:|
   |j| |d;d
t|d |dd<t| dW  Y d}~S d}~0 0 dS )=z
    Valida el acceso del usuario a la ruta solicitada.
    Aplica validaciones en cascada y maneja errores de integridad.
    r   )r   r   )r   r
   r   r   )r   Nu?   Intento de acceso sin UserID en sesión - Redirigiendo al loginloginzRuta no proporcionadaZINPUT_VALIDATIONrV   )rS   zSecurity/AccessDened.html)messagez&=== INICIANDO VALIDACION DE ACCESO ===zUser: rU   z | Restricted: z&=== VALIDANDO 4 METODOS EN CASCADA ===u%   No se encontró el módulo en la BD: ZDB_INTEGRITYrW   u    | Tiempo ejecución: rs   zs | u3   El módulo no está registrado en la base de datos.z	WARNING: zErrores de integridad en BD: z; z"Error al validar datos de usuario.zACCESO FINAL CONCEDIDO POR: z	 | User: z
 | RoleID=zN/Az | ModuloID=z | Tiempo: rt   z
CompanyID=z | DivisionID=rh   z | DepartamentID=ri   zPerfil de usuario no disponiblez	ModuloID=z | CompanyID=rj   u    Datos del módulo no disponiblesu>   ACCESO FINAL DENEGADO - TODOS LOS 4 MÉTODOS FALLARON | User: u      Comparación → Usuario: u    | Módulo: ACCESS_DENIEDu8   Diferencias detectadas entre perfil y módulo (Usuario: u    vs Módulo: )u/   No tienes permisos para acceder a este módulo.u   ERROR CRÍTICO | User: zs | Error: r   zTraceback completo:
ZGENERALzError al verificar acceso: )&Consultas_SQL.Security.UserPasswordSQLr   r   flaskr   r
   r   r   r   	tracebackrX   r   r   r\   clearr^   rZ   LookupErrorrx   rS   rM   r6   rr   r|   r=   r"   r   
format_exc)rq   rN   rl   r   r   r   r
   r   r   r   r   rz   Zaccess_controllerr]   rI   r{   rJ   rK   rL   r\   rm   Z	resultadoZmetodora   Zuser_cmpZ
module_cmprF   r   r   r   check_user_accessh  s    
 
r   )r-   r   r   r   	functoolsr   r   r   r   r   r   r	   r
   r   r   r   r   r   r   r   r   r   r   r   r   <module>   s      Y