U
    wRdQS                     @   s   d dl Z d dlZd dlZd dlZd dlZd dlZd dlZd dlZd dlZd dlm	Z	 d dl
mZ d dlmZmZ d dlmZmZ d dlmZ d dlmZ d dlmZ d d	lmZmZ d d
lT ddlmZ ddlmZ d dl m!Z! G dd dej"Z"dS )    N)pbkdf2_hmac)	urlencode)AES
PKCS1_OAEP)SHA1SHA256)RSA)get_random_bytes)
PKCS1_v1_5)padunpad)*   )
send_email   )auth)
Supervisorc                       s^  e Zd ZdZdZedd Zedd Zdd Ze	d	d
 Z
dBddZdCddZdd ZdDddZdEddZedd Zedd Zedd Ze	dd Ze	d d! Ze	d"d# Ze	d$d% Ze	d&d' Zd(d) Zd*d+ Ze	d,d- Ze	d.d/ ZdFd1d2Ze	d3d4 Ze	dGd5d6Z fd7d8Z d9d: Z!e	d;d< Z"e	e#d=d>d?Z$e	d@dA Z%  Z&S )HCmfAuth    
   c                 C   s   t | jdd S )N$base64	b64decode	pass_hashsplitself r   ./modules/auth/models/auth.pykey!   s    zCmfAuth.keyc                 C   s   t | jdd S )Nr   r   r   r   r   r    salt%   s    zCmfAuth.saltc                 C   s2   t | j}|ttt 7 }|| j 7 }|S N)secrets	token_hextoken_lengthstrinttimer#   hex)r   server_challenger   r   r    gen_server_challenge)   s    zCmfAuth.gen_server_challengec                 C   s   d| j d  }}||| }||d  }}||| }|t| }}t||| }td| |d}	t| j }
t	t
t }||
 | | }ttj}t|	tj|}|t| tj}||  S )Nr   r   r   sha256順 )r'   lenbytesfromhexhashlibr   encoder%   r&   r(   r)   r*   r	   r   
block_sizenewMODE_CBCZencryptr   r+   )clsloginpasswordr,   startendserver_randomserver_timestampZserver_saltZtest_keyclient_randomsecretivcipherZencrypted_secretr   r   r    test_gen_server_challenge_resp/   s&       
z&CmfAuth.test_gen_server_challenge_resprestore_passwordc                 C   sH   | j dd t| jd}|dkr*| j|d< tj d| dtj| S )u   
        Сформируем ссылку на сброс и отправим её пользователю.
        Альтернативно переиспользуется для приглашения нового пользователя.
        F)reset)hrD   r9   z/auth/?)	reset_pass_set_datadictreset_password_hashr9   configAUTH_SERVER_URLurllibparser   )r   Zendpointparamsr   r   r    reset_pass_linkL   s
    
zCmfAuth.reset_pass_linkTc                 C   s:   |rdnt d| _|rdntt d | _|   dS )u  
        Выставляем (или сбрасываем) секретик для сброса пароля
        Не очень хорошо, наверное хранить его в чистом виде, если упрут базу account будет печально,
        т.к. по сути даст доступ ко всем, кто в течение часа до угона БД запросил восстановление пароля.
        По хорошему хэшировать чем-то, что хранится отдельно от БД и периодически менять.
        Но это TODO-преTODO, т.к. паранойя.
        12 байт рандома дают нам 2**(8*12)=79,2E+27 значений. Перебирать по 1 в сек по сети - 2,5E+21 лет.
        :param reset - если True, выставляем всё в None, если False - генерируем новые значения
        N   Q )r%   Ztoken_urlsaferJ   r)   r*   reset_password_expiressave)r   rE   r   r   r    rH   W   s    
zCmfAuth.reset_pass_set_datac                 C   s   | j  pt | j kS )u_    Проверяем что ссылка для сброса пароля не протухла )rS   r*   r   r   r   r    reset_pass_is_expirede   s    zCmfAuth.reset_pass_is_expiredNc                 C   st   ddd}|d kr6| j jtt d|  | jjd}tt|	 
 }tt|	 
 }| d| S )NZRS256ZJWT)ZalgtyprR   )r9   expscope.)r9   valuer)   r*   rX   r   	b64encodejsondumpsr4   decode)r   dayspayloadheaderr   r   r    
create_jwti   s    
zCmfAuth.create_jwtc                 C   s^   |d kr|  |}ttj}t }||  ||}t	
| }| d| }|S NrY   )rb   r
   r6   APPZrsa_private_keyr   updater4   signr   r[   r^   )r   r_   jwtZsignerdigestrf   resr   r   r    rsa_sign_pack_jwtu   s    

zCmfAuth.rsa_sign_pack_jwtc                 C   s   |  d\}}}t }| d| }||  t|}ttj	}|
||}|s^dS t| }t| }t|}t|}||dS )u   
        TODO: проверять exp здесь, а не в from_jwt, возвращать None, если просрочили
        rY   Nra   r`   )r   r   r6   re   r4   r   r   r
   rd   rsa_public_keyverifyr^   r\   loads)rjwtra   r`   	signaturerh   rg   verifierZverifiedr   r   r    rsa_verify_unpack_jwt   s    


zCmfAuth.rsa_verify_unpack_jwtc                 C   sJ   |  d\}}}t| }t| }t|}t|}||dS )NrY   rk   )r   r   r   r^   r\   rn   )ro   ra   r`   rp   r   r   r    rsa_unpack_jwt   s    

zCmfAuth.rsa_unpack_jwtc           	      C   s^   |  d\}}}t }| d| }||  t|}t|}t	|}|
||S rc   )r   r   r6   re   r4   r   r   r   Z
import_keyr
   rm   )	ro   Zrsa_public_key_bytesra   r`   rp   rh   rg   rl   rq   r   r   r    rsa_verify_jwt   s    


zCmfAuth.rsa_verify_jwtc              
   C   s  t d |st d d S z| |}W n& tk
rL } zd }W 5 d }~X Y nX |s^t d d S d}zt|d dd}W n ttfk
r   Y nX tj 	 }||krt d d S | dd	}|d d
 |_
|d d
 |_|d d |_d |_d|_tjtd r|jst d |S ttd ^}| }d}	|jdD ]"}
|
| drBd}	 qfqB|	st d W 5 Q R  d S W 5 Q R X t d|j
 d|j  |S )Nzfrom_jwt: startzfrom_jwt: warn not jwtz2from_jwt: warn not cls.rsa_verify_unpack_jwt(rjwt)r   r`   rW   z)from_jwt: reset auth, cause token expiredT)emptyr9   rX   z/custom/org_nameu,   from_jwt: нет билета доступаF :zfrom_jwt: jwt is ok, z, )printrr   	Exceptionr)   get	TypeError
ValueErrordatetimenowZ	timestampr9   emailrX   Zjwt_is_supportZjwt_is_match_orgospathexistsZPROJECT_DIRopenreadr   
startswith)r8   ro   rg   erW   r~   objforg_nameZacceptZpermr   r   r    from_jwt   sT    

zCmfAuth.from_jwtc                 C   s  | j |dgd}|s$| j |dgd}|s8| j |dgd}|s\tjjddd d|idd	d
 d S t|}dtj }}||| }|t| }}||| }t	|j
tj|}||}	zt|	tj}
W n< tk
r    td tjjddd d|idd	d
 Y d S X |
 }d|jd  }}||| }|||jd   }}||| }|||j  }}||| }|t| }}||| }t t| dkrtjjddd d|idd	d
 d S tjjddd d|idd	d
 |S )Nz***)	ext_loginfieldsr9   r   )r   r   r   r   r9   failToperatecmf_model_nameparent
audit_dataresult_statuscelery_skipr   z$get_by_challenge_resp: wrong paddingr   rR   ok)rz   modelsCmfAuditaudit_eventr1   r2   r   r5   r0   r6   r!   r7   Zdecryptr   r|   rx   r^   r'   	ts_lengthr*   r)   )r8   r9   Zchallenge_respr   r;   r<   rA   Zencrypted_messagerB   Zres0Zres1Zres2r=   r?   r>   r   r   r    get_by_challenge_resp   sn    
  


  
  
  zCmfAuth.get_by_challenge_respc                 C   s"   |  }||_ ||_||| |S r$   )r9   r   set_pass_hash)r8   r9   hashr#   r   r   r   r    new_from_login_hash_salt  s
    z CmfAuth.new_from_login_hash_saltc           
      C   sl   | d}|d }|dkrZ|dd  \}}}t|}t|}	|	td| |t|kS td| d S )Nr   r   Zpbkdf2_sha256r   r.   zNot Implemented for )r   r   r   r   r4   r)   NotImplementedError)
r8   r@   Zsecret_hashZ
hash_partsZ	hash_algoZn_itersalt_b64hash_b64Zsalt_bZhash_br   r   r    check_secret*  s    


zCmfAuth.check_secretc                 C   s`   | j |d}|r@| ||jjr@tjjddd|id ddd |S tjjddd|id ddd d S )	Nr9   r   r   r9   r   Tr   r   r   r   r   r   r   )rz   r   r   rZ   r   r   r   )r8   r9   r:   r   r   r   r    from_login_password6  s"    
  
  zCmfAuth.from_login_passwordc                 C   s$   t |}t |}| || d S r$   )r1   r2   set_pass_hash_bytes)r   r   r#   
hash_bytes
salt_bytesr   r   r    r   F  s    

zCmfAuth.set_pass_hashc                 C   s2   t | }t | }d| d| | _d S )Nzpbkdf2_sha256$100000$r   )r   r[   r^   r   )r   r   r   r   r   r   r   r    r   K  s    zCmfAuth.set_pass_hash_bytesc                 C   s   t jS r$   )gr   )r8   r   r   r    current_authV  s    zCmfAuth.current_authc                 C   s:   g }t dD ]}|ttjtj  qd|dS )N    zutf-8)	rangeappendrandomchoicestringascii_lettersdigitsjoinr4   )r8   charsir   r   r    gen_saltZ  s    zCmfAuth.gen_salt   c                    sz   t jt j  |s,d fddt|D }t|  }td|	 |d}| 
|| tjjddd| jid	d
dd |S )uO   
        Генерирует новый пароль
        :return:
        r   c                 3   s   | ]}t  V  qd S r$   )r   r   .0r   Zlettersr   r    	<genexpr>h  s     z)CmfAuth.reset_password.<locals>.<genexpr>r.   r/   reset_passwordr   r9   Nr   Tr   )r   r   r   r   r   typer   r3   r   r4   r   r   r   r   r9   )r   lengthr:   r#   r   r   r   r    r   a  s$       
  zCmfAuth.reset_passwordc                 C   s@   dt j }d|g}t||| tjjddd d|iddd d S )	Nu&   Пароль для доступа к u   Пароль:send_passwordr   r   r   Tr   )rK   ZPROJECT_NAMEr   r   r   r   )r8   r:   r   ZsubjectZmsg_contentsr   r   r    r   s  s    
  zCmfAuth.send_passwordc                 C   sh   ddl m} | }tj||d}|  |jtj d|ddd}|jdkrVt	d	t
|jd
dS )Nr   )session)r9   rg_member_ofz/auth/signupT)r9   Zgen_pwd)data   u>   Не удалось создать учётную записьaccess_token)r   )Zrequestsr   r   Z	CmfPersonrT   ZpostrK   rL   Zstatus_codery   rI   Zcookiesrz   )r8   r9   r   r   sZpersonrr   r   r    create_person|  s    

zCmfAuth.create_personc                    sh   | j jrZd| _| j jsZ| j D ].}| j | D ]}|  jd| d| 7  _q*q| jj | _t j||S )Nr   rv   rw   )groups
is_changedrX   is_nullrZ   stripsuperrT   )r   argskwargsr   Zgrp_name	__class__r   r    rT     s    
zCmfAuth.savec                 C   s&   | j jrg S tdd | j dD S )Nc                 S   s   g | ]}| d d qS )rw   r   )r   r   r   r   r    
<listcomp>  s     z)CmfAuth.prepare_scope.<locals>.<listcomp>rv   )rX   r   setr   r   r   r   r    prepare_scope  s    zCmfAuth.prepare_scopec                 C   s   |  |}|d d }zt|}W n  tk
rD   d}t|Y nX | ||}|s|d|d d  d}t| t||S )Nr`   issuJ   Не удалось прочитать публичный ключ EvaTeamuE   Не удалось валидировать токен от EVA_APP r   !)rs   r   Zread_crm_pub_keyRuntimeErrorry   rt   loggingerror)r8   eva_app_tokenrg   r   Zcrm_pub_keyr   rm   r   r   r    _check_token  s    

zCmfAuth._check_token)usersc             
   O   s  |  |}|d d }|D ]}zt|d   }| j|ddddgd}	|	svtj|d	}	td
|  |		  |dpd}
t|
  p||	_
|dpd}t|  pd|	_|	jjri |	_|	jsg |	_||	jkr|	j| g |	j|< |d rHtd|| ||	jkr,|	j| |	j|= d|	j_|		  W q|d D ]:}td| d| d|  |	j| | d|	j_qP|d |	_td|  td|	j  |		  t  td|	j  W q tk
r   td|   Y qX qddiS )u   
        Метод вызывается из eva_app при синхронизации
        создает и привязывает пользователей
        https://bcrm.carbonsoft.ru/project/Document/DOC-003025#spec-0-ldap
        r`   r   r9   r   rX   auth_pluginreg_org_name_listr   r   u(   Создали пользователя r   r   r   NZcmf_deletedu4   Пользователь {} удален из crm {}Tr   u,   Добавляем пользователю u    права u    в crm auth_optionsz
user_dict=zuser.groups=zuser.scope=u)   Не удалось обработать resultr   )r   r(   lowerr   rz   r   r   r   debugrT   r   r   r   r   r   r   formatremover   r   Zcommit_with_eventrX   ry   Z	exception)r8   r   r   r   r   rg   r   Z	user_dictr9   userr   r   Zgrp_coder   r   r    rpc_account_sync_push  sV    






zCmfAuth.rpc_account_sync_pushc                O   s  t js
d S dd }t jsd S | |}|d d }|D ]}tjj|d d dgd}	|	s`t }	||	|d  |d d |	_|	  tjj|d dd	gd}
|
st }
||
| ||
_	|d |
_|	|
_
|
  q6tjjd
ddd |D gdD ]}	|	  qddiS )Nc                 S   sF   |D ]<}|dks| ds|dr&qt| |rt| |||  qd S )N)idcodeZext_ipZcmf_Z_id)r   endswithhasattrsetattr)r   Zobj_dictZ
field_namer   r   r    copy_f  s    
z/CmfAuth.rpc_account_plugin_push.<locals>.copy_fr`   r   pluginr   r   )ext_idr   zplugin.*r   zNOT INc                 S   s   g | ]}|d  qS )r   r   )r   r   r   r   r    r   	  s     z3CmfAuth.rpc_account_plugin_push.<locals>.<listcomp>)filterr   r   )rK   ZIS_BOX_VERSIONr   r   Z	CmfPluginrz   r   rT   ZCmfAuthLdapPluginr   r   listdelete)r8   r   Zauth_pluginsr   r   r   rg   r   r   r   Zauth_plugin_objr   r   r    rpc_account_plugin_push  s2    



"
zCmfAuth.rpc_account_plugin_push)rD   )T)r   N)r   N)r   N)N)'__name__
__module____qualname__r'   r   propertyr!   r#   r-   classmethodrC   rP   rH   rU   rb   rj   staticmethodrr   rs   rt   r   r   r   r   r   r   r   r   r   r   r   r   rT   r   r   r   r   r   __classcell__r   r   r   r    r      sb   











4
8









8r   )#r   r}   r3   r\   r   r%   r   r*   rM   r   Zurllib.parser   ZCrypto.Cipherr   r   ZCrypto.Hashr   r   ZCrypto.PublicKeyr   ZCrypto.Randomr	   ZCrypto.Signaturer
   ZCrypto.Util.Paddingr   r   Zcmf.includer   r   r   r   Zmodules.auth.models.supervisorr   r   r   r   r   r    <module>   s*   