U
    lufÑ?  ã                   @   sŠ   d Z ddlZddlZddlmZmZmZmZmZm	Z	m
Z
mZ ddlZddlmZ ddlmZ ddlmZ dZd	ZG d
d„ dƒZddgZdS )z*Base implementation of 0MQ authentication.é    N)ÚAnyÚ	AwaitableÚDictÚListÚOptionalÚSetÚTupleÚUnion)Ú_check_version)Úz85é   )Úload_certificatesÚ*s   1.0c                   @   sÚ  e Zd ZU dZded< eed< eed< eeef ed< ded< e	e ed	< e	e ed
< eeeeef f ed< eeee
ef f ed< eed< d=ed eedœdd„Zddœdd„Zddœdd„Zeddœdd„Zeddœdd„Zd>eeeeef  ddœdd „Zd?eeeejf dd"œd#d$„Zd@eedd%œd&d'„Ze
ed(œd)d*„ZdAeee dd"œd+d,„Zee
 d-œd.d/„Zeeeeee
f d0œd1d2„Zee
eee
f d3œd4d5„Zee
eee
f d6œd7d8„ZdBe
e
e
edd:œd;d<„ZdS )CÚAuthenticatoraü  Implementation of ZAP authentication for zmq connections.

    This authenticator class does not register with an event loop. As a result,
    you will need to manually call `handle_zap_message`::

        auth = zmq.Authenticator()
        auth.allow("127.0.0.1")
        auth.start()
        while True:
            await auth.handle_zap_msg(auth.zap_socket.recv_multipart())

    Alternatively, you can register `auth.zap_socket` with a poller.

    Since many users will want to run ZAP in a way that does not block the
    main thread, other authentication classes (such as :mod:`zmq.auth.thread`)
    are provided.

    Note:

    - libzmq provides four levels of security: default NULL (which the Authenticator does
      not see), and authenticated NULL, PLAIN, CURVE, and GSSAPI, which the Authenticator can see.
    - until you add policies, all incoming NULL connections are allowed.
      (classic ZeroMQ behavior), and all PLAIN and CURVE connections are denied.
    - GSSAPI requires no configuration.
    zzmq.ContextÚcontextÚencodingÚ	allow_anyÚcredentials_providersz
zmq.SocketÚ
zap_socketÚ_allowedÚ_deniedÚ	passwordsÚcertsÚlogNúutf-8)r   r   r   c                 C   sb   t ddƒ |ptj ¡ | _|| _d| _i | _d | _t	ƒ | _
t	ƒ | _i | _i | _|pZt d¡| _d S )N)é   r   ÚsecurityFzzmq.auth)r
   ÚzmqÚContextÚinstancer   r   r   r   r   Úsetr   r   r   r   ÚloggingÚ	getLoggerr   )Úselfr   r   r   © r$   ú1/tmp/pip-unpacked-wheel-h6ekxre8/zmq/auth/base.pyÚ__init__:   s    
zAuthenticator.__init__)Úreturnc                 C   s:   | j jtjtjd| _d| j_| j d¡ | j 	d¡ dS )zCreate and bind the ZAP socket)Zsocket_classr   zinproc://zeromq.zap.01ZStartingN)
r   Úsocketr   ZREPZSocketr   ZlingerÚbindr   Údebug©r#   r$   r$   r%   ÚstartP   s    zAuthenticator.startc                 C   s   | j r| j  ¡  d| _ dS )zClose the ZAP socketN)r   Úcloser+   r$   r$   r%   ÚstopW   s    
zAuthenticator.stop)Ú	addressesr'   c                 G   s2   | j rtdƒ‚| j dd |¡¡ | j |¡ dS )a6  Allow IP address(es).

        Connections from addresses not explicitly allowed will be rejected.

        - For NULL, all clients from this address will be accepted.
        - For real auth setups, they will be allowed to continue with authentication.

        allow is mutually exclusive with deny.
        z Only use allow or deny, not bothzAllowing %sú,N)r   Ú
ValueErrorr   r*   Újoinr   Úupdate©r#   r/   r$   r$   r%   Úallow]   s    
zAuthenticator.allowc                 G   s2   | j rtdƒ‚| j dd |¡¡ | j |¡ dS )z§Deny IP address(es).

        Addresses not explicitly denied will be allowed to continue with authentication.

        deny is mutually exclusive with allow.
        z"Only use a allow or deny, not bothz
Denying %sr0   N)r   r1   r   r*   r2   r   r3   r4   r$   r$   r%   Údenyl   s    zAuthenticator.denyr   )Údomainr   r'   c                 C   s    |r|| j |< | j d|¡ dS )zõConfigure PLAIN authentication for a given domain.

        PLAIN authentication uses a plain-text password file.
        To cover all domains, use "*".
        You can modify the password file at any time; it is reloaded automatically.
        zConfigure plain: %sN©r   r   r*   )r#   r7   r   r$   r$   r%   Úconfigure_plainx   s    	
zAuthenticator.configure_plainÚ.)r7   Úlocationr'   c              
   C   sp   | j  d||¡ |tkr d| _nLd| _zt|ƒ| j|< W n2 tk
rj } z| j  d||¡ W 5 d}~X Y nX dS )a	  Configure CURVE authentication for a given domain.

        CURVE authentication uses a directory that holds all public client certificates,
        i.e. their public keys.

        To cover all domains, use "*".

        You can add and remove certificates in that directory at any time. configure_curve must be called
        every time certificates are added or removed, in order to update the Authenticator's state

        To allow all client keys without checking, specify CURVE_ALLOW_ANY for the location.
        zConfigure curve: %s[%s]TFz&Failed to load CURVE certs from %s: %sN)r   r*   ÚCURVE_ALLOW_ANYr   r   r   Ú	ExceptionÚerror)r#   r7   r;   Úer$   r$   r%   Úconfigure_curve…   s    zAuthenticator.configure_curve)r7   Úcredentials_providerr'   c                 C   s,   d| _ |dk	r|| j|< n| j d|¡ dS )aÁ  Configure CURVE authentication for a given domain.

        CURVE authentication using a callback function validating
        the client public key according to a custom mechanism, e.g. checking the
        key against records in a db. credentials_provider is an object of a class which
        implements a callback method accepting two parameters (domain and key), e.g.::

            class CredentialsProvider(object):

                def __init__(self):
                    ...e.g. db connection

                def callback(self, domain, key):
                    valid = ...lookup key and/or domain in db
                    if valid:
                        logging.info('Authorizing: {0}, {1}'.format(domain, key))
                        return True
                    else:
                        logging.warning('NOT Authorizing: {0}, {1}'.format(domain, key))
                        return False

        To cover all domains, use "*".
        FNz0None credentials_provider provided for domain:%s)r   r   r   r>   )r#   r7   rA   r$   r$   r%   Úconfigure_curve_callback    s    z&Authenticator.configure_curve_callback)Úclient_public_keyr'   c                 C   s   t  |¡ d¡S )að  Return the User-Id corresponding to a CURVE client's public key

        Default implementation uses the z85-encoding of the public key.

        Override to define a custom mapping of public key : user-id

        This is only called on successful authentication.

        Parameters
        ----------
        client_public_key: bytes
            The client public key used for the given message

        Returns
        -------
        user_id: unicode
            The user ID as text
        Úascii)r   ÚencodeÚdecode)r#   rC   r$   r$   r%   Úcurve_user_idÂ   s    zAuthenticator.curve_user_idc                 C   s   dS )z~Configure GSSAPI authentication

        Currently this is a no-op because there is nothing to configure with GSSAPI.
        Nr$   )r#   r7   r;   r$   r$   r%   Úconfigure_gssapi×   s    zAuthenticator.configure_gssapi)Úmsgc              	   ƒ   sÎ  t |ƒdk rJˆ j d|¡ t |ƒdk r4ˆ j d¡ nˆ  |d dd¡ dS |dd… \}}}}}}|dd… }| ˆ jd	¡}| ˆ jd	¡}|tkr²ˆ j d
|¡ ˆ  |dd¡ dS ˆ j d||||||¡ d}	d}
d}ˆ jr|ˆ jkrüd}	ˆ j d|¡ nd}
d}ˆ j d|¡ n>ˆ j	rR|ˆ j	kr@d}
d}ˆ j d|¡ nd}	ˆ j d|¡ d}|
s¤|dkr€|	s€ˆ j d¡ d}	n$|dkrât |ƒdkr¸ˆ j d|¡ ˆ  |dd¡ dS ‡ fdd„|D ƒ\}}ˆ  
|||¡\}	}nÂ|dkrJt |ƒdkrˆ j d|¡ ˆ  |dd¡ dS |d  }ˆ  ||¡I dH \}	}|	r¤ˆ  |¡}nZ|d!kr¤t |ƒdkr‚ˆ j d"|¡ ˆ  |dd¡ dS |d  }| d#¡}ˆ  ||¡\}	}|	r¼ˆ  |d$d%|¡ nˆ  |d|¡ dS )&zPerform ZAP authenticationé   z*Invalid ZAP message, not enough frames: %ré   zNot enough information to replyr   s   400s   Not enough framesNÚreplacezInvalid ZAP version: %rs   Invalid versionzQversion: %r, request_id: %r, domain: %r, address: %r, identity: %r, mechanism: %rFs	   NO ACCESSTzPASSED (allowed) address=%ss   Address not allowedzDENIED (not allowed) address=%ss   Address deniedzDENIED (denied) address=%szPASSED (not denied) address=%sÚ	anonymouss   NULLzALLOWED (NULL)s   PLAINzInvalid PLAIN credentials: %rs   Invalid credentialsc                 3   s   | ]}|  ˆ jd ¡V  qdS )rL   N)rF   r   )Ú.0Úcr+   r$   r%   Ú	<genexpr>$  s    z3Authenticator.handle_zap_message.<locals>.<genexpr>s   CURVEzInvalid CURVE credentials: %rr   s   GSSAPIzInvalid GSSAPI credentials: %rÚutf8ó   200ó   OK)Úlenr   r>   Ú_send_zap_replyrF   r   ÚVERSIONr*   r   r   Ú_authenticate_plainÚ_authenticate_curverG   Ú_authenticate_gssapi)r#   rI   ÚversionÚ
request_idr7   ÚaddressÚidentityZ	mechanismÚcredentialsÚallowedZdeniedÚreasonÚusernameÚpasswordÚkeyÚ	principalr$   r+   r%   Úhandle_zap_messageß   s”    ø


ÿ



z Authenticator.handle_zap_message)r7   ra   rb   r'   c                 C   s˜   d}d}| j r~|sd}|| j krR|| j | krL|| j | | krFd}qPd}qVd}nd}|rn| j d|||¡ q| j d	|¡ nd
}| j d|¡ ||fS )zPLAIN ZAP authenticationFó    r   Ts   Invalid passwords   Invalid usernames   Invalid domainz1ALLOWED (PLAIN) domain=%s username=%s password=%sz	DENIED %ss   No passwords definedzDENIED (PLAIN) %sr8   )r#   r7   ra   rb   r_   r`   r$   r$   r%   rW   C  s.    
üz!Authenticator._authenticate_plain)r7   Ú
client_keyr'   c                 Ã   s  d}d}| j r$d}d}| j d¡ nä| ji kr¨|s6d}|| jkr¢t |¡}| j|  ||¡}t|tƒrp|I dH }|r~d}d}nd}|rŠd	nd
}| j d|||¡ nd}n`|s°d}|| j	krt |¡}| j	|  
|¡ràd}d}nd}|rìd	nd
}| j d|||¡ nd}||fS )zCURVE ZAP authenticationFrf   TrS   z ALLOWED (CURVE allow any client)r   Ns   Unknown keyZALLOWEDZDENIEDz0%s (CURVE auth_callback) domain=%s client_key=%ss   Unknown domainz"%s (CURVE) domain=%s client_key=%s)r   r   r*   r   r   rE   ÚcallbackÚ
isinstancer   r   Úget)r#   r7   rg   r_   r`   Zz85_client_keyÚrÚstatusr$   r$   r%   rX   i  sV    




ü
üz!Authenticator._authenticate_curve)r7   rd   r'   c                 C   s   | j  d||¡ dS )zPNothing to do for GSSAPI, which has already been handled by an external service.z'ALLOWED (GSSAPI) domain=%s principal=%s)TrS   )r   r*   )r#   r7   rd   r$   r$   r%   rY   §  s    z"Authenticator._authenticate_gssapirM   )r[   Ústatus_codeÚstatus_textÚuser_idr'   c                 C   s\   |dkr|nd}t |tƒr(| | jd¡}d}| j d||¡ t|||||g}| j |¡ dS )z.Send a ZAP reply to finish the authentication.rR   rf   rL   zZAP reply code=%s text=%sN)	ri   ÚstrrE   r   r   r*   rV   r   Zsend_multipart)r#   r[   rm   rn   ro   ÚmetadataZreplyr$   r$   r%   rU   ¬  s    
zAuthenticator._send_zap_reply)Nr   N)r   N)r   r:   )r   N)r   N)rM   ) Ú__name__Ú
__module__Ú__qualname__Ú__doc__Ú__annotations__rp   Úboolr   r   r   Úbytesr   r&   r,   r.   r5   r6   r9   r	   ÚosÚPathLiker@   rB   rG   rH   r   re   r   rW   rX   rY   rU   r$   r$   r$   r%   r      sŽ   
   üü   ÿ þ   ÿ þ   ÿ þ"   ÿ þe  
þ' 
þ>
 ûúr   r<   )ru   r!   ry   Útypingr   r   r   r   r   r   r   r	   r   Z	zmq.errorr
   Z	zmq.utilsr   r   r   r<   rV   r   Ú__all__r$   r$   r$   r%   Ú<module>   s   (   ,