U
    d\                     @   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
dHddZdIddZdd ZdJddZdKd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dLd1d2Ze	d3d4 Ze	dMd5d6Z fd7d8Z d9d: Z!e	d;d< Z"e	e#d=d>d?Z$e	d@dA Z%edBdC Z&edDdE Z'edFdG Z(  Z)S )N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   Z
block_sizenewZMODE_CBCZencryptr   r+   )clsloginpasswordr,   startendZserver_randomZserver_timestampZserver_saltZtest_keyZclient_randomsecretZivZ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)hr=   r7   z/auth/?)	reset_pass_set_datadictreset_password_hashr7   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_urlsaferC   r)   r*   reset_password_expiressave)r   r>   r   r   r    rA   W   s    
zCmfAuth.reset_pass_set_datac                 C   s   | j  pt | j kS )u_    Проверяем что ссылка для сброса пароля не протухла )rL   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typrK   )r7   expscope.)r7   valuer)   r*   rQ   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 NrR   )r[   r
   r5   APPZrsa_private_keyr   updater4   signr   rT   rW   )r   rX   jwtZsignerdigestr_   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 )NrR   rP   u9   Время жизни токена закончилосьrZ   rY   )r   r   r5   r^   r4   r   r   r
   r]   rsa_public_keyverifyrW   rU   loadsr)   r*   gdebug)rjwtrZ   rY   	signaturera   r`   verifierZverifiedr   r   r    rsa_verify_unpack_jwt   s"    


zCmfAuth.rsa_verify_unpack_jwtc                 C   sJ   |  d\}}}t| }t| }t|}t|}||dS )NrR   rd   )r   r   r   rW   rU   rg   )rj   rZ   rY   rk   r   r   r    rsa_unpack_jwt   s    

zCmfAuth.rsa_unpack_jwtc           	      C   s^   |  d\}}}t }| d| }||  t|}t|}t	|}|
||S r\   )r   r   r5   r^   r4   r   r   r   Z
import_keyr
   rf   )	rj   Zrsa_public_key_bytesrZ   rY   rk   ra   r`   re   rl   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)emptyrY   r7   rQ   z/custom/org_name  :r   uC   from_jwt: Доступ по билету тех поддержки zfrom_jwt: jwt is ok, z, z, is_local=)rh   ri   rm   	Exceptionr]   logger	exceptionr7   emailrQ   Zjwt_is_supportZjwt_is_match_orgospathexistsZPROJECT_DIRopenreadstripr   
startswithZglobal_settingsZsupport_mode)r6   rj   r`   eobjorg_namefZ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r|j
d\}}tjj|drtjj|dgdD ]}zR|||r
tjj $ tjjddd |dddd	d
 W 5 Q R X |W   S W q tk
rF } 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 |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 )Nz***)	ext_loginfieldsr7   r   )rw   r   r   r   r7   failToperatecmf_model_nameparent
audit_dataresult_statuscelery_skipZ
allow_ldap@)domainplugin.*)r   r   Zldap)r7   typeoku/   Ошибка авторизации через z: Z
allow_base)getcmfutilcmfutildisable_aclmodelsCmfAuditaudit_eventauth_optionsrS   r7   r   CmfAuthLdapPlugincountlistZsigninrt   rh   ri   check_secretr   )r6   r7   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$   )r7   rw   set_pass_hash)r6   r7   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)
r6   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   r7   r   Tr   r   r   r   r   r   r   )r   r   r   rS   r   r   r   r   r   r   r   )r6   r7   r8   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   rT   rW   r   )r   r   r   r   r   r   r   r    r   4  s    zCmfAuth.set_pass_hash_bytesc                 C   s   t jS r$   )rh   r   )r6   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   rq   zutf-8)	rangeappendrandomchoicestringascii_lettersdigitsjoinr4   )r6   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:
        rq   c                 3   s   | ]}t  V  qd S r$   )r   r   .0r   Zlettersr   r    	<genexpr>Q  s     z)CmfAuth.reset_password.<locals>.<genexpr>r.   r/   reset_passwordr   r7   Nr   Tr   )r   r   r   r   r   r   r   r3   r   r4   r   r   r   r   r   r   r   r   r7   )r   lengthr8   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   rw   r   Tr   )
rD   ZPROJECT_NAMEr   r   r   r   r   r   r   r   )r6   r8   rw   ZsubjectZ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)r7   rg_member_ofz/auth/signupT)r7   Zgen_pwd)data   u>   Не удалось создать учётную записьaccess_token)r   )Zrequestsr   r   Z	CmfPersonrM   ZpostrD   rE   Zstatus_codert   rB   Zcookiesr   )r6   r7   r   r   sZ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 )Nrq   rr   rs   )groups
is_changedrQ   is_nullrS   r}   superrM   )r   argskwargsr   Zgrp_name	__class__r   r    rM   }  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 )rs   r   )r   r   r   r   r    
<listcomp>  s     z)CmfAuth.prepare_scope.<locals>.<listcomp>rr   )rQ   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.1rY   issuJ   Не удалось прочитать публичный ключ EvaTeamuE   Не удалось валидировать токен от EVA_APP r   !)rn   rD   ZEVA_ACCOUNT_USEZrequestZremote_addrr   Zread_crm_pub_keyRuntimeErrorrt   ro   loggingerror)r6   eva_app_tokenr`   r   Zcrm_pub_keyr   rf   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
        rY   r   r7   r   rQ   r   reg_org_name_listrw   r   r   )r7   u(   Создали пользователя rq   NZ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   ri   rM   rw   r   r   r   r   r   formatremover   r   Zcommit_with_eventrQ   rt   rv   )r6   r   r   r   r   r`   r   Z	user_dictr7   userrw   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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_frY   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   )rD   ZIS_BOX_VERSIONr   r   Z	CmfPluginr   r   rM   r   r   r   r   delete)r6   r   Zauth_pluginsr   r   r   r`   r   r   r   Zauth_plugin_objr   r   r    rpc_account_plugin_push  s2    



"
zCmfAuth.rpc_account_plugin_pushc                 K   sB   |j d|  f|| jtj| jjd tjtjd d| d S )NZsession_token)ZsecondsrX   r   Zexpires)	
set_cookieZ	get_tokenZreauth_datedatetime	timedeltaZaccess_token_expires_inrS   rD   PROLONG_DAYS)r   responsecookie_domaincookie_kwargsr   r   r    set_session_token  s    "zCmfAuth.set_session_tokenc                 K   sF   |j d| jtjd df|tj tjtjtj d d| d S )Nr   r   r   r   )r   rc   rD   TOKEN_TTL_DAYSr   nowr   r   )r   r   r   r   r   r   r    set_access_token	  s    
	zCmfAuth.set_access_tokenc                 K   s.   | j d|tj tjtjd d| d S )Nnginx_auth_tokenpassword123r   r   )r   r   )r   r   r   r   rD   r   )r   r   r   r   r   r    set_nginx_token  s      zCmfAuth.set_nginx_token)r=   )T)r   N)r   N)r   N)N)*__name__
__module____qualname__r'   Z	ts_lengthpropertyr!   r#   r-   classmethodr<   rI   rA   rN   r[   rc   staticmethodrm   rn   ro   r   r   r   r   r   r   r   r   r   r   r   r   rM   r   r   r   r   r   r   r   r   __classcell__r   r   r   r    r      sn   











'
-







	

9
!

r   )#r   r   r3   rU   r   r%   r   r*   rF   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.includerw   r   r   r   Z
supervisorr   r   r   r   r   r    <module>   s*   