U
    HdlS                     @   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/crm/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endZserver_randomZserver_timestampZserver_saltZtest_keyZ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)hrB   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%   token_urlsaferH   r)   r*   reset_password_expiressave)r   rC   r   r   r    rF   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 )NRS256JWT)algtyprQ   )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\   )re   r
   r6   APPrsa_private_keyr   updater4   signr   r^   ra   )r   rb   jwtsignerdigestrj   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|}tt t|d krtdt |d  d S ||dS )Nr\   rZ   u9   Время жизни токена закончилосьrd   rc   )r   r   r6   ri   r4   r   r   r
   rg   rsa_public_keyverifyra   r_   loadsr)   r*   gdebug)rjwtrd   rc   	signaturerm   rk   verifierverifiedr   r   r    rsa_verify_unpack_jwt   s"    


zCmfAuth.rsa_verify_unpack_jwtc                 C   sJ   |  d\}}}t| }t| }t|}t|}||dS )Nr\   rp   )r   r   r   ra   r_   rs   )rv   rd   rc   rw   r   r   r    rsa_unpack_jwt   s    

zCmfAuth.rsa_unpack_jwtc           	      C   s^   |  d\}}}t }| d| }||  t|}t|}t	|}|
||S rf   )r   r   r6   ri   r4   r   r   r   
import_keyr
   rr   )	rv   Zrsa_public_key_bytesrd   rc   rw   rm   rk   rq   rx   r   r   r    rsa_verify_jwt   s    


zCmfAuth.rsa_verify_jwtc              
   C   s|  t d |st d d S z| |}W n2 tk
r\ } ztjd d }W 5 d }~X Y nX |spt d d S | dd}|d d |_|d d |_|d d	 |_	d |_
d |_d }tjtd
 rttd
 }|  }W 5 Q R X | |_|j	pddD ]T}|r|| dr"d|_|dkr t jjr t d|  d|_
d|_q t d|j d|j	 d|j  |S )Nzfrom_jwt: startzfrom_jwt: warn not jwtzfail unpack jwtz2from_jwt: warn not cls.rsa_verify_unpack_jwt(rjwt)T)emptyrc   r:   r[   z/custom/org_name  :r   uC   from_jwt: Доступ по билету тех поддержки zfrom_jwt: jwt is ok, z, z, is_local=)rt   ru   rz   	Exceptionrg   logger	exceptionr:   emailr[   jwt_is_supportjwt_is_match_orgospathexistsPROJECT_DIRopenreadstripr   
startswithglobal_settingsZsupport_mode)r9   rv   rk   eobjorg_namefpermr   r   r    from_jwt   s@    




"zCmfAuth.from_jwtc                 C   s
  | j |dgd}|s$| j |dgd}|s8| j |dgd}|sttjj " tjjddd d|idd	d
 W 5 Q R X d S |jj	 drr|j
d\}}tjj|dgdD ]}zP|||rtjj $ tjjddd |dddd	d
 W 5 Q R X |W   S W q tk
r4 } ztd| d|  W 5 d }~X Y qX qtjj $ tjjddd |dddd	d
 W 5 Q R X d S |jj	 dr| ||jj	rtjj $ tjjddd |dddd	d
 W 5 Q R X |S tjj " tjjddd d|idd	d
 W 5 Q R X d S d S )Nz***)	ext_loginfieldsr:   r   )r   r   r   r   r:   failToperatecmf_model_nameparent
audit_dataresult_statuscelery_skipZ
allow_ldap@plugin.*)domainr   Zldap)r:   typeoku/   Ошибка авторизации через z: 
allow_base)getcmfutilcmfutildisable_aclmodelsCmfAuditaudit_eventauth_optionsr]   r:   r   CmfAuthLdapPluginlistZsigninr   rt   ru   check_secretr   )r9   r:   Zchallenge_respr   r   r   auth_pluginr   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   r>   Zsecret_hashZ
hash_partsZ	hash_algoZn_itersalt_b64hash_b64Zsalt_bZhash_br   r   r    r     s    


zCmfAuth.check_secretc              	   C   s   | j |dgd}|r\| ||jjr\tjj " tj	j
ddd|id ddd W 5 Q R X |S tjj " tj	j
ddd|id d	dd W 5 Q R X d S )
Nr   r   r   r   r:   r   Tr   r   r   r   r   r   r   )r   r   r   r]   r   r   r   r   r   r   r   )r9   r:   r;   r   r   r   r    from_login_password  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   /  s    

zCmfAuth.set_pass_hashc                 C   s2   t | }t | }d| d| | _d S )Nzpbkdf2_sha256$100000$r   )r   r^   ra   r   )r   r   r   r   r   r   r   r    r   4  s    zCmfAuth.set_pass_hash_bytesc                 C   s   t jS r$   )rt   r   )r9   r   r   r    current_auth?  s    zCmfAuth.current_authc                 C   s:   g }t dD ]}|ttjtj  qd|dS )N   r   zutf-8)	rangeappendrandomchoicestringascii_lettersdigitsjoinr4   )r9   charsir   r   r    gen_saltC  s    zCmfAuth.gen_salt   c              	      s   t jt j  |s,d fddt|D }t|  }td|	 |d}| 
|| tjj $ tjjddd| jid	d
dd W 5 Q R X |S )uO   
        Генерирует новый пароль
        :return:
        r   c                 3   s   | ]}t  V  qd S r$   )r   r   .0r   lettersr   r    	<genexpr>Q  s     z)CmfAuth.reset_password.<locals>.<genexpr>r.   r/   reset_passwordr   r:   Nr   Tr   )r   r   r   r   r   r   r   r3   r   r4   r   r   r   r   r   r   r   r   r:   )r   lengthr;   r#   r   r   r   r    r   J  s&       
  zCmfAuth.reset_passwordc              	   C   sX   dt j }d|g}t||| tjj " tjj	ddd d|iddd W 5 Q R X d S )	Nu&   Пароль для доступа к u   Пароль:send_passwordr   r   r   Tr   )
rI   PROJECT_NAMEr   r   r   r   r   r   r   r   )r9   r;   r   subjectmsg_contentsr   r   r    r   ]  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   	CmfPersonrT   postrI   rJ   status_coder   rG   cookiesr   )r9   r:   r   r   spersonrr   r   r    create_persong  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]   r   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 )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   |  |}tjdkr"tjdkr"|S |d d }zt|}W n  tk
r\   d}t|Y nX | 	||}|sd|d d  d}t
| t||S )	NFalsez	127.0.0.1rc   issuJ   Не удалось прочитать публичный ключ EvaTeamuE   Не удалось валидировать токен от EVA_APP r   !)r{   rI   EVA_ACCOUNT_USErequestremote_addrr   Zread_crm_pub_keyRuntimeErrorr   r}   loggingerror)r9   eva_app_tokenrk   r   Zcrm_pub_keyr   rr   r   r   r    check_token  s    

zCmfAuth.check_token)usersc             
   O   s  |  |}|d d }|D ]}zt|d   }| j|dddddd	gd
}	|	sztj|d}	td|  |		  |dpd}
t|
  p||	_
|d	pd}t|  pd|	_|	jjri |	_|	jsg |	_||	jkr|	j| g |	j|< |d rLtd|| ||	jkr0|	j| |	j|= d|	j_|		  W q|d D ]:}td| d| d|  |	j| | d|	j_qT|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
        rc   r   r:   r   r[   r   reg_org_name_listr   r   r   )r:   u(   Создали пользователя r   Ncmf_deletedu4   Пользователь {} удален из crm {}Tr   u,   Добавляем пользователю u    права u    в crm r   z
user_dict=zuser.groups=zuser.scope=u)   Не удалось обработать resultr   )r   r(   lowerr   r   r   r   r   ru   rT   r   r   r   r   r   r   formatremover   r   commit_with_eventr[   r   r   )r9   r   r   r   r   rk   r   Z	user_dictr:   userr   r   Zgrp_coder   r   r    rpc_account_sync_push  s^    

  




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   obj_dict
field_namer   r   r    copy_f  s    
z/CmfAuth.rpc_account_plugin_push.<locals>.copy_frc   r   pluginr  r   )ext_idr   r   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   )rI   IS_BOX_VERSIONr   r   	CmfPluginr   r  rT   r   r   r  r   delete)r9   r   Zauth_pluginsr   r   r  rk   r   r   r  Zauth_plugin_objr   r   r    rpc_account_plugin_push  s2    



"
zCmfAuth.rpc_account_plugin_push)rB   )T)r   N)r   N)r   N)N)'__name__
__module____qualname__r'   Z	ts_lengthpropertyr!   r#   r-   classmethodrA   rO   rF   rU   re   ro   staticmethodrz   r{   r}   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   











'
-







	

9r   )#r   datetimer3   r_   r   r%   r   r*   rK   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
supervisorr   r   r   r   r   r    <module>   s*   