o
    PI                     @   s  d 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Zddl	m
Z ddlmZ ddlmZ dd	lmZ dd
lmZ ddlm
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ZdZdZdZdZdd Zej e! ddZ"dd Z#G dd dZ$G dd de
j%Z&G dd de
j%Z'd d! Z(d"d# Z)d$d% Z*d&d' Z+d(d) Z,d*e-fd+d,Z.d-d. Z/G d/d0 d0ej0Z1G d1d2 d2e2Z3G d3d4 d4e3Z4G d5d6 d6e3Z5da6d7d8 Z7dS )9z'Helper module for context aware access.    )absolute_import)division)unicode_literalsN)
exceptions)_mtls_helper)enterprise_certificate_config)
argv_utils)config)log)
properties)files)	platformsaccess_deniedzAccount restricteda
  Access was blocked by Context Aware Access. If you are using gcloud on a remote machine via SSH and your organization requires gcloud from a company managed device, please first CRD (Chrome Remote Desktop) or RDP (Remote Desktop Protocol) into your remote machine and log into Chrome using your credentials to register your remote machine. After that, you may need to wait for a few minutes before retrying. If you are using cloud shell, you don't need to run `gcloud auth login` and can run your gcloud commands directly.ag  Access was blocked by Context Aware Access. Possible solutions:

 1. Please restart your terminal if you haven't already and try again. 

 2. If you are using gcloud on Cloudtop or other remote machines via SSH and your organization requires gcloud from a company managed device, please first CRD (Chrome Remote Desktop) or RDP (Remote Desktop Protocol) into your remote machine and log into Chrome using your credentials to register your remote machine. After that, you may need to wait for a few minutes before retrying. 

 3. Please do not use gcloud in Cloud Shell as it is not a Google managed device. Choose corp machines instead, for example, gMac, gLinux, gWindows, or Cloudtop.

 If you are not able to do any of the above, please apply for policy exemption via go/gcloud-cba-exemption. If you have any questions, please reach out to go/gcloud-cba-investigation.a  Access was blocked by Context Aware Access. You can try to fix this by updating the context_aware/use_client_certificate flag to true. To do that, run `gcloud config set context_aware/use_client_certificate true` and try running your command again. If your device has the env variable CLOUDSDK_CONTEXT_AWARE_USE_CLIENT_CERTIFICATE configured, ensure it is set to true as that overrides the gcloud properties flag.c                 C   s   t | }t|v ot|v S N)six	text_type!CONTEXT_AWARE_ACCESS_DENIED_ERROR-CONTEXT_AWARE_ACCESS_DENIED_ERROR_DESCRIPTION)excexc_text r   >/tmp/google-cloud-sdk/lib/googlecloudsdk/core/context_aware.pyIsContextAwareAccessDeniedErrorU   s   
r   z.secureConnectzcontext_aware_metadata.jsonc                  C   s   t jjj } | dur| S tS )z=Return the file path of the context aware configuration file.N)r   VALUEScontext_awareauto_discovery_file_pathGet DEFAULT_AUTO_DISCOVERY_FILE_PATH)cfg_filer   r   r   _AutoDiscoveryFilePathb   s   r   c                   @   s   e Zd ZdZedd ZdS )ContextAwareAccessErrorz<Get ContextAwareAccessError based on the users organization.c                   C   s"   t  rt jjj stS tS tS )z}Get ContextAwareAccessError based on the users organization.

    Returns:
      str: Context aware access help message.
    )	r   IsInternalUserCheckr   r   use_client_certificateGetBool*CONTEXT_AWARE_ACCESS_MTLS_HELP_MSG_GOOGLER%CONTEXT_AWARE_ACCESS_HELP_MSG_GOOGLERCONTEXT_AWARE_ACCESS_HELP_MSGr   r   r   r   r   n   s
   zContextAwareAccessError.GetN)__name__
__module____qualname____doc__staticmethodr   r   r   r   r   r    k   s    r    c                       s   e Zd Z fddZ  ZS )ConfigExceptionc                    s   t t| d d S )Nz}Use of client certificate requires endpoint verification agent. Run `gcloud topic client-certificate` for installation guide.)superr,   __init__)self	__class__r   r   r.      s   
zConfigException.__init__)r'   r(   r)   r.   __classcell__r   r   r0   r   r,   }   s    r,   c                   @   s   e Zd ZdZdS )CertProvisionExceptionz9Represents errors when provisioning a client certificate.N)r'   r(   r)   r*   r   r   r   r   r3      s    r3   c              
   C   sl   zt jd| d\}}}}|r||fW S W t  tjy5 } zt|}t|| W Y d}~t d}~ww )aa  Generates the client SSL credentials.

  Args:
    config_path: path to the context aware configuration file.

  Raises:
    CertProvisionException: if the cert could not be provisioned.
    ConfigException: if there is an issue in the context aware config.

  Returns:
    Tuple[bytes, bytes]: client certificate and private key bytes in PEM format.
  Fgenerate_encrypted_keycontext_aware_metadata_pathN)r   get_client_ssl_credentialsgoogle_auth_exceptionsClientCertErrorr3   r   
raise_fromr,   )config_pathhas_cert
cert_bytes	key_bytes_
caught_excnew_excr   r   r   SSLCredentials   s    

rB   c           
   
   C   s   z?t jd| d\}}}}|r<tjt jd}t	|}|
| |
| W d   n1 s2w   Y  ||fW S W t  tjy^ } zt|}t|| W Y d}~t d}~w tjyy }	 ztd| |	 W Y d}	~	t d}	~	ww )a  Generates the encrypted client SSL credentials.

  The encrypted client SSL credentials are stored in a file which is returned
  along with the password.

  Args:
    config_path: path to the context aware configuration file.

  Raises:
    CertProvisionException: if the cert could not be provisioned.
    ConfigException: if there is an issue in the context aware config.

  Returns:
    Tuple[str, bytes]: cert and key file path and passphrase bytes.
  Tr4   zcaa_cert.pemNz-context aware settings discovery file %s - %s)r   r7   ospathjoinr	   Pathsglobal_config_dirr   BinaryFileWriterwriter8   r9   r3   r   r:   Errorr
   debugr,   )
r;   r<   r=   r>   passphrase_bytes	cert_pathfr@   rA   er   r   r   EncryptedSSLCredentials   s0   


rP   c                 C   s   t  }d|v r
dS d| vrdS t| d  dk rdS d| vr"dS tg d}tjjj	 r8t
 r8|d t| d  }||krFdS dS )	zVCheck if ECP binaries should be installed and the ECP config updated to point to them.initFcert_configs   libs)ecp
ecp_clienttls_offloadecp_http_proxyT)r   GetDecodedArgvlenkeyssetr   r   r   use_ecp_http_proxyr#   r!   add)cert_configargsexpected_keysactual_keysr   r   r   _ShouldRepairECP   s&   
rc   c                  C   s>   t j } | jt jjkr| jt jjkrt j	 rt jj
| _| S r   )r   PlatformCurrentoperating_systemOperatingSystemMACOSXarchitectureArchitecturex86_64IsActuallyM1ArmArchitecturearm)platformr   r   r   _GetPlatform   s   


ro   c              
   C   s   t jjjd ddlm} t }|jdd|d}z	|	dgd}W n t
jy< } zt
djt jd	|d}~ww |rStjt|| d
 t jjjd dS dS )zInstall ECP and update the ecp config to include the new binaries.

  Args:
    cert_config_file_path: The filepath of the active certificate config.

  See go/gcloud-ecp-repair.
  Fr   )update_managerN)sdk_rooturlplatform_filterzenterprise-certificate-proxyzDevice appears to be enrolled in Certificate Based Access but is missing critical components. Installing enterprise-certificate-proxy and restarting gcloud.a  Enterprise Certificate Proxy cannot be repaired because you do not have permission to modify the Google Cloud SDK installation directory [{sdk_root}]. Please reinstall Google Cloud SDK in a location where you have write permissions, such as your home directory.)rq   )output_fileT)r   r   r   r"   Setgooglecloudsdk.core.updaterrp   ro   UpdateManagerEnsureInstalledAndRestartr   RequiresAdminRightsErrorrJ   formatr	   rF   rq   r   update_configplatform_to_config)cert_config_file_pathrp   rn   updateralready_installedrO   r   r   r   
_RepairECP   s:   	r   certificate_config_file_pathc              
   C   s   zt | }t|W S  ty) } ztd|}t|| W Y d}~dS d}~w t jyG } ztd|}t|| W Y d}~dS d}~ww )aL  Loads and returns the enterprise certificate configuration from the given file path.

  Args:
    certificate_config_file_path: The path to the JSON configuration file.

  Returns:
    A dictionary representing the parsed JSON configuration.

  Raises:
    CertProvisionException: If the file cannot be read or is not valid JSON.
  z?The enterprise certificate config file is not a valid JSON fileNz1Failed to read enterprise certificate config file)	r   ReadFileContentsjsonloads
ValueErrorr3   r   r:   rJ   )r   contentr@   rA   r   r   r   GetCertificateConfig'  s"   
r   c                  C   s   t jjj } | du rt } tj	| sdS t
| }d|v r6d|d v r6tj	|d d s6td| d|v r\d|d v r\tj	|d d s\t jjj r\t  r\td| t|rdt|  | S )a>  Finds, loads, validates, and potentially repairs the enterprise certificate config file.

  This function determines the path to the config file by first checking the
  `context_aware.certificate_config_file_path` property. If that is not set,
  it falls back to the default path from `config.CertConfigDefaultFilePath()`.

  If the file exists, it's read and parsed as JSON. It then performs
  validations, such as ensuring that if an ECP binary path is specified, that
  binary file actually exists on the filesystem.

  Lastly, it may also trigger an in-place repair of the ECP configuration
  by installing missing components if needed.

  Returns:
      str: The path to the config file if found and valid.
      Returns None if the config file does not exist.

  Raises:
      CertProvisionException:
          - If the config file fails to be read (e.g., file permissions).
          - If the config file content is not valid JSON.
          - If an 'ecp' or 'ecp_http_proxy' (if enabled) binary path is
          specified
            in the config but the file is not found.
  NrT   rU   a  Enterprise certificate provider (ECP) binary path (cert_config["libs"]["ecp"]) specified in enterprise certificate config file was not found. Cannot use mTLS with ECP if the ECP binary does not exist. Please check the ECP configuration. See `gcloud topic client-certificate` to learn more about ECP. 
If this error is unexpected either delete {} or generate a new configuration with `$ gcloud auth enterprise-certificate-config create --help` rX   a  Enterprise certificate provider (ECP) HTTP proxy binary path (cert_config["libs"]["ecp_http_proxy"]) specified in enterprise certificate config file was not found. Cannot use mTLS with ECP if the ECP HTTP proxy binary does not exist. Please check the ECP configuration. See `gcloud topic client-certificate` to learn more about ECP. 
If this error is unexpected either delete {} or generate a new configuration with `$ gcloud auth enterprise-certificate-config create --help` )r   r   r   r   r   r	   CertConfigDefaultFilePathrC   rD   existsr   r3   rz   r]   r#   r!   rc   r   )	file_pathr_   r   r   r   _GetCertificateConfigFileD  sB   r   c                   @   s   e Zd ZdZdZdS )
ConfigTyperS      N)r'   r(   r)   ENTERPRISE_CERTIFICATEON_DISK_CERTIFICATEr   r   r   r   r     s    r   c                   @   s$   e Zd ZdZedd Zdd ZdS )_ConfigImpla  Represents the configurations associated with context aware access.

  Both the encrypted and unencrypted certs need to be generated to support HTTP
  API clients and gRPC API clients, respectively.

  Only one instance of Config can be created for the program.
  c                 C   sf   t jjj s	dS t }|rtd t|S td t	 }t
|\}}t|\}}t|||||S )zLoads the context aware config.Nz'enterprise certificate is used for mTLSz$on disk certificate is used for mTLS)r   r   r   r"   r#   r   r
   rK   _EnterpriseCertConfigImplr   rB   rP   _OnDiskCertConfigImpl)clsr   r;   r=   r>   encrypted_cert_pathpasswordr   r   r   Load  s   


z_ConfigImpl.Loadc                 C   s
   || _ d S r   )config_type)r/   r   r   r   r   r.     s   
z_ConfigImpl.__init__N)r'   r(   r)   r*   classmethodr   r.   r   r   r   r   r     s
    
r   c                       s2   e Zd ZdZ fddZedefddZ  ZS )r   z{Represents the configurations associated with context aware access through a enterprise certificate on TPM or OS key store.c                    s   t t| tj || _d S r   )r-   r   r.   r   r   r   )r/   r   r0   r   r   r.     s   

z"_EnterpriseCertConfigImpl.__init__returnc                 C   s   t jjj }|ot  S )zHReturns True if the necessary conditions to use the local proxy are met.)r   r   r   r]   r#   r!   )r/   r]   r   r   r   use_local_proxy  s   z)_EnterpriseCertConfigImpl.use_local_proxy)	r'   r(   r)   r*   r.   propertyboolr   r2   r   r   r0   r   r     s
    r   c                       s(   e Zd ZdZ fddZdd Z  ZS )r   a&  Represents the configurations associated with context aware access through a certificate on disk.

  Both the encrypted and unencrypted certs need to be generated to support HTTP
  API clients and gRPC API clients, respectively.

  Only one instance of Config can be created for the program.
  c                    s@   t t| tj || _|| _|| _|| _|| _	t
| j d S r   )r-   r   r.   r   r   r;   client_cert_bytesclient_key_bytesencrypted_client_cert_pathencrypted_client_cert_passwordatexitregisterCleanUp)r/   r;   r   r   r   r   r0   r   r   r.     s   z_OnDiskCertConfigImpl.__init__c              
   C   sv   | j dur7tj| j r9zt| j  td| j  W dS  tjy6 } zt	d| W Y d}~dS d}~ww dS dS )z=Cleanup any files or resource provisioned during config init.Nzunprovisioned client cert - %sz(failed to remove client certificate - %s)
r   rC   rD   r   remover
   rK   r   rJ   error)r/   rO   r   r   r   r     s   
z_OnDiskCertConfigImpl.CleanUp)r'   r(   r)   r*   r.   r   r2   r   r   r0   r   r     s    r   c                   C   s   t st a t S )zCRepresents the configurations associated with context aware access.)singleton_configr   r   r   r   r   r   Config  s   r   )8r*   
__future__r   r   r   r   enumr   rC   google.authr   r8   google.auth.transportr   googlecloudsdk.command_lib.authr   googlecloudsdk.corer   r	   r
   r   googlecloudsdk.core.utilr   r   r   r   r   r&   r%   r$   r   rD   rE   
GetHomeDirr   r   r    rJ   r,   r3   rB   rP   rc   ro   r   strr   r   Enumr   objectr   r   r   r   r   r   r   r   r   <module>   s`   

		%!-V$'