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