o
    þÑÐb}f  ã                   @   s   d Z ddlmZmZ ddlmZmZ ddlZddlZddl	Z	ddl
mZ ddlmZ zddlZW n   dZY ddlmZ dd	lmZmZ e e¡ZG d
d„ deƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZG dd„ deƒZdd„ Z dS )z5Implementing support for MySQL Authentication Pluginsé    )Ú	b64encodeÚ	b64decode)Úsha1Úsha256N)Úquote)Úuuid4é   )Úerrors)Únormalize_unicode_stringÚ"validate_normalized_unicode_stringc                   @   s6   e Zd ZdZdZdZ		ddd„Zdd„ Zd	d
„ ZdS )ÚBaseAuthPluginaÉ  Base class for authentication plugins


    Classes inheriting from BaseAuthPlugin should implement the method
    prepare_password(). When instantiating, auth_data argument is
    required. The username, password and database are optional. The
    ssl_enabled argument can be used to tell the plugin whether SSL is
    active or not.

    The method auth_response() method is used to retrieve the password
    which was prepared by prepare_password().
    FÚ Nc                 C   s"   || _ || _|| _|| _|| _dS )ZInitializationN)Ú
_auth_dataÚ	_usernameÚ	_passwordZ	_databaseÚ_ssl_enabled)ÚselfÚ	auth_dataÚusernameÚpasswordZdatabaseZssl_enabledÚinstance© r   ú]/var/www/secure340b-portal/env/lib/python3.10/site-packages/mysql/connector/authentication.pyÚ__init__E   s
   
zBaseAuthPlugin.__init__c                 C   s   t ‚)zåPrepares and returns password to be send to MySQL

        This method needs to be implemented by classes inheriting from
        this class. It is used by the auth_response() method.

        Raises NotImplementedError.
        )ÚNotImplementedError©r   r   r   r   Úprepare_passwordN   s   zBaseAuthPlugin.prepare_passwordc                 C   s(   | j r| jst dj| jd¡‚|  ¡ S )z°Returns the prepared password to send to MySQL

        Raises InterfaceError on errors. For example, when SSL is required
        by not enabled.

        Returns str
        ú{name} requires SSL©Úname)Úrequires_sslr   r	   ÚInterfaceErrorÚformatÚplugin_namer   r   r   r   r   Úauth_responseX   s
   ÿzBaseAuthPlugin.auth_response)NNNFN)	Ú__name__Ú
__module__Ú__qualname__Ú__doc__r    r#   r   r   r$   r   r   r   r   r   4   s    
ÿ	
r   c                   @   ó    e Zd ZdZdZdZdd„ ZdS )ÚMySQLNativePasswordAuthPluginzBClass implementing the MySQL Native Password authentication pluginFZmysql_native_passwordc           	   
   C   sÈ   | j st d¡‚| jsdS | j}t| jtƒr| j d¡}n| j}| j }d}z*t|ƒ ¡ }t|ƒ ¡ }t|| ƒ ¡ }dd„ t	||ƒD ƒ}t
jdg|¢R Ž }W |S  tyc } zt d |¡¡‚d}~ww )	z;Prepares and returns password as native MySQL 4.1+ passwordú"Missing authentication data (seed)ó    úutf-8Nc                 S   ó   g | ]\}}||A ‘qS r   r   )Ú.0Úh1Úh3r   r   r   Ú
<listcomp>   ó    zBMySQLNativePasswordAuthPlugin.prepare_password.<locals>.<listcomp>Z20BzFailed scrambling password; {0})r   r	   r!   r   Ú
isinstanceÚstrÚencoder   ÚdigestÚzipÚstructÚpackÚ	Exceptionr"   )	r   r   r   Zhash4Úhash1Úhash2Úhash3ÚxoredÚexcr   r   r   r   l   s.   
üÿ€ÿz.MySQLNativePasswordAuthPlugin.prepare_passwordN©r%   r&   r'   r(   r    r#   r   r   r   r   r   r*   f   ó
    r*   c                   @   r)   )ÚMySQLClearPasswordAuthPluginzAClass implementing the MySQL Clear Password authentication pluginTZmysql_clear_passwordc                 C   ó,   | j sdS | j }t|tƒr| d¡}|d S ©ú!Returns password as as clear textó    Úutf8©r   r4   r5   r6   ©r   r   r   r   r   r      ó   

z-MySQLClearPasswordAuthPlugin.prepare_passwordNrA   r   r   r   r   rC   Š   rB   rC   c                   @   r)   )ÚMySQLSHA256PasswordAuthPluginzÆClass implementing the MySQL SHA256 authentication plugin

    Note that encrypting using RSA is not supported since the Python
    Standard Library does not provide this OpenSSL functionality.
    TZsha256_passwordc                 C   rD   rE   rI   rJ   r   r   r   r   ¦   rK   z.MySQLSHA256PasswordAuthPlugin.prepare_passwordNrA   r   r   r   r   rL   œ   s
    rL   c                   @   s8   e Zd ZdZdZdZdZdZdd„ Zdd	„ Z	d
d„ Z
dS )Ú"MySQLCachingSHA2PasswordAuthPluginzÕClass implementing the MySQL caching_sha2_password authentication plugin

    Note that encrypting using RSA is not supported since the Python
    Standard Library does not provide this OpenSSL functionality.
    FZcaching_sha2_passwordé   é   c                 C   sž   | j st d¡‚| jsdS t| jtƒr| j d¡n| j}| j }t|ƒ ¡ }tƒ }| 	t|ƒ ¡ ¡ | 	|¡ | ¡ }dd„ t
||ƒD ƒ}tjdg|¢R Ž }|S )z» Returns a scramble of the password using a Nonce sent by the
        server.

        The scramble is of the form:
        XOR(SHA2(password), SHA2(SHA2(SHA2(password)), Nonce))
        r+   r,   r-   c                 S   r.   r   r   )r/   r0   Úh2r   r   r   r2   Ó   r3   z@MySQLCachingSHA2PasswordAuthPlugin._scramble.<locals>.<listcomp>Z32B)r   r	   r!   r   r4   r5   r6   r   r7   Úupdater8   r9   r:   )r   r   r   r<   r=   r?   r>   r   r   r   Ú	_scramble½   s"   

ÿÿ
z,MySQLCachingSHA2PasswordAuthPlugin._scramblec                 C   s2   t | jƒdkr|  ¡ S | jd | jkr|  ¡ S d S )Nr   r   )Úlenr   rR   Úperform_full_authenticationÚ_full_authenticationr   r   r   r   r   Ø   s
   z3MySQLCachingSHA2PasswordAuthPlugin.prepare_passwordc                 C   sF   | j st dj| jd¡‚| jsdS | j}t|tƒr| d¡}|d S )rF   r   r   rG   rH   )	r   r	   r!   r"   r#   r   r4   r5   r6   rJ   r   r   r   rU   ß   s   ÿ

z7MySQLCachingSHA2PasswordAuthPlugin._full_authenticationN)r%   r&   r'   r(   r    r#   rT   Zfast_auth_successrR   r   rU   r   r   r   r   rM   ²   s    rM   c                   @   s®   e Zd ZdZg d¢ZdZdZeZdZ	dZ
dZdZdZdZdd„ Zd	d
„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zdd„ Zd#dd„Zdd„ Zdd„ Zdd„ Zdd „ Zd!d"„ ZdS )$ÚMySQLLdapSaslPasswordAuthPlugina5  Class implementing the MySQL ldap sasl authentication plugin.

    The MySQL's ldap sasl authentication plugin support two authentication
    methods SCRAM-SHA-1 and GSSAPI (using Kerberos). This implementation only
    support SCRAM-SHA-1 and SCRAM-SHA-256.

    SCRAM-SHA-1 amd SCRAM-SHA-256
        This method requires 2 messages from client and 2 responses from
        server.

        The first message from client will be generated by prepare_password(),
        after receive the response from the server, it is required that this
        response is passed back to auth_continue() which will return the
        second message from the client. After send this second message to the
        server, the second server respond needs to be passed to auth_finalize()
        to finish the authentication process.
    )zSCRAM-SHA-1zSCRAM-SHA-256ZGSSAPIFZauthentication_ldap_sasl_clientNr   c                 C   s   t dd„ t||ƒD ƒƒS )Nc                 S   r.   r   r   )r/   Úb1Úb2r   r   r   r2     r3   z8MySQLLdapSaslPasswordAuthPlugin._xor.<locals>.<listcomp>)Úbytesr8   )r   Zbytes1Zbytes2r   r   r   Ú_xor  s   z$MySQLLdapSaslPasswordAuthPlugin._xorc                 C   s   t  ||| j¡}| ¡ S ©N)ÚhmacÚnewÚdef_digest_moder7   )r   r   ÚsaltZdigest_makerr   r   r   Ú_hmac  s   z%MySQLLdapSaslPasswordAuthPlugin._hmacc                 C   sJ   |  ¡ }|  ||d ¡}|}t|d ƒD ]}|  ||¡}|  ||¡}q|S )zŽPrepares Hi
        Hi(password, salt, iterations) where Hi(p,s,i) is defined as
        PBKDF2 (HMAC, p, s, i, output length of H).

        s      r   )r6   r`   ÚrangerZ   )r   r   r_   ÚcountÚpwÚhiZauxÚ_r   r   r   Ú_hi  s   z#MySQLLdapSaslPasswordAuthPlugin._hic                 C   s,   t |ƒ}t|ƒ}|d urt d |¡¡‚|S )Nzbroken_rule: {})Ú	norm_ustrÚ
valid_normr	   r!   r"   )r   ÚstringZnorm_strZbroken_ruleÚcharÚruler   r   r   Ú
_normalize!  s
   z*MySQLLdapSaslPasswordAuthPlugin._normalizec                 C   sH   d}t tƒ ƒ dd¡| _|j|  | j¡| jd}t|t ƒr"| d¡}|S )aq  This method generates the first message to the server to start the

        The client-first message consists of a gs2-header,
        the desired username, and a randomly generated client nonce cnonce.

        The first message from the server has the form:
            b'n,a=<user_name>,n=<user_name>,r=<client_nonce>

        Returns client's first message
        z.n,a={user_name},n={user_name},r={client_nonce}ú-r   )Ú	user_nameÚclient_noncerH   )	r5   r   Úreplacero   r"   rl   r   r4   r6   )r   Z
cfm_fprnatÚcfmr   r   r   Ú_first_message,  s   ÿ

z.MySQLLdapSaslPasswordAuthPlugin._first_messagec           	      C   s
  t  d| j¡ tjjj| j d¡tjj	d}z3t 
¡ }t  d¡ z|j W n" tjjjyG } zt  d|¡ | |¡ t d |¡¡‚d}~ww W n\ tjjjy¥ } zM| jset  d|¡ t d	 |¡¡‚zt  d
¡ tjj|| j d¡dd}|d }W n tjjjyš } zt  d|¡ t d |¡¡‚d}~ww W Y d}~nd}~ww tjjtjjtjjf}| jr¸| j}nd}t  d|¡ tj|tjjd}|| _ tj!||t"|ƒdd| _#z| j# $¡ }W n tjjjyü } zt  d|¡ t d |¡¡‚d}~ww t  d|¡ |S )z–Get a TGT Authentication request and initiates security context.

        This method will contact the Kerberos KDC in order of obtain a TGT.
        z# user name: %srH   )Z	name_typezE# Stored credentials found, if password was given it will be ignored.z Credentials has expired: %szCredentials has expired: {}Nz* Unable to retrieve stored credentials: %sz/Unable to retrieve stored credentials error: {}z5# Attempt to retrieve credentials with given passwordZinitiate)Úusager   z; Unable to retrieve credentials with the given password: %sz:Unable to retrieve credentials with the given password: {}zldap/ldapauthz# service principal: %s)r   ÚcredsÚflagsrs   z'Unable to initiate security context: %sz'Unable to initiate security context: {}z# initial client token: %s)%Ú_LOGGERÚdebugr   ÚgssapiÚrawÚnamesÚimport_namer6   ZNameTypeÚuserÚCredentialsZlifetimeÚ
exceptionsZExpiredCredentialsErrorÚwarningÚacquirer	   r!   r"   ÚmiscZGSSErrorr   ÚerrorZacquire_cred_with_passwordÚProgrammingErrorZRequirementFlagZmutual_authenticationZextended_errorZdelegate_to_peerÚkrb_service_principalÚNameZkerberos_principalÚtarget_nameZSecurityContextÚsumÚctxÚstep)	r   rn   ÚcredÚerrZacquire_cred_resultZflags_lZservice_principalZservkZinitial_client_tokenr   r   r   Ú_first_message_krb@  s‚   ÿ


€ýÿÿ
ÿÿþ€ýÿ€õþý€þz2MySQLLdapSaslPasswordAuthPlugin._first_message_krbc                 C   s@   t  d|¡ | j |¡}t  d|¡ t  d| jj¡ || jjfS )a   Continue with the Kerberos TGT service request.

        With the TGT authentication service given response generate a TGT
        service request. This method must be invoked sequentially (in a loop)
        until the security context is completed and an empty response needs to
        be send to acknowledge the server.

        Args:
            tgt_auth_challenge the challenge for the negotiation.

        Returns: tuple (bytearray TGS service request,
                        bool True if context is completed otherwise False).
        ztgt_auth challenge: %sz# context step response: %sz# context completed?: %s)rv   rw   rˆ   r‰   Úcomplete)r   Ztgt_auth_challengeÚrespr   r   r   Úauth_continue_krb„  s
   z1MySQLLdapSaslPasswordAuthPlugin.auth_continue_krbc              
   C   sÖ   | j js	t d¡‚t d|¡ t d| j j¡ z| j  |¡}t d|¡ W n tj	j
jyB } zt d|¡ t d |¡¡‚d}~ww t d|¡ td	ƒ}t d
|¡ | j j|dd}t d|d t|d ƒ¡ |jS )aP  Accept handshake and generate closing handshake message for server.

        This method verifies the server authenticity from the given message
        and included signature and generates the closing handshake for the
        server.

        When this method is invoked the security context is already established
        and the client and server can send GSSAPI formated secure messages.

        To finish the authentication handshake the server sends a message
        with the security layer availability and the maximum buffer size.

        Since the connector only uses the GSSAPI authentication mechanism to
        authenticate the user with the server, the server will verify clients
        message signature and terminate the GSSAPI authentication and send two
        messages; an authentication acceptance b'  ' and a
        OK packet (that must be received after sent the returned message from
        this method).

        Args:
            message a wrapped hssapi message from the server.

        Returns: bytearray closing handshake message to be send to the server.
        z"Security context is not completed.z# servers message: %sz# GSSAPI flags in use: %sz# unwraped: %sz#Unable to unwrap server message: %sz#Unable to unwrap server message: {}Nz# unwrapped server message: %ss      z# message response: %sF)Zencryptz*# wrapped message response: %s, length: %dr   )rˆ   r   r	   rƒ   rv   rw   Zactual_flagsÚunwraprx   ry   r~   ZBadMICErrorr!   r"   Ú	bytearrayÚwraprS   Úmessage)r   r“   Zunwrapedr‹   ÚresponseZwrapedr   r   r   Úauth_accept_close_handshakeš  s,   
ÿ€þÿz;MySQLLdapSaslPasswordAuthPlugin.auth_accept_close_handshakec              
   C   sˆ   | j  ¡ }|| _t d|¡ || jvr(t d |d 	| jdd… ¡| jd ¡¡‚d| j v r8t
s4t d¡‚|  ¡ S | j dkr@t| _|  ¡ S )	z„This method will prepare the fist message to the server.

        Returns bytes to send to the server as the first message.
        z read_method_name_from_server: %szpThe sasl authentication method "{}" requested from the server is not supported. Only "{}" and "{}" are supportedz", "Néÿÿÿÿs   GSSAPIzwModule gssapi is required for GSSAPI authentication mechanism but was not found. Unable to authenticate with the servers   SCRAM-SHA-256)r   Údecoder„   rv   rw   Úsasl_mechanismsr	   r!   r"   Újoinrx   rƒ   rŒ   r   r^   rr   )r   r„   Zauth_mechanismr   r   r   r$   Í  s(   

þþ
ÿ
z-MySQLLdapSaslPasswordAuthPlugin.auth_responsec                 C   sê  | j st d¡‚|  | j¡}|  |t| jƒ| j¡}t	 
dt|ƒ ¡ ¡ |  |d¡}t	 
dt|ƒ ¡ ¡ |  |¡ ¡ }t	 
dt|ƒ ¡ ¡ |  |d¡}t	 
dt|ƒ ¡ ¡ d d	 |  | j¡¡d
 | j¡g¡}t	 
d|¡ d || jd td |  | j¡¡ ¡ ƒ ¡ ¡d
 | j¡g¡}t	 
d|¡ |  || ¡ ¡}t	 
dt|ƒ ¡ ¡ |  ||¡}	t	 
dt|	ƒ ¡ ¡ t|  || ¡ ¡ƒ ¡ | _t	 
d| j¡ td |  | j¡¡ ¡ ƒ ¡ }
d d |
¡d
 | j¡d t|	ƒ ¡ ¡g¡}t	 
d|¡ | ¡ S )a¥  This method generates the second message to the server

        Second message consist on the concatenation of the client and the
        server nonce, and cproof.

        c=<n,a=<user_name>>,r=<server_nonce>,p=<client_proof>
        where:
            <client_proof>: xor(<client_key>, <client_signature>)

            <client_key>: hmac(salted_password, b"Client Key")
            <client_signature>: hmac(<stored_key>, <auth_msg>)
            <stored_key>: h(<client_key>)
            <auth_msg>: <client_first_no_header>,<servers_first>,
                        c=<client_header>,r=<server_nonce>
            <client_first_no_header>: n=<username>r=<client_nonce>
        r+   zsalted_password: %ss
   Client Keyzclient_key: %szstored_key: %ss
   Server Keyzserver_key: %sú,zn={}zr={}zclient_first_no_header: %szc={}zn,a={},zauth_msg: %szclient_signature: %szclient_proof: %szserver_auth_var: %szp={}zsecond_message: %s)r   r	   r!   rl   r   rf   r   Úserver_saltÚ
iterationsrv   rw   r   r—   r`   r^   r7   r™   r"   r   ro   Úservers_firstr6   Úserver_noncerZ   Úserver_auth_var)r   ZpasswZsalted_passwordZ
client_keyZ
stored_keyZ
server_keyZclient_first_no_headerZauth_msgZclient_signatureZclient_proofZclient_headerÚmsgr   r   r   Ú_second_messageé  sr   
þ
ÿ
þ

ÿÿÿ
û
ÿÿÿÿÿ
þz/MySQLLdapSaslPasswordAuthPlugin._second_messagec                 C   s2  |r	t |ttfƒst d |¡¡‚z| ¡ }|| _| d¡\}}}W n t	y1   t d |¡¡‚w | 
d¡rA| 
d¡rA| 
d¡sIt d |¡¡‚| j|v r]|dd… | _t d	| j¡ nt d
 |¡¡‚|dd… | _t d| jt| jƒ¡ z|dd… }t d |¡¡ t|ƒ| _W dS    t d |¡¡‚)zâValidates first message from the server.

        Extracts the server's salt and iterations from the servers 1st response.
        First message from the server is in the form:
            <server_salt>,i=<iterations>
        zUnexpected server message: {}rš   zr=zs=zi=z&Incomplete reponse from the server: {}é   Nzserver_nonce: %sz<Unable to authenticate response: response not well formed {}zserver_salt: %s length: %sziterations: {}z/Unable to authenticate: iterations not found {})r4   r‘   rY   r	   r!   r"   r—   r   ÚsplitÚ
ValueErrorÚ
startswithro   rž   rv   rw   r›   rS   Úintrœ   )r   r   Zr_server_nonceZs_saltZ	i_counterr   r   r   Ú_validate_first_reponse-  sN   ÿÿÿ
ÿþÿ
þ
ÿÿz7MySQLLdapSaslPasswordAuthPlugin._validate_first_reponsec                 C   s   |   |¡ |  ¡ S )zwreturn the second message from the client.

        Returns bytes to send to the server as the second message.
        )r§   r¡   )r   Zservers_first_responser   r   r   Úauth_continueU  s   
z-MySQLLdapSaslPasswordAuthPlugin.auth_continuec                 C   sT   |rt |tƒrt|ƒdks| d¡st d¡‚|dd…  ¡ }t d|¡ | j	|kS )aX  Validates second message from the server.

        The client and the server prove to each other they have the same Auth
        variable.

        The second message from the server consist of the server's proof:
            server_proof = HMAC(<server_key>, <auth_msg>)
            where:
                <server_key>: hmac(<salted_password>, b"Server Key")
                <auth_msg>: <client_first_no_header>,<servers_first>,
                            c=<client_header>,r=<server_nonce>

        Our server_proof must be equal to the Auth variable send on this second
        response.
        r¢   s   v=z(The server's proof is not well formated.Nzserver auth variable: %s)
r4   r‘   rS   r¥   r	   r!   r—   rv   rw   rŸ   )r   Zservers_secondZ
server_varr   r   r   Ú_validate_second_reponse]  s   
ÿÿ

z8MySQLLdapSaslPasswordAuthPlugin._validate_second_reponsec                 C   s   |   |¡s
t d¡‚dS )zÁfinalize the authentication process.

        Raises errors.InterfaceError if the ervers_second_response is invalid.

        Returns True in succesfull authentication False otherwise.
        z7Authentication failed: Unable to proof server identity.T)r©   r	   r!   )r   Zservers_second_responser   r   r   Úauth_finalizet  s   

z-MySQLLdapSaslPasswordAuthPlugin.auth_finalizer[   )r%   r&   r'   r(   r˜   r    r#   r   r^   ro   Zclient_saltr›   r„   rœ   rŸ   rZ   r`   rf   rl   rr   rŒ   r   r•   r$   r¡   r§   r¨   r©   rª   r   r   r   r   rV   ï   s4    D
3D(rV   c                 C   s0   t  ¡ D ]}|j| kr|  S qt d | ¡¡‚)a.  Return authentication class based on plugin name

    This function returns the class for the authentication plugin plugin_name.
    The returned class is a subclass of BaseAuthPlugin.

    Raises errors.NotSupportedError when plugin_name is not supported.

    Returns subclass of BaseAuthPlugin.
    z,Authentication plugin '{0}' is not supported)r   Ú__subclasses__r#   r	   ZNotSupportedErrorr"   )r#   Z	authclassr   r   r   Úget_auth_plugin  s   

ÿÿr¬   )!r(   Úbase64r   r   Úhashlibr   r   r\   Úloggingr9   Úurllib.parser   Úuuidr   rx   r   r	   Úutilsr
   rg   r   rh   Ú	getLoggerr%   rv   Úobjectr   r*   rC   rL   rM   rV   r¬   r   r   r   r   Ú<module>   s2   
2$=   