iaptoolkit 0.0.2__tar.gz → 0.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: iaptoolkit
3
- Version: 0.0.2
3
+ Version: 0.0.4
4
4
  Summary: Library of common utils for interacting with Identity-Aware Proxies
5
5
  Author: Rob Voigt
6
6
  Author-email: code@ravoigt.com
@@ -9,7 +9,7 @@ Classifier: Programming Language :: Python :: 3
9
9
  Classifier: Programming Language :: Python :: 3.11
10
10
  Classifier: Programming Language :: Python :: 3.12
11
11
  Requires-Dist: google-auth (>=2.26.2,<3.0.0)
12
- Requires-Dist: kvcommon (>=0.0.6,<0.0.7)
12
+ Requires-Dist: kvcommon (>=0.0.7.1,<0.0.8.0)
13
13
  Requires-Dist: pytest (>=7.4.4,<8.0.0)
14
14
  Requires-Dist: requests (>=2.31.0,<3.0.0)
15
15
  Requires-Dist: toml (>=0.10.2,<0.11.0)
@@ -1,18 +1,34 @@
1
1
  [tool.poetry]
2
2
  name = "iaptoolkit"
3
- version = "0.0.2"
3
+ version = "0.0.4"
4
4
  description = "Library of common utils for interacting with Identity-Aware Proxies"
5
5
  authors = ["Rob Voigt <code@ravoigt.com>"]
6
6
  readme = "README.md"
7
7
 
8
+ [build-system]
9
+ requires = ["poetry-core>=1.0.0"]
10
+ build-backend = "poetry.core.masonry.api"
11
+
12
+ [project.urls]
13
+ Homepage = "https://github.com/RAVoigt/iaptoolkit"
14
+ Repository = "https://github.com/RAVoigt/iaptoolkit"
15
+
16
+ # ================================
17
+ # Tools etc.
18
+ [tool.black]
19
+ line-length = 100
20
+ target-version = ['py311']
21
+ include = '\.pyi?$'
22
+
23
+ # ================================
24
+ # Dependencies
8
25
  [tool.poetry.dependencies]
9
26
  python = "^3.11"
10
27
  google-auth = "^2.26.2"
11
28
  requests = "^2.31.0"
12
29
  pytest = "^7.4.4"
13
30
  toml = "^0.10.2"
14
- kvcommon = "^0.0.6"
15
-
31
+ kvcommon = "^0.0.7.1"
16
32
 
17
33
  [tool.poetry.dev-dependencies]
18
34
  black = "*"
@@ -25,12 +41,6 @@ pytest-cov = "*"
25
41
  pytest-socket = "*"
26
42
  pyfakefs = "^5.3.2"
27
43
 
28
-
29
- [tool.black]
30
- line-length = 100
31
- target-version = ['py311']
32
- include = '\.pyi?$'
33
-
34
- [build-system]
35
- requires = ["poetry-core>=1.0.0"]
36
- build-backend = "poetry.core.masonry.api"
44
+ # [tool.poetry.extras]
45
+ # flask = ["flask"]
46
+ # k8s = ["kubernetes"]
@@ -24,7 +24,7 @@ class TokenStorageException(TokenException):
24
24
 
25
25
  class ServiceAccountTokenException(TokenException):
26
26
  def __init__(
27
- self, message: str, google_exception: t.Union[DefaultCredentialsError, RefreshError]
27
+ self, message: str, google_exception: t.Union[DefaultCredentialsError, RefreshError] | None
28
28
  ):
29
29
  self.google_exception = google_exception
30
30
  credentials_env_var_value = os.environ.get(GOOGLE_CREDENTIALS_FILE_PATH)
@@ -40,7 +40,7 @@ class ServiceAccountTokenException(TokenException):
40
40
 
41
41
  @property
42
42
  def retryable(self):
43
- return self.google_exception._retryable
43
+ return self.google_exception and self.google_exception._retryable
44
44
 
45
45
 
46
46
  class ServiceAccountNoDefaultCredentials(ServiceAccountTokenException):
@@ -49,3 +49,7 @@ class ServiceAccountNoDefaultCredentials(ServiceAccountTokenException):
49
49
 
50
50
  class ServiceAccountTokenFailedRefresh(ServiceAccountTokenException):
51
51
  pass
52
+
53
+
54
+ class InvalidDomain(IAPToolkitBaseException):
55
+ pass
@@ -4,13 +4,13 @@ from kvcommon import logger
4
4
 
5
5
  from iaptoolkit.constants import GOOGLE_IAP_AUTH_HEADER
6
6
  from iaptoolkit.constants import GOOGLE_IAP_AUTH_HEADER_PROXY
7
- from iaptoolkit.tokens import get_token_for_google_service_account as get_token
7
+ from iaptoolkit.tokens import get_token_for_google_service_account
8
8
  from iaptoolkit.tokens.structs import ResultAddTokenHeader
9
9
  from iaptoolkit.utils.urls import is_url_safe_for_token
10
10
  from iaptoolkit.vars import IAPTOOLKIT_USE_AUTH_HEADER
11
+ from iaptoolkit.vars import GOOGLE_IAP_CLIENT_ID
11
12
 
12
-
13
- LOG = logger.get_logger("iaptoolkit")
13
+ LOG = logger.get_logger("iaptk")
14
14
 
15
15
 
16
16
  def _sanitize_request_header(headers_dict: dict, header_key: str):
@@ -39,7 +39,7 @@ def sanitize_request_headers(headers: dict) -> dict:
39
39
  return log_safe_headers
40
40
 
41
41
 
42
- def add_token_to_request_headers(request_headers: dict, use_oauth2: bool) -> bool:
42
+ def add_token_to_request_headers(request_headers: dict, use_oauth2: bool, iap_client_id: str) -> bool:
43
43
  """
44
44
  Adds Bearer token to headers dict. Modifies dict in-place.
45
45
  Returns True if added token is a fresh one, or False if token is from cache
@@ -47,7 +47,7 @@ def add_token_to_request_headers(request_headers: dict, use_oauth2: bool) -> boo
47
47
  # TODO: Make this less google-specific, or move it to a google-specific implementation
48
48
  # TODO: oauth2
49
49
 
50
- token_refresh_struct = get_token()
50
+ token_refresh_struct = get_token_for_google_service_account(iap_client_id=iap_client_id)
51
51
  id_token: str = token_refresh_struct.id_token
52
52
  auth_header_str = "Bearer {}".format(id_token)
53
53
 
@@ -73,7 +73,8 @@ def check_url_and_add_token_header(
73
73
  url: str,
74
74
  request_headers: dict,
75
75
  use_oauth2: bool = False,
76
- valid_domains: t.Optional[t.List[str]] = None,
76
+ valid_domains: t.List[str] | None = None,
77
+ iap_client_id: str = GOOGLE_IAP_CLIENT_ID
77
78
  ) -> ResultAddTokenHeader:
78
79
  """Prevent inadvertently sending private tokens to arbitrary locations.
79
80
  Returns:
@@ -85,7 +86,7 @@ def check_url_and_add_token_header(
85
86
 
86
87
  # Verify that the url's domain is one we allow before adding a token
87
88
  if is_url_safe_for_token(url_parts, valid_domains):
88
- token_is_fresh = add_token_to_request_headers(request_headers, use_oauth2)
89
+ token_is_fresh = add_token_to_request_headers(request_headers, use_oauth2, iap_client_id=iap_client_id)
89
90
  return ResultAddTokenHeader(token_added=True, token_is_fresh=token_is_fresh)
90
91
  else:
91
92
  LOG.warn(
@@ -3,7 +3,6 @@ from kvcommon import logger
3
3
  from iaptoolkit.exceptions import ServiceAccountTokenException
4
4
  from iaptoolkit.exceptions import TokenStorageException
5
5
  from iaptoolkit.exceptions import TokenException
6
- from iaptoolkit.vars import GOOGLE_IAP_CLIENT_ID
7
6
 
8
7
  from .structs import TokenStruct
9
8
  from .structs import TokenRefreshStruct
@@ -13,14 +12,12 @@ from .structs import TokenRefreshStruct
13
12
  # from .service_account import ServiceAccount
14
13
  from .service_account import GoogleServiceAccount
15
14
 
16
- LOG = logger.get_logger("iaptoolkit")
15
+ LOG = logger.get_logger("iaptk")
17
16
 
18
- google_sa_token_client = GoogleServiceAccount(GOOGLE_IAP_CLIENT_ID)
19
17
 
20
-
21
- def get_token_for_google_service_account(iap_client_id: str = GOOGLE_IAP_CLIENT_ID):
18
+ def get_token_for_google_service_account(iap_client_id):
22
19
  try:
23
- return GoogleServiceAccount(GOOGLE_IAP_CLIENT_ID).get_token()
20
+ return GoogleServiceAccount(iap_client_id).get_token()
24
21
  except ServiceAccountTokenException as ex:
25
22
  LOG.debug(ex)
26
23
  raise
@@ -16,7 +16,6 @@ from iaptoolkit.exceptions import ServiceAccountTokenFailedRefresh
16
16
  from iaptoolkit.exceptions import ServiceAccountNoDefaultCredentials
17
17
  from iaptoolkit.exceptions import TokenStorageException
18
18
 
19
- from iaptoolkit.vars import GOOGLE_IAP_CLIENT_ID
20
19
  # from iaptoolkit.vars import GOOGLE_CLIENT_ID
21
20
  # from iaptoolkit.vars import GOOGLE_CLIENT_SECRET
22
21
 
@@ -24,13 +23,13 @@ from .structs import TokenStruct
24
23
  from .structs import TokenRefreshStruct
25
24
 
26
25
 
27
- LOG = logger.get_logger("iaptoolkit")
26
+ LOG = logger.get_logger("iaptk")
28
27
  MAX_RECURSE = 3
29
28
 
30
29
 
31
30
  class ServiceAccount(object):
32
- """Base class for interacting with service accounts and OIDC tokens for IAP
33
- """
31
+ """Base class for interacting with service accounts and OIDC tokens for IAP"""
32
+
34
33
  # TODO: This is a static namespace for SA functions. Turn it into a per-iap-client-id client
35
34
  # TODO: Move Google-specific logic to GoogleServiceAccount
36
35
 
@@ -166,9 +165,13 @@ class ServiceAccount(object):
166
165
 
167
166
 
168
167
  class GoogleServiceAccount(ServiceAccount):
169
- """For interacting with Google service accounts and OIDC tokens for Google IAP
170
- """
171
- def __init__(self, iap_client_id: str = GOOGLE_IAP_CLIENT_ID) -> None:
168
+ """For interacting with Google service accounts and OIDC tokens for Google IAP"""
169
+
170
+ def __init__(self, iap_client_id: str) -> None:
171
+ if not iap_client_id or not isinstance(iap_client_id, str):
172
+ raise ServiceAccountTokenException(
173
+ "Invalid iap_client_id for GoogleServiceAccount", google_exception=None
174
+ )
172
175
  self._iap_client_id = iap_client_id
173
176
  super().__init__()
174
177
 
@@ -5,7 +5,7 @@ import typing as t
5
5
  from kvcommon import logger
6
6
 
7
7
 
8
- LOG = logger.get_logger("iaptoolkit")
8
+ LOG = logger.get_logger("iaptk")
9
9
 
10
10
 
11
11
  @dataclass(kw_only=True)
@@ -13,7 +13,7 @@ from iaptoolkit.vars import PERSISTENT_DATASTORE_PATH
13
13
  from iaptoolkit.vars import PERSISTENT_DATASTORE_USERNAME
14
14
 
15
15
 
16
- LOG = logger.get_logger("iaptoolkit-datastore")
16
+ LOG = logger.get_logger("iaptk-ds")
17
17
 
18
18
 
19
19
  class TokenDatastore(VersionedDatastore):
@@ -4,13 +4,9 @@ from urllib.parse import ParseResult
4
4
  from kvcommon import logger
5
5
  from kvcommon.urls import get_netloc_without_port_from_url_parts
6
6
 
7
- from iaptoolkit.exceptions import IAPToolkitBaseException
7
+ from iaptoolkit.exceptions import InvalidDomain
8
8
 
9
- LOG = logger.get_logger("iaptoolkit")
10
-
11
-
12
- class InvalidDomain(IAPToolkitBaseException):
13
- pass
9
+ LOG = logger.get_logger("iaptk")
14
10
 
15
11
 
16
12
  def is_url_safe_for_token(
File without changes
File without changes