U
    TFdQS                     @   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   (/opt/account/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_CBC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)hrE   r:   z/auth/?)	reset_pass_set_datadictreset_password_hashr:   configAUTH_SERVER_URLurllibparser   )r   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_urlsaferK   r)   r*   reset_password_expiressave)r   rF   r   r   r    rI   W   s    
zCmfAuth.reset_pass_set_datac                 C   s   | j  pt | j kS )u_    Проверяем что ссылка для сброса пароля не протухла )rU   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 )NRS256JWT)algtyprT   )r:   expscope.)r:   valuer)   r*   r]   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 Nr^   )rg   r
   r6   APPrsa_private_keyr   updater4   signr   r`   rc   )r   rd   jwtsignerdigestrl   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, если просрочили
        r^   Nrf   re   )r   r   r6   rk   r4   r   r   r
   ri   rsa_public_keyverifyrc   ra   loads)rjwtrf   re   	signaturero   rm   verifierZverifiedr   r   r    rsa_verify_unpack_jwt   s    


zCmfAuth.rsa_verify_unpack_jwtc                 C   sJ   |  d\}}}t| }t| }t|}t|}||dS )Nr^   rr   )r   r   r   rc   ra   ru   )rv   rf   re   rw   r   r   r    rsa_unpack_jwt   s    

zCmfAuth.rsa_unpack_jwtc           	      C   s^   |  d\}}}t }| d| }||  t|}t|}t	|}|
||S rh   )r   r   r6   rk   r4   r   r   r   
import_keyr
   rt   )	rv   Zrsa_public_key_bytesrf   re   rw   ro   rm   rs   rx   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   re   r\   z)from_jwt: reset auth, cause token expiredT)emptyr:   r]   z/custom/org_nameu,   from_jwt: нет билета доступаF :zfrom_jwt: jwt is ok, z, )printry   	Exceptionr)   get	TypeError
ValueErrordatetimenow	timestampr:   emailr]   jwt_is_supportjwt_is_match_orgospathexistsPROJECT_DIRopenreadr   
startswith)r9   rv   rm   er\   r   objforg_nameaccept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r:   r   )r   r   r   r   r:   failToperatecmf_model_nameparent
audit_dataresult_statuscelery_skipr   z$get_by_challenge_resp: wrong paddingr   rT   ok)r   modelsCmfAuditaudit_eventr1   r2   r   r5   r0   r6   r!   r7   decryptr   r   r   rc   r'   	ts_lengthr*   r)   )r9   r:   Zchallenge_respr   r<   r=   rB   encrypted_messagerC   Zres0res1Zres2r>   r@   r?   r   r   r    get_by_challenge_resp   sn    
  


  
  
  zCmfAuth.get_by_challenge_respc                 C   s"   |  }||_ ||_||| |S r$   )r:   r   set_pass_hash)r9   r:   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)
r9   rA   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r:   r   r   r:   r   Tr   r   r   r   r   r   r   )r   r   r   r_   r   r   r   )r9   r:   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`   rc   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   )r9   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   )r9   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   lettersr   r    	<genexpr>h  s     z)CmfAuth.reset_password.<locals>.<genexpr>r.   r/   reset_passwordr   r:   Nr   Tr   )r   r   r   r   r   typer   r3   r   r4   r   r   r   r   r:   )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   )rL   PROJECT_NAMEr   r   r   r   )r9   r;   r   subject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)r:   rg_member_ofz/auth/signupT)r:   Zgen_pwd)data   u>   Не удалось создать учётную записьaccess_token)r   )requestsr   r   	CmfPersonrV   postrL   rM   status_coder   rJ   cookiesr   )r9   r:   r   r   s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   r~   r   )groups
is_changedr]   is_nullr_   stripsuperrV   )r   argskwargsr   Zgrp_name	__class__r   r    rV     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 )r   r   )r   r   r   r   r    
<listcomp>  s     z)CmfAuth.prepare_scope.<locals>.<listcomp>r~   )r]   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 )Nre   issuJ   Не удалось прочитать публичный ключ EvaTeamuE   Не удалось валидировать токен от EVA_APP r   !)rz   r   Zread_crm_pub_keyRuntimeErrorr   r|   loggingerror)r9   eva_app_tokenrm   r   Zcrm_pub_keyr   rt   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
        re   r   r:   r   r]   auth_pluginreg_org_name_listr   r   u(   Создали пользователя r   r   r   Ncmf_deletedu4   Пользователь {} удален из crm {}Tr   u,   Добавляем пользователю u    права u    в crm auth_optionsz
user_dict=zuser.groups=zuser.scope=u)   Не удалось обработать resultr   )r   r(   lowerr   r   r   r   r   debugrV   r   r   r   r   r   r   formatremover   r   commit_with_eventr]   r   	exception)r9   r   r   r   r   rm   r   Z	user_dictr:   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codeext_ipcmf__id)r   endswithhasattrsetattr)r   Zobj_dict
field_namer   r   r    copy_f  s    
z/CmfAuth.rpc_account_plugin_push.<locals>.copy_fre   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   )rL   IS_BOX_VERSIONr   r   	CmfPluginr   r  rV   CmfAuthLdapPluginr   r  listdelete)r9   r   Zauth_pluginsr   r   r  rm   r   r   r  Zauth_plugin_objr   r   r    rpc_account_plugin_push  s2    



"
zCmfAuth.rpc_account_plugin_push)rE   )T)r   N)r   N)r   N)N)'__name__
__module____qualname__r'   r   propertyr!   r#   r-   classmethodrD   rR   rI   rW   rg   rq   staticmethodry   rz   r|   r   r   r   r   r   r   r   r   r   r   r   r   rV   r   r   r  r  r  __classcell__r   r   r   r    r      sb   











4
8

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