
    p!                     l   d Z ddlmZ ddlmZ ddlmZ ddlmZ ddlZddlZddlZddl	m
Z
 ddlZddlmZ dd	lmZ dd
lmZ daej"                  j%                  ej"                  j'                  ddd            ZdZdZ G d de      Z G d de      Zd Zd Zd Zd Zd Z G d de      Z d Z!d Z"y)z)Manages device context mTLS certificates.    )absolute_import)print_function)division)unicode_literalsN)config)	exception)	boto_util)execution_util~z.secureConnectzcontext_aware_metadata.jsoncert_provider_commandz--with_passphrasec                       e Zd ZdZy)CertProvisionErrorz9Represents errors when provisioning a client certificate.N__name__
__module____qualname____doc__     'platform/gsutil/gslib/context_config.pyr   r   +   s    Ar   r   c                       e Zd ZdZy)(ContextConfigSingletonAlreadyExistsErrorz>Error for when create_context_config is called multiple times.Nr   r   r   r   r   r   0   s    Fr   r   c                     | j                  d      r| j                  d      rdd| dd fS | j                  d      r| j                  d      rdd| dd fS y	)
z)Returns (begin:bool, end:bool, name:str).z-----BEGIN z-----TF   z	-----END 	   )FF )
startswithendswith)lines    r   _is_pem_section_markerr!   5   sY    	__]#g(>R##{#g(>$Qr
""r   c                     i }g }d}| j                         D ]  }|j                         }|st        |      \  }}}|rA|r|j                  d|z         ||j	                         v r|j                  d|z         |}g }n7|r5|s|j                  d|z         n||k7  r|j                  d|d|       d}|s|j                  |       |sdj                  |      dz   ||<   d} |r|j                  d|z         |S )	a  Returns dict with {name: section} by parsing contents in PEM format.

  A simple parser for PEM file. Please see RFC 7468 for the format of PEM
  file. Not using regex to improve performance catching nested matches.
  Note: This parser requires the post-encapsulation label of a section to
  match its pre-encapsulation label. It ignores a section without a
  matching label.

  Args:
    contents (str): Contents of a PEM file.
    logger (logging.logger): gsutil logger.

  Returns:
    A dict of the PEM file sections.
  Nz0Section %s missing end line and will be ignored.zASection %s already exists, and the older section will be ignored.z8Section %s missing a beginning line and will be ignored.zSection z% missing a matching end line. Found: 
zSection %s missing an end line.)
splitlinesstripr!   warningkeysappendjoin)	contentsloggerresult	pem_linespem_section_namer    beginendnames	            r   _split_pem_into_sectionsr2   ?   s%     &)!!#d::<D-d3E3	I'( 	)		 %'+, 	-i	FM	Ot#($0 	1t	yy+d2t9 $< 
NN47GGH	-r   c                      t         j                  j                  t              } t         j                  j	                  |       sy| S )zChecks for content aware metadata.

  If content aware metadata exists, return its absolute path;
  otherwise, returns None.

  Returns:
    str: Absolute path if exists. Otherwise, None.
  N)ospath
expanduser_DEFAULT_METADATA_PATHexists)metadata_paths    r   _check_pathr:   w   s2     ''$$%;<-		&	r   c                     	 t        |       5 }t        j                  |      cddd       S # 1 sw Y   yxY w# t        $ r}t	        |      d}~ww xY w)zLoads context aware metadata from the given path.

  Returns:
      dict: The metadata JSON.

  Raises:
      CertProvisionError: If failed to parse metadata as JSON.
  N)openjsonload
ValueErrorr   )r9   fes      r   _read_metadata_filerB      sB     	m	YYq\ 
			  
Q
 s)   8 ,	8 58 8 	AAAc                      t               } | st        d      t        |       }t        |vrt        d      |t           }t        |vr|j                  t               |S )zLoads default cert provider command.

  Returns:
      str: The default command.

  Raises:
      CertProvisionError: If command cannot be found.
  z+Client certificate provider file not found.z.Client certificate provider command not found.)r:   r   rB   _CERT_PROVIDER_COMMAND(_CERT_PROVIDER_COMMAND_PASSPHRASE_OPTIONr(   )r9   metadata_jsoncommands      r   _default_commandrH      s]     --	
J
KK%m4-=0
M
NN01'.g=NN;<	.r   c                   "    e Zd ZdZd Zd Zd Zy)_ContextConfigzRepresents the configurations associated with context aware access.

  Only one instance of Config can be created for the program.
  c                    || _         t        j                  dd      | _        d| _        | j                  syt        j                  | j                         t        j                  j                  t        j                         d      | _        	 | j                  | j                         y# t        $ r(}| j                   j                  d|z         Y d}~yd}~ww xY w)zQInitializes config.

    Args:
      logger (logging.logger): gsutil logger.
    Credentialsuse_client_certificateNzcaa_cert.pemz*Failed to provision client certificate: %s)r+   r   getboolrM   client_cert_pathatexitregister_unprovision_client_certr4   r5   r)   r	   GetGsutilStateDir_provision_client_certr   error)selfr+   rA   s      r   __init__z_ContextConfig.__init__   s     DK"(..1I#KD D&& OOD112GGLL)D)D)F)79DJ !!$"7"78 J
kkDqHIIJs   B* *	C3CCc                 `   t        j                  ddd      }|r|j                  d      }n
t               }	 t	        j
                  |      \  }}t        || j                        }t        |d      5 }|j                  |d          d|v r0|j                  |d          |d   j                         d	   | _        n|j                  |d
          d| _        ddd       y# 1 sw Y   yxY w# t        j                  t        f$ r}t        |      d}~wt         $ r}t        d|z        d}~ww xY w)zDExecutes certificate provider to obtain client certificate and keys.rL   r   N zw+CERTIFICATEzENCRYPTED PRIVATE KEY
PASSPHRASE   zPRIVATE KEYz6Invalid output format from certificate provider, no %s)r   getsplitrH   r
   ExecuteExternalCommandr2   r+   r<   writer$   client_cert_passwordr   ExternalBinaryErrorOSErrorr   KeyError)	rV   	cert_pathcert_command_stringcert_commandcommand_stdout_string_sectionsr@   rA   s	            r   rT   z%_ContextConfig._provision_client_cert   s(    **]4K%)+(..s3l &'lH!/!F!F
"Q **?Mh	4 A	'("h.
''(23
4&.|&<&G&G&I!&L$
#
''(=)
*&*$
# !   ))73 "q!! H
BQ
FH HHsB   :C* 1A$CC* C'#C* 'C* *D-DD-D((D-c                    | j                   I	 t        j                  | j                          | j                  j	                  d| j                   z         yy# t
        $ r(}| j                  j                  d|z         Y d}~yd}~ww xY w)z@Cleans up any files or resources provisioned during config init.NzUnprovisioned client cert: %sz'Failed to remove client certificate: %s)rO   r4   remover+   debugrc   rU   )rV   rA   s     r   rR   z'_ContextConfig._unprovision_client_cert   s}    (I
		$''(9//0 	1 )
  ICaGHHIs   AA 	B BBN)r   r   r   r   rW   rT   rR   r   r   r   rJ   rJ      s    
J4H:Ir   rJ   c                 <    t         st        |       a t         S t        )zShould be run once at gsutil startup. Creates global singleton.

  Args:
    logger (logging.logger): For logging during config functions.

  Returns:
    New ContextConfig singleton.

  Raises:
    Exception if singleton already exists.
  )_singleton_configrJ   r   )r+   s    r   create_context_configrp      s     
&v.00r   c                      t         S )zuRetrieves ContextConfig global singleton.

  Returns:
    ContextConfig or None if global singleton doesn't exist.
  )ro   r   r   r   get_context_configrr   
  s
     
r   )#r   
__future__r   r   r   r   rP   r=   r4   botor   gslibr   gslib.utilsr	   r
   ro   r5   r6   r)   r7   rD   rE   	Exceptionr   r   r!   r2   r:   rB   rH   objectrJ   rp   rr   r   r   r   <module>ry      s    0 & %  '   	    ! &   ++GGLL&(EFH 0 +> ( 
y 
5p  2EIV EIP1&r   