Ë
    Õ!òiº  ã                  ó¬   — d Z ddlmZ ddlZddlmZmZmZ ddlm	Z	m
Z
 ddlmZ ddlmZ  ee«      Z ej"                  d«      Zdd	„Zdd
„Zdd„Zdd„Zy)uÈ  
middleware/auth_middleware.py
=============================
Hybrid auth dependency for FastAPI routes.

Auth precedence:
    1. `Authorization: Bearer <jwt>`  â†’ preferred path; JWT minted by
       /api/auth/login (local DB participant lookup).
    2. `X-Access-Key: <access_key>`   â†’ graceful fallback used after the
       external People Hub login succeeds. Resolves the access key to a
       participant row via the local DB.

The fallback exists because the candidate-portal landing page authenticates
against the external People Hub API and never round-trips through
/api/auth/login. Without this fallback every JWT-protected route (the
entire coding module) errors with "session expired" / 401 even though the
candidate is fully authenticated upstream â€” that was the root cause of the
visible "Session Expired" toast on the coding screen.

Security notes:
    â€¢ The access-key fallback still requires a successful DB lookup, so a
      forged value goes nowhere.
    â€¢ All code paths return a *normalized* candidate dict; routes never
      see raw DB rows or raw JWT claims.
    â€¢ Failures return a single opaque "Authentication required" message â€”
      we never tell an attacker which path failed.
é    )ÚannotationsN)ÚHTTPExceptionÚRequestÚstatus)Údecode_tokenÚget_candidate)Úparticipant_repo)Ú
get_loggerz ^[A-Za-z0-9][A-Za-z0-9_-]{1,63}$c                ó  — | j                   j                  d«      xs | j                   j                  d«      xs d}|sy|j                  dd«      }t        |«      dk7  s|d   j	                  «       dk7  ry|d   j                  «       S )	z>Extract the JWT from the Authorization header without raising.ÚAuthorizationÚauthorizationÚ Né   é   r   Úbearer)ÚheadersÚgetÚsplitÚlenÚlowerÚstrip)ÚrequestÚrawÚpartss      úu/Users/priyanka/Documents/AI_Agent_Assessment/pepole_hub_candidate/people_hub_candidate/middleware/auth_middleware.pyÚ_bearer_tokenr   -   sw   € à
�/‰/×
Ñ
˜oÓ
.Ò
\°'·/±/×2EÑ2EÀoÓ2VÒ
\ÐZ\€CÙØØ�I‰I�d˜AÓ€EÜ
ˆ5ƒz�Q‚˜% ™(Ÿ.™.Ó*¨hÒ6ØØ�‰8�>‰>ÓÐó    c                ób   — | sy t        | «      }|r|j                  d«      sy t        |d   «      S )NÚsub)r   r   r   )ÚtokenÚpayloads     r   Ú_candidate_from_jwtr"   8   s2   € ÙØÜ˜5Ó!€GÙ˜'Ÿ+™+ eÔ,ØÜ˜ ™Ó(Ð(r   c                óÞ   — | xs dj                  «       }|rt        j                  |«      sy 	 t        j                  |«      S # t
        $ r }t        j                  d|«       Y d }~y d }~ww xY w)Nr   z%access_key fallback lookup failed: %s)r   Ú_ACCESS_KEY_REÚ	fullmatchr	   Úfind_by_access_keyÚ	ExceptionÚlogÚwarning)Ú
access_keyÚkeyÚexcs      r   Ú_candidate_from_access_keyr-   A   s`   € ØÒ˜×
"Ñ
"Ó
$€CÙ”n×.Ñ.¨sÔ3ØðÜ×2Ñ2°3Ó7Ð7øÜò ä�‰Ð;¸SÔAÜûðús   ®A Á	A,ÁA'Á'A,c                ó  — t        t        | «      «      }|r|S | j                  j                  d«      xs | j                  j                  d«      xs d}t	        |«      }|r|S t        t        j                  dddi¬«      ‚)z±FastAPI dependency. Resolves the candidate via JWT *or* access key.

    Routes use this by declaring a dependency:
        candidate: dict = Depends(get_current_candidate)
    zX-Access-Keyzx-access-keyr   z-Authentication required. Please log in again.zWWW-AuthenticateÚBearer)Ústatus_codeÚdetailr   )r"   r   r   r   r-   r   r   ÚHTTP_401_UNAUTHORIZED)r   Ú	candidater*   s      r   Úget_current_candidater4   M   sŒ   € ô $¤M°'Ó$:Ó;€IÙØÐð 	�‰×Ñ˜NÓ+ò 	Ø�?‰?×Ñ˜~Ó.ò	àð ô
 +¨:Ó6€IÙØÐô Ü×0Ñ0Ø>Ø# XÐ.ôð r   )r   r   ÚreturnÚstr)r    r6   r5   údict | None)r*   r6   r5   r7   )r   r   r5   Údict)Ú__doc__Ú
__future__r   ÚreÚfastapir   r   r   Úservices.auth_servicer   r   Úservicesr	   Úutils.loggerr
   Ú__name__r(   Úcompiler$   r   r"   r-   r4   © r   r   Ú<module>rC      sR   ðñõ6 #ã 	ç 2Ñ 2ç =Ý %Ý #á�Ó€ð �—‘Ð?Ó@€óó)ó	ôr   