U
    ACej                     @   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
dMddZdNddZdd ZdOddZeedddZdPed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e	d)d* Zd+d, ZdQd-d.ZdRd/d0Ze	d1d2 Ze	d3d4 Z dSd6d7Z!e	d8d9 Z"e	dTd:d;Z# fd<d=Z$d>d? Z%e	d@dA Z&e	e'dBdCdDZ(e	dEdF Z)edGdH Z*edIdJ Z+edUdKdLZ,  Z-S )V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_jwt)jwtc                 C   sF   t t| d   }t t| d   }| d| S )NrZ   rY   rR   )r   rT   rU   rV   r4   rW   )r\   rZ   rY   r   r   r    
jwt_to_stru   s    zCmfAuth.jwt_to_strc                 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   r\   Zsignerdigestra   resr   r   r    rsa_sign_pack_jwt{   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   	signaturerb   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   re   )r   r   r   rW   rU   rh   )rk   rZ   rY   rl   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
   rg   )	rk   Zrsa_public_key_bytesrZ   rY   rl   rb   r\   rf   rm   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=)ri   rj   rn   	Exceptionr_   logger	exceptionr7   emailrQ   Zjwt_is_supportZjwt_is_match_orgospathexistsZPROJECT_DIRopenreadstripr   
startswithglobal_settingsZsupport_mode)r6   rk   r\   eobjorg_namefZpermr   r   r    from_jwt   s@    




"zCmfAuth.from_jwtc                 C   sb  | j dd|gdgd}|s0| j dd|gdgd}|sJ| j dd|gdgd}|stjj ( tjjddd d|id	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 ]}zh||jj	|r8tjj 6 tjjddd |jj	dddd
d|jj	|jj	d	 W 5 Q R X |W   S W q tk
rt } ztd| d|  W 5 d }~X Y qX qtjj 6 tjjddd |jj	ddd	d
d|jj	|jj	d	 W 5 Q R X |jj	 dr^| ||jj	r"tjj * tjjddd |dddd
d||d	 W 5 Q R X |S tjj * tjjddd |ddd	d
d||d	 W 5 Q R X d S )N	ext_loginZILIKEz***)filterfieldsr7   rx   Zident_failedr   failTr   )	operatecmf_model_nameparent
audit_dataresult_statuscurrent_transactionsecurity_levelparent_nameparent_codeZ
allow_ldap@)domainplugin.*)r   r   auth_successedZldap)r7   typeoku/   Ошибка авторизации через z: auth_failedZ
allow_basebase)getcmfutilcmfutildisable_aclmodelsCmfAuditaudit_eventauth_optionsrS   r7   r   CmfAuthLdapPlugincountlistZsigninr   ru   ri   rj   check_secretr   )r6   r7   Zchallenge_respr   _r   auth_pluginr   r   r   r    get_by_challenge_resp   s    
    
    *
    
    
    zCmfAuth.get_by_challenge_respc                 C   s"   |  }||_ ||_||| |S r$   )r7   rx   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ddgd}|rf| ||jjrftjj ( tj	j
ddd|id ddd	||d
	 W 5 Q R X |S tjj ( tj	j
ddd|id ddd	||d
	 W 5 Q R X d S )Nr   r7   rQ   r7   r   r   r   r   Tr   )	r   r   r   r   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)  s2    
    
    zCmfAuth.from_login_passwordc                 C   sR   t jjsd S tjj| dgddgddgdD ]"}|jr*| ||jr*t|j	q*d S )Nz-cmf_created_atr      r   cmf_created_at)r   Zorder_byslicer   )
ri   r   Zpassword_check_historyr   CmfAuthHistoryZslistr   r   ZCmfAuthReusePasswordErrorr   )r   r8   historyr   r   r    check_history<  s       
zCmfAuth.check_historyc                 C   s(   t |}t |}| j|||d d S )Nr8   )r1   r2   set_pass_hash_bytes)r   r   r#   r8   
hash_bytes
salt_bytesr   r   r    r   H  s    

zCmfAuth.set_pass_hashc              	   C   s   |d k	r|  | t| }t| }d| d| | _| j  tjj	| j
d}|r|j  d|_t  |jdd W 5 Q R X d S )Nzpbkdf2_sha256$100000$r   r7   FT)Z	only_data)r   r   rT   rW   r   Zpassword_changed_dateZset_nowr   	CmfPersonr   r7   Zpassword_must_changer   r   rM   )r   r   r   r8   r   r   personr   r   r    r   M  s    



zCmfAuth.set_pass_hash_bytesc                 C   s   t jS r$   )ri   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   rr   zutf-8)	rangeappendrandomchoicestringascii_lettersdigitsjoinr4   )r6   charsir   r   r    gen_salta  s    zCmfAuth.gen_salt   c                    s   |  dg tjtj  |s8d fddt|D }t|  }t	d|
 |d}| j|||of|d tjj . tjjdd	d| jid
dd| j| jdd	 W 5 Q R X |S )uO   
        Генерирует новый пароль
        :return:
        r7   rr   c                 3   s   | ]}t  V  qd S r$   )r   r   .0r   Zlettersr   r    	<genexpr>p  s     z)CmfAuth.reset_password.<locals>.<genexpr>r.   r/   r   reset_passwordr   Nr   Tr   )	r   r   r   r   r   r   r   r   r   )Zload_fieldsr   r   r   r   r   r   r   r3   r   r4   r   r   r   r   r   r   r   r   r7   )r   lengthr8   forcer#   r   r   r   r    r   h  s$    
    zCmfAuth.reset_passwordc                 C   s^   dt j }d|g}t||| tjj ( tjj	ddd d|idd||dd		 W 5 Q R X d S )
Nu&   Пароль для доступа к u   Пароль:send_passwordr   rx   r   Tr   )	r   r   r   r   r   r   r   r   r   )
rD   ZHOSTNAME_FQDNr   r   r   r   r   r   r   r   )r6   r8   rx   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   r   rM   ZpostrD   rE   Zstatus_coderu   rB   Zcookiesr   )r6   r7   r   r   sr   rr   r   r    create_person  s    

zCmfAuth.create_personc              	      s   | j jrZd| _| j jsZ| j D ].}| j | D ]}|  jd| d| 7  _q*q| jj | _t j||}| jjrt	
  tj| | jd  W 5 Q R X |S )Nrr   rs   rt   )r   r   )groups
is_changedrQ   is_nullrS   r~   superrM   r   r   r   r   r   )r   argskwargsr   Zgrp_namerc   	__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 )rt   r   )r   r   r   r   r    
<listcomp>  s     z)CmfAuth.prepare_scope.<locals>.<listcomp>rs   )rQ   r   setr   r   r   r   r    prepare_scope  s    zCmfAuth.prepare_scopec                 C   s   |  |}tjdkr|S |d d }zt|}W n  tk
rR   d}t|Y nX | ||}|sd|d d  d}t	| t||S )NFalserY   issuJ   Не удалось прочитать публичный ключ EvaTeamuE   Не удалось валидировать токен от EVA_APP r   !)
ro   rD   ZEVA_ACCOUNT_USEr   Zread_crm_pub_keyRuntimeErrorru   rp   loggingerror)r6   eva_app_tokenr\   r   Zcrm_pub_keyr   rg   r   r   r    check_token  s    


zCmfAuth.check_token)usersc             
   O   sT  |  |}|d d }|D ].}zt|d   }dddddd	g}	d
}
|dr| jt|d   |	d}
|
r||
_n| j||	d}
|
stj|d}
t	d|  |

  |dpd}t|  p||
_|d	pd}t|  pd
|
_|
jjri |
_|
jsg |
_||
jkr4|
j| g |
j|< |d rt	d|| ||
jkrr|
j| |
j|= d|
j_|

  W q|d D ]:}t	d| d| d|  |
j| | d|
j_q|d |
_t	d|  t	d|
j  |

  t  t	d|
j  W q tk
rH   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_listrx   r   NZ	old_loginr   r   u(   Создали пользователя rr   Zcmf_deletedu4   Пользователь {} удален из Eva {}Tr   u,   Добавляем пользователю u    права u    в Eva r   z
user_dict=zuser.groups=zuser.scope=u)   Не удалось обработать resultr   )r   r(   lowerr~   r   r7   r   r   r   rj   rM   rx   r   r   r   r   r   formatremover   r   Zcommit_with_eventrQ   ru   rw   )r6   r   r   r   r   r\   r   Z	user_dictr7   _fieldsuserrx   r   Zgrp_coder   r   r    rpc_account_sync_push  sj    

  





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>)r   r   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   sf   | j tj| jjd tjtjd }ttdtj	}|j
d|  f||d| tj|||f| d S )N)ZsecondsrX   ZAUTH_SESSION_COOKIE_DOMAINZsession_tokenr   expires)Zreauth_datedatetime	timedeltaZaccess_token_expires_inrS   rD   PROLONG_DAYSgetattrZrequestZhost
set_cookieZ	get_tokenr   set_nginx_token)r   responsecookie_kwargsr  cookie_domainr   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  rd   rD   TOKEN_TTL_DAYSr  nowr  r	  )r   r  r  r  r   r   r    set_access_token7  s    
	zCmfAuth.set_access_tokenc                 K   s6   |st j  t jtjd }| jd||d| d S )Nr  nginx_auth_tokenpassword123r  )r  r  )r  r  r  rD   r  r  )r  r  r  r  r   r   r    r  E  s      zCmfAuth.set_nginx_token)r=   )T)r   N)r   N)N)N)r   NN)N)N).__name__
__module____qualname__r'   Z	ts_lengthpropertyr!   r#   r-   classmethodr<   rI   rA   rN   r[   staticmethodrB   r]   r(   rd   rn   ro   rp   r   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      st   










'
2











@
!

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.includerx   r   r   r   Z
supervisorr   r   r   r   r   r    <module>   s*   