|
16 | 16 |
|
17 | 17 | """Helpers for client setup and configuration.""" |
18 | 18 |
|
19 | | -from typing import Any, Optional |
| 19 | +import os |
| 20 | +from typing import Any, Callable, Optional, Tuple |
20 | 21 |
|
21 | 22 | from google.auth.exceptions import MutualTLSChannelError # type: ignore |
| 23 | +from google.auth.transport import mtls # type: ignore |
22 | 24 |
|
23 | 25 |
|
24 | 26 | def get_default_mtls_endpoint(api_endpoint: Optional[str]) -> Optional[str]: |
@@ -124,3 +126,89 @@ def get_universe_domain( |
124 | 126 | if not universe_domain: |
125 | 127 | raise ValueError("Universe Domain cannot be an empty string.") |
126 | 128 | return universe_domain |
| 129 | + |
| 130 | + |
| 131 | +def use_client_cert_effective() -> bool: |
| 132 | + """Returns whether client certificate should be used for mTLS if the |
| 133 | + google-auth version supports should_use_client_cert automatic mTLS |
| 134 | + enablement. |
| 135 | +
|
| 136 | + Alternatively, read from the GOOGLE_API_USE_CLIENT_CERTIFICATE env var. |
| 137 | +
|
| 138 | + Returns: |
| 139 | + bool: whether client certificate should be used for mTLS |
| 140 | + Raises: |
| 141 | + ValueError: (If using a version of google-auth without |
| 142 | + should_use_client_cert and GOOGLE_API_USE_CLIENT_CERTIFICATE is |
| 143 | + set to an unexpected value.) |
| 144 | + """ |
| 145 | + # check if google-auth version supports should_use_client_cert for |
| 146 | + # automatic mTLS enablement |
| 147 | + if hasattr(mtls, "should_use_client_cert"): # pragma: NO COVER |
| 148 | + return mtls.should_use_client_cert() |
| 149 | + else: # pragma: NO COVER |
| 150 | + # if unsupported, fallback to reading from env var |
| 151 | + use_client_cert_str = os.getenv( |
| 152 | + "GOOGLE_API_USE_CLIENT_CERTIFICATE", "false" |
| 153 | + ).lower() |
| 154 | + if use_client_cert_str not in ("true", "false"): |
| 155 | + raise ValueError( |
| 156 | + "Environment variable `GOOGLE_API_USE_CLIENT_CERTIFICATE` " |
| 157 | + "must be either `true` or `false`" |
| 158 | + ) |
| 159 | + return use_client_cert_str == "true" |
| 160 | + |
| 161 | + |
| 162 | +def get_client_cert_source( |
| 163 | + provided_cert_source: Optional[Callable[[], Tuple[bytes, bytes]]], |
| 164 | + use_cert_flag: bool, |
| 165 | +) -> Optional[Callable[[], Tuple[bytes, bytes]]]: |
| 166 | + """Return the client cert source to be used by the client. |
| 167 | +
|
| 168 | + Args: |
| 169 | + provided_cert_source (Callable[[], Tuple[bytes, bytes]]): The client certificate source provided. |
| 170 | + use_cert_flag (bool): A flag indicating whether to use the |
| 171 | + client certificate. |
| 172 | +
|
| 173 | + Returns: |
| 174 | + Callable[[], Tuple[bytes, bytes]] or None: The client cert source to be used by the client. |
| 175 | + """ |
| 176 | + if use_cert_flag: |
| 177 | + if provided_cert_source: |
| 178 | + return provided_cert_source |
| 179 | + elif ( |
| 180 | + hasattr(mtls, "has_default_client_cert_source") |
| 181 | + and mtls.has_default_client_cert_source() |
| 182 | + ): |
| 183 | + return mtls.default_client_cert_source() |
| 184 | + else: |
| 185 | + raise ValueError( |
| 186 | + "Client certificate is required for mTLS, but no client certificate source was provided or found." |
| 187 | + ) |
| 188 | + return None |
| 189 | + |
| 190 | + |
| 191 | +def read_environment_variables() -> Tuple[bool, str, Optional[str]]: |
| 192 | + """Returns the environment variables used by the client. |
| 193 | +
|
| 194 | + Returns: |
| 195 | + Tuple[bool, str, Optional[str]]: returns the |
| 196 | + GOOGLE_API_USE_CLIENT_CERTIFICATE, GOOGLE_API_USE_MTLS_ENDPOINT, |
| 197 | + and GOOGLE_CLOUD_UNIVERSE_DOMAIN environment variables. |
| 198 | +
|
| 199 | + Raises: |
| 200 | + ValueError: If GOOGLE_API_USE_CLIENT_CERTIFICATE is not |
| 201 | + any of ["true", "false"]. |
| 202 | + google.auth.exceptions.MutualTLSChannelError: If |
| 203 | + GOOGLE_API_USE_MTLS_ENDPOINT is not any of |
| 204 | + ["auto", "never", "always"]. |
| 205 | + """ |
| 206 | + use_client_cert = use_client_cert_effective() |
| 207 | + use_mtls_endpoint = os.getenv("GOOGLE_API_USE_MTLS_ENDPOINT", "auto").lower() |
| 208 | + universe_domain_env = os.getenv("GOOGLE_CLOUD_UNIVERSE_DOMAIN") |
| 209 | + if use_mtls_endpoint not in ("auto", "never", "always"): |
| 210 | + raise MutualTLSChannelError( |
| 211 | + "Environment variable `GOOGLE_API_USE_MTLS_ENDPOINT` " |
| 212 | + "must be `never`, `auto` or `always`" |
| 213 | + ) |
| 214 | + return use_client_cert, use_mtls_endpoint, universe_domain_env |
0 commit comments