h2o-secure-store 1.0.0__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.
Files changed (111) hide show
  1. h2o_secure_store-1.0.0/.gitignore +8 -0
  2. h2o_secure_store-1.0.0/Makefile +23 -0
  3. h2o_secure_store-1.0.0/PKG-INFO +34 -0
  4. h2o_secure_store-1.0.0/PUBLIC_README.md +15 -0
  5. h2o_secure_store-1.0.0/README.md +40 -0
  6. h2o_secure_store-1.0.0/pyproject.toml +91 -0
  7. h2o_secure_store-1.0.0/src/.openapi-generator-ignore +4 -0
  8. h2o_secure_store-1.0.0/src/h2o_secure_store/__init__.py +3 -0
  9. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/auth/token_api_client.py +25 -0
  10. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/base/workspace.py +5 -0
  11. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/connection_config.py +110 -0
  12. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/login.py +175 -0
  13. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/oauth_client/client.py +239 -0
  14. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/oauth_client/oauth_client.py +114 -0
  15. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/oauth_client/page.py +21 -0
  16. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/secret/client.py +195 -0
  17. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/secret/page.py +19 -0
  18. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/secret/secret.py +69 -0
  19. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/secret/state.py +16 -0
  20. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/secret_version/client.py +160 -0
  21. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/secret_version/page.py +21 -0
  22. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/secret_version/secret_version.py +54 -0
  23. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/token_source/client.py +172 -0
  24. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/token_source/page.py +21 -0
  25. h2o_secure_store-1.0.0/src/h2o_secure_store/clients/token_source/token_source.py +77 -0
  26. h2o_secure_store-1.0.0/src/h2o_secure_store/exception.py +36 -0
  27. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/__init__.py +27 -0
  28. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/oauth_client_pb2.py +64 -0
  29. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/oauth_client_pb2.pyi +45 -0
  30. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/oauth_client_pb2_grpc.py +4 -0
  31. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/oauth_client_service_pb2.py +79 -0
  32. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/oauth_client_service_pb2.pyi +78 -0
  33. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/oauth_client_service_pb2_grpc.py +262 -0
  34. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/secret_pb2.py +48 -0
  35. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/secret_pb2.pyi +35 -0
  36. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/secret_pb2_grpc.py +4 -0
  37. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/secret_service_pb2.py +82 -0
  38. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/secret_service_pb2.pyi +85 -0
  39. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/secret_service_pb2_grpc.py +257 -0
  40. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/secret_version_pb2.py +40 -0
  41. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/secret_version_pb2.pyi +20 -0
  42. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/secret_version_pb2_grpc.py +4 -0
  43. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/secret_version_service_pb2.py +70 -0
  44. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/secret_version_service_pb2.pyi +71 -0
  45. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/secret_version_service_pb2_grpc.py +214 -0
  46. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/token_source_pb2.py +56 -0
  47. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/token_source_pb2.pyi +36 -0
  48. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/token_source_pb2_grpc.py +4 -0
  49. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/token_source_service_pb2.py +72 -0
  50. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/token_source_service_pb2.pyi +67 -0
  51. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/ai/h2o/securestore/v1/token_source_service_pb2_grpc.py +212 -0
  52. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/api/__init__.py +3 -0
  53. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/api/o_auth_client_service_api.py +748 -0
  54. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/api/secret_service_api.py +780 -0
  55. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/api/secret_version_service_api.py +618 -0
  56. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/api/token_source_service_api.py +623 -0
  57. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/api_client.py +896 -0
  58. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/apis/__init__.py +20 -0
  59. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/configuration.py +446 -0
  60. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/exceptions.py +158 -0
  61. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/__init__.py +5 -0
  62. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/o_auth_client_resource.py +333 -0
  63. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/protobuf_any.py +263 -0
  64. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/rpc_status.py +277 -0
  65. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/secret_state.py +283 -0
  66. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_create_o_auth_client_response.py +269 -0
  67. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_create_secret_response.py +269 -0
  68. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_create_secret_version_response.py +269 -0
  69. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_create_token_source_response.py +269 -0
  70. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_delete_secret_response.py +269 -0
  71. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_get_o_auth_client_response.py +269 -0
  72. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_get_secret_response.py +269 -0
  73. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_get_secret_version_response.py +269 -0
  74. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_get_token_source_response.py +269 -0
  75. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_list_o_auth_clients_response.py +273 -0
  76. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_list_secret_versions_response.py +277 -0
  77. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_list_secrets_response.py +277 -0
  78. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_list_token_sources_response.py +273 -0
  79. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_o_auth_client.py +338 -0
  80. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_reveal_secret_version_value_response.py +272 -0
  81. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_secret.py +299 -0
  82. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_secret_version.py +289 -0
  83. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_token_source.py +318 -0
  84. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_undelete_secret_response.py +269 -0
  85. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model/v1_update_o_auth_client_response.py +269 -0
  86. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/model_utils.py +2056 -0
  87. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/models/__init__.py +35 -0
  88. h2o_secure_store-1.0.0/src/h2o_secure_store/gen/rest.py +352 -0
  89. h2o_secure_store-1.0.0/tests/integration/conftest.py +169 -0
  90. h2o_secure_store-1.0.0/tests/integration/e2e/oauth_client/test_create_oauth_client.py +114 -0
  91. h2o_secure_store-1.0.0/tests/integration/e2e/oauth_client/test_delete_oauth_client.py +39 -0
  92. h2o_secure_store-1.0.0/tests/integration/e2e/oauth_client/test_get_oauth_client.py +42 -0
  93. h2o_secure_store-1.0.0/tests/integration/e2e/oauth_client/test_list_oauth_client.py +70 -0
  94. h2o_secure_store-1.0.0/tests/integration/e2e/oauth_client/test_update_oauth_client.py +82 -0
  95. h2o_secure_store-1.0.0/tests/integration/e2e/secret/test_create_secret.py +93 -0
  96. h2o_secure_store-1.0.0/tests/integration/e2e/secret/test_delete_secret.py +55 -0
  97. h2o_secure_store-1.0.0/tests/integration/e2e/secret/test_get_secret.py +36 -0
  98. h2o_secure_store-1.0.0/tests/integration/e2e/secret/test_list_secret.py +149 -0
  99. h2o_secure_store-1.0.0/tests/integration/e2e/secret/test_prune_deleted.py +47 -0
  100. h2o_secure_store-1.0.0/tests/integration/e2e/secret/test_undelete_secret.py +52 -0
  101. h2o_secure_store-1.0.0/tests/integration/e2e/secret_version/test_create_secret_version.py +44 -0
  102. h2o_secure_store-1.0.0/tests/integration/e2e/secret_version/test_get_secret_version.py +113 -0
  103. h2o_secure_store-1.0.0/tests/integration/e2e/secret_version/test_key_rotation.py +28 -0
  104. h2o_secure_store-1.0.0/tests/integration/e2e/secret_version/test_list_secret_versions.py +136 -0
  105. h2o_secure_store-1.0.0/tests/integration/e2e/secret_version/test_reveal_secret_version.py +90 -0
  106. h2o_secure_store-1.0.0/tests/integration/e2e/test_login.py +17 -0
  107. h2o_secure_store-1.0.0/tests/integration/e2e/token_source/test_create_token_source.py +65 -0
  108. h2o_secure_store-1.0.0/tests/integration/e2e/token_source/test_delete_token_source.py +54 -0
  109. h2o_secure_store-1.0.0/tests/integration/e2e/token_source/test_get_token_source.py +64 -0
  110. h2o_secure_store-1.0.0/tests/integration/e2e/token_source/test_list_token_source.py +90 -0
  111. h2o_secure_store-1.0.0/usage.py +88 -0
@@ -0,0 +1,8 @@
1
+ src/.openapi-generator
2
+ .pytest_cache
3
+ dist
4
+ __pycache__
5
+
6
+ # Ignore custom scripts for local development & testing (except example.py and ambassador_host.yaml that we want to track).
7
+ local/*
8
+ !local/example.py
@@ -0,0 +1,23 @@
1
+ build:
2
+ hatch -v build
3
+
4
+ clean-build:
5
+ rm -rf dist
6
+
7
+ test-unit:
8
+ hatch run test:unit -v
9
+
10
+ test-api:
11
+ hatch run test:api -v
12
+
13
+ test-e2e:
14
+ hatch run test:e2e -v
15
+
16
+ lint-check:
17
+ hatch run lint:check -v
18
+
19
+ lint-fix:
20
+ hatch run lint:fix -v
21
+
22
+ generate-docs:
23
+ hatch run docs:generate -v
@@ -0,0 +1,34 @@
1
+ Metadata-Version: 2.3
2
+ Name: h2o-secure-store
3
+ Version: 1.0.0
4
+ Summary: Python client for H2O Secure Store
5
+ Project-URL: Documentation, https://docs.h2o.ai/secure-store/py/initialization
6
+ Author-email: "H2O.ai" <support@h2o.ai>
7
+ Requires-Python: >=3.8
8
+ Requires-Dist: certifi>=2022.12.7
9
+ Requires-Dist: gcloud>=0.18.3
10
+ Requires-Dist: google-api-python-client>=2.108.0
11
+ Requires-Dist: grpcio>=1.60.0
12
+ Requires-Dist: h2o-authn>=1.1.0
13
+ Requires-Dist: h2o-cloud-discovery>=2.1.0
14
+ Requires-Dist: protobuf>=4.25.1
15
+ Requires-Dist: python-dateutil>=2.8.2
16
+ Requires-Dist: requests>=2.26.0
17
+ Requires-Dist: urllib3>=1.26.15
18
+ Description-Content-Type: text/markdown
19
+
20
+ # `h2o-secure-store`
21
+
22
+ [![pypi](https://img.shields.io/pypi/v/h2o-secure-store?style=flat-square)](https://pypi.org/project/h2o-secure-store/)
23
+
24
+ Python client for [H2O Secure Store](https://docs.h2o.ai/secure-store/).
25
+
26
+ ## Installation
27
+
28
+ ```sh
29
+ pip install h2o-secure-store
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ Visit the [documentation](https://docs.h2o.ai/secure-store/py/initialization) for more information.
@@ -0,0 +1,15 @@
1
+ # `h2o-secure-store`
2
+
3
+ [![pypi](https://img.shields.io/pypi/v/h2o-secure-store?style=flat-square)](https://pypi.org/project/h2o-secure-store/)
4
+
5
+ Python client for [H2O Secure Store](https://docs.h2o.ai/secure-store/).
6
+
7
+ ## Installation
8
+
9
+ ```sh
10
+ pip install h2o-secure-store
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ Visit the [documentation](https://docs.h2o.ai/secure-store/py/initialization) for more information.
@@ -0,0 +1,40 @@
1
+ # H2O Secure Store
2
+
3
+ H2O Secure Store Python client.
4
+ This Python client implements interaction with the Secure Store REST API server.
5
+
6
+ ## Local development
7
+
8
+ This python project is managed by [hatch](https://github.com/pypa/hatch) (environment management, version management,
9
+ dependency management, building, publishing, etc.).
10
+
11
+ You're free to use any tools for local development for managing python environments that you're comfortable with.
12
+
13
+ ## Usage
14
+
15
+ ### Run using hatch
16
+
17
+ You can run H2O Secure Store Python client using Hatch.
18
+ Hatch will automatically create an environment and install all required dependencies:
19
+
20
+ ```shell
21
+ hatch run python local/example.py
22
+ ```
23
+
24
+ You can also switch to hatch's environment and run commands in it:
25
+
26
+ ```shell
27
+ hatch shell
28
+ python local/example.py
29
+ ```
30
+
31
+ ### Run in custom env
32
+
33
+ If you want to use your own environment for running the client (global, virtual env, etc.), you can do so.
34
+ For example to build, install and run H2O Secure Store Python client in the current python env:
35
+
36
+ ```shell
37
+ hatch build
38
+ pip install dist/h2o_secure_store-*.whl
39
+ python local/example.py
40
+ ```
@@ -0,0 +1,91 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "h2o-secure-store"
7
+ dynamic = ["version"]
8
+ description = 'Python client for H2O Secure Store'
9
+ readme = "PUBLIC_README.md"
10
+ requires-python = ">=3.8"
11
+ keywords = []
12
+ authors = [
13
+ { name = "H2O.ai", email = "support@h2o.ai" },
14
+ ]
15
+ dependencies = [
16
+ "urllib3>=1.26.15",
17
+ "python-dateutil>=2.8.2",
18
+ "h2o-authn>=1.1.0",
19
+ "h2o-cloud-discovery>=2.1.0",
20
+ "requests>=2.26.0",
21
+ "certifi>=2022.12.7",
22
+ # GRPC client dependencies
23
+ "grpcio>=1.60.0",
24
+ "protobuf>=4.25.1",
25
+ "gcloud>=0.18.3",
26
+ "google-api-python-client>=2.108.0",
27
+ ]
28
+
29
+ [project.urls]
30
+ Documentation = "https://docs.h2o.ai/secure-store/py/initialization"
31
+
32
+ [tool.hatch.build.targets.wheel]
33
+ packages = ["src/h2o_secure_store"]
34
+
35
+ [tool.hatch.version]
36
+ path = "../../VERSION"
37
+ pattern = "(?P<version>.*)"
38
+
39
+ [tool.hatch.envs.lint]
40
+ detached = true
41
+ dependencies = [
42
+ "black==23.1.0",
43
+ "isort==5.12.0",
44
+ "autoflake==2.3.0",
45
+ ]
46
+
47
+ [tool.hatch.envs.lint.scripts]
48
+ # TODO use flake8 and mypy
49
+ check = [
50
+ "black --check --diff .",
51
+ "isort --check --diff .",
52
+ "autoflake --check-diff ."
53
+ ]
54
+ fix = [
55
+ "black .",
56
+ "isort .",
57
+ "autoflake ."
58
+ ]
59
+
60
+ [tool.black]
61
+ exclude = [
62
+ "src/h2o_secure_store/gen",
63
+ "local",
64
+ ]
65
+ skip-magic-trailing-comma = true
66
+
67
+ [tool.isort]
68
+ skip = [
69
+ "src/h2o_secure_store/gen",
70
+ "local"
71
+ ]
72
+ force_single_line = true
73
+ known_application = ["h2o_secure_store"]
74
+ profile = "black"
75
+
76
+ [tool.autoflake]
77
+ exclude = [
78
+ "*/gen/*",
79
+ "local",
80
+ ]
81
+ remove_all_unused_imports = true
82
+ recursive = true
83
+
84
+ [tool.hatch.envs.test]
85
+ dependencies = [
86
+ "pytest==8.2.1",
87
+ "psycopg2-binary==2.9.9",
88
+ ]
89
+
90
+ [tool.hatch.envs.test.scripts]
91
+ e2e = "python -m pytest tests/integration/e2e"
@@ -0,0 +1,4 @@
1
+ h2o_secure_store/__init__.py
2
+ h2o_secure_store/gen_README.md
3
+ h2o_secure_store/gen/test/*
4
+ h2o_secure_store/gen/docs/*
@@ -0,0 +1,3 @@
1
+ from h2o_secure_store.clients.login import login # noqa
2
+ from h2o_secure_store.clients.login import login_custom # noqa
3
+ from h2o_secure_store.clients.login import login_custom_with_token_provider # noqa
@@ -0,0 +1,25 @@
1
+ from typing import Callable
2
+
3
+ from h2o_secure_store.gen.api_client import ApiClient
4
+ from h2o_secure_store.gen.api_client import Configuration
5
+
6
+
7
+ class TokenApiClient(ApiClient):
8
+ """Overrides update_params_for_auth method of the generated ApiClient classes"""
9
+
10
+ def __init__(self, configuration: Configuration, token_provider: Callable[[], str]):
11
+ self._token_provider = token_provider
12
+ super().__init__(configuration=configuration)
13
+
14
+ def update_params_for_auth(
15
+ self,
16
+ headers,
17
+ queries,
18
+ auth_settings,
19
+ resource_path,
20
+ method,
21
+ body,
22
+ request_auths=None,
23
+ ):
24
+ token = self._token_provider()
25
+ headers["Authorization"] = f"Bearer {token}"
@@ -0,0 +1,5 @@
1
+ # Reserved name of the global workspace.
2
+ GLOBAL_WORKSPACE = "workspaces/global"
3
+
4
+ # Reserved name of the default (personal) workspace.
5
+ DEFAULT_WORKSPACE = "workspaces/default"
@@ -0,0 +1,110 @@
1
+ import ssl
2
+ from typing import Callable
3
+ from typing import NamedTuple
4
+ from typing import Optional
5
+ from typing import Union
6
+
7
+ import h2o_authn
8
+ import h2o_discovery
9
+ from h2o_authn import TokenProvider
10
+
11
+ # Name of the platform client in the discovery response.
12
+ PLATFORM_CLIENT_NAME = "platform"
13
+ # Name of the Secure Store API service in the discovery response.
14
+ SECURE_STORE_SERVICE_NAME = "secure-store"
15
+
16
+
17
+ class ConnectionConfig(NamedTuple):
18
+ """Object holding connection configuration for the Secure Store API server."""
19
+
20
+ server_url: str
21
+ token_provider: Union[TokenProvider, Callable[[], str]]
22
+
23
+
24
+ def get_connection(
25
+ server_url: str,
26
+ refresh_token: str,
27
+ issuer_url: str,
28
+ client_id: str,
29
+ client_secret: Optional[str] = None,
30
+ ) -> ConnectionConfig:
31
+ """Creates ConnectionConfig object. Initializes and tests token provider."""
32
+
33
+ # init token provider
34
+ tp = h2o_authn.TokenProvider(
35
+ issuer_url=issuer_url,
36
+ refresh_token=refresh_token,
37
+ client_id=client_id,
38
+ client_secret=client_secret,
39
+ )
40
+ # test token refresh
41
+ tp()
42
+
43
+ return ConnectionConfig(server_url=server_url, token_provider=tp)
44
+
45
+
46
+ def discover_platform_connection(
47
+ environment_url: Optional[str] = None,
48
+ config_path: Optional[str] = None,
49
+ platform_token: Optional[str] = None,
50
+ token_provider: Optional[TokenProvider] = None,
51
+ ssl_context: Optional[ssl.SSLContext] = None,
52
+ ) -> ConnectionConfig:
53
+ """Creates ConnectionConfig object by discovering platform connection configuration using h2o_discovery.
54
+
55
+ :param environment_url: Override for the URL of the environment passed to the discovery service.
56
+ :param config_path: Override path to the h2o cli config file passed to the discovery service.
57
+ :param platform_token: Platform token. If not provided, the token will be discovered.
58
+ :param token_provider: Token provider. If not provided, the provider will be constructed from the discovered config.
59
+ :param ssl_context: SSL context to use for the discovery client.
60
+ """
61
+ # Discover the Secure Store server URL
62
+ d = h2o_discovery.discover(environment=environment_url, config_path=config_path, ssl_context=ssl_context)
63
+
64
+ secure_store_service = d.services.get(SECURE_STORE_SERVICE_NAME)
65
+ if secure_store_service is None:
66
+ raise Exception("Secure Store API service is not registered in discovery service")
67
+
68
+ secure_store_url = secure_store_service.uri
69
+ if not secure_store_url:
70
+ raise ConnectionError("Unable to discover Secure Store server URL connection value.")
71
+
72
+ # If the token provider is provided, use it to construct the connection config.
73
+ if token_provider is not None:
74
+ # Test token refresh
75
+ token_provider()
76
+ return ConnectionConfig(server_url=secure_store_url, token_provider=token_provider)
77
+
78
+ # If the token provider is not provided, construct it from the discovered config.
79
+ if not platform_token:
80
+ platform_client_credentials = d.credentials[PLATFORM_CLIENT_NAME]
81
+ if platform_client_credentials is None:
82
+ raise Exception("Platform client credentials are not available in discovery service")
83
+
84
+ platform_token = platform_client_credentials.refresh_token
85
+
86
+ if not platform_token:
87
+ raise ValueError(
88
+ "Please set the 'platform_token' argument or configure the H2O CLI."
89
+ )
90
+
91
+ # Discover client id
92
+ platform_client = d.clients.get(PLATFORM_CLIENT_NAME)
93
+ if platform_client is None:
94
+ raise Exception("platform client is not registered in discovery service")
95
+
96
+ client_id = platform_client.oauth2_client_id
97
+ if not client_id:
98
+ raise ConnectionError(
99
+ "Unable to discover platform oauth2_client_id connection value."
100
+ )
101
+
102
+ tp = h2o_authn.TokenProvider(
103
+ issuer_url=d.environment.issuer_url,
104
+ client_id=client_id,
105
+ refresh_token=platform_token,
106
+ )
107
+ # Test token refresh
108
+ tp()
109
+
110
+ return ConnectionConfig(server_url=secure_store_url, token_provider=tp)
@@ -0,0 +1,175 @@
1
+ import ssl
2
+ from typing import Callable
3
+ from typing import Optional
4
+ from urllib.parse import urljoin
5
+
6
+ import requests
7
+ from h2o_authn import TokenProvider
8
+
9
+ from h2o_secure_store.clients.connection_config import ConnectionConfig
10
+ from h2o_secure_store.clients.connection_config import discover_platform_connection
11
+ from h2o_secure_store.clients.connection_config import get_connection
12
+ from h2o_secure_store.clients.oauth_client.client import OAuthClientClient
13
+ from h2o_secure_store.clients.secret.client import SecretClient
14
+ from h2o_secure_store.clients.secret_version.client import SecretVersionClient
15
+ from h2o_secure_store.clients.token_source.client import TokenSourceClient
16
+
17
+
18
+ class Clients:
19
+ def __init__(
20
+ self,
21
+ oauth_client_client: OAuthClientClient,
22
+ token_source_client: TokenSourceClient,
23
+ secret_client: SecretClient,
24
+ secret_version_client: SecretVersionClient,
25
+ ) -> None:
26
+ self.oauth_client_client = oauth_client_client
27
+ self.token_source_client = token_source_client
28
+ self.secret_client = secret_client
29
+ self.secret_version_client = secret_version_client
30
+
31
+
32
+ def login(
33
+ environment: Optional[str] = None,
34
+ token_provider: Optional[TokenProvider] = None,
35
+ platform_token: Optional[str] = None,
36
+ config_path: Optional[str] = None,
37
+ verify_ssl: bool = True,
38
+ ssl_ca_cert: Optional[str] = None,
39
+ ) -> Clients:
40
+ """Initializes Secure Store clients for H2O AI Cloud.
41
+
42
+ All arguments are optional. Configuration-less login is dependent on having the H2O CLI configured.
43
+ See: https://docs.h2o.ai/h2o-ai-cloud/developerguide/cli#platform-token
44
+ The Discovery Service is used to discover the Secure Store server endpoint.
45
+ See: https://pypi.org/project/h2o-cloud-discovery/
46
+
47
+ Args:
48
+ environment (str, optional): The H2O Cloud environment URL to use (e.g. https://cloud.h2o.ai).
49
+ If left empty, the environment will be read from the H2O CLI configuration or environmental variables.
50
+ Then, h2o-cloud-discovery will be used to discover the Secure Store API server endpoint.
51
+ token_provider (TokenProvider, optional) = Token provider. Takes priority over platform_token argument.
52
+ platform_token (str, optional): H2O Platform Token.
53
+ If neither 'token_provider' nor 'platform_token' is provided the platform token will be read
54
+ from the H2O CLI configuration.
55
+ config_path: (str, optional): Path to the H2O AI Cloud configuration file.
56
+ Defaults to '~/.h2oai/h2o-cli-config.toml'.
57
+ verify_ssl: Set to False to disable SSL certificate verification.
58
+ ssl_ca_cert: Path to a CA cert bundle with certificates of trusted CAs.
59
+
60
+ Raises:
61
+ FileNotFoundError: When the H2O CLI configuration file is needed but cannot be found.
62
+ TomlDecodeError: When the H2O CLI configuration file is needed but cannot be processed.
63
+ LookupError: When the service endpoint cannot be discovered.
64
+ ConnectionError: When a communication with server failed.
65
+ """
66
+ ssl_context = ssl.create_default_context(cafile=ssl_ca_cert) # Will use system store if None
67
+ if not verify_ssl:
68
+ ssl_context.check_hostname = False
69
+ ssl_context.verify_mode = ssl.CERT_NONE
70
+
71
+ cfg = discover_platform_connection(
72
+ environment_url=environment,
73
+ platform_token=platform_token,
74
+ token_provider=token_provider,
75
+ config_path=config_path,
76
+ ssl_context=ssl_context,
77
+ )
78
+
79
+ return __init_clients(
80
+ cfg=cfg, verify_ssl=verify_ssl, ssl_ca_cert=ssl_ca_cert,
81
+ )
82
+
83
+
84
+ def login_custom(
85
+ endpoint: str,
86
+ refresh_token: str,
87
+ issuer_url: str,
88
+ client_id: str,
89
+ client_secret: Optional[str] = None,
90
+ verify_ssl: bool = True,
91
+ ssl_ca_cert: Optional[str] = None,
92
+ ) -> Clients:
93
+ """Initializes Secure store clients using h2o_authn to construct a token provider.
94
+
95
+ Args:
96
+ endpoint (str): The Secure Store API server endpoint URL (e.g. https://secure-store.cloud.h2o.ai).
97
+ refresh_token (str): The OIDC refresh token.
98
+ issuer_url (str): The OIDC issuer URL.
99
+ client_id (str): The OIDC Client ID that issued the 'refresh_token'.
100
+ client_secret (str, optional): Optional OIDC Client Secret that issued the 'refresh_token'. Defaults to None.
101
+ verify_ssl: Set to False to disable SSL certificate verification.
102
+ ssl_ca_cert: Path to a CA cert bundle with certificates of trusted CAs.
103
+ """
104
+ # Remove trailing slash from the URL for the generated clients
105
+ endpoint = endpoint.rstrip("/")
106
+ cfg = get_connection(
107
+ server_url=endpoint,
108
+ refresh_token=refresh_token,
109
+ issuer_url=issuer_url,
110
+ client_id=client_id,
111
+ client_secret=client_secret,
112
+ )
113
+
114
+ return __init_clients(
115
+ cfg=cfg, verify_ssl=verify_ssl, ssl_ca_cert=ssl_ca_cert,
116
+ )
117
+
118
+
119
+ def login_custom_with_token_provider(
120
+ endpoint: str,
121
+ token_provider: Callable[[], str],
122
+ verify_ssl: bool = True,
123
+ ssl_ca_cert: Optional[str] = None,
124
+ ) -> Clients:
125
+ """Initializes Secure store clients using a custom token provider.
126
+
127
+ A token provider can be constructed using h2o_authn:
128
+ token_provider = h2o_authn.TokenProvider(
129
+ issuer_url=issuer_url,
130
+ refresh_token=refresh_token,
131
+ client_id=client_id,
132
+ client_secret=client_secret,
133
+ )
134
+
135
+ Args:
136
+ endpoint (str): The Secure Store API server endpoint URL (e.g. https://secure-store.cloud.h2o.ai).
137
+ token_provider (Callable[[], str]): A callable that returns an OIDC access token.
138
+ verify_ssl: Set to False to disable SSL certificate verification.
139
+ ssl_ca_cert: Path to a CA cert bundle with certificates of trusted CAs.
140
+ """
141
+ # Remove trailing slash from the URL for the generated clients
142
+ endpoint = endpoint.rstrip("/")
143
+ # Test token refresh
144
+ token_provider()
145
+ cfg = ConnectionConfig(server_url=endpoint, token_provider=token_provider)
146
+
147
+ return __init_clients(
148
+ cfg=cfg, verify_ssl=verify_ssl, ssl_ca_cert=ssl_ca_cert,
149
+ )
150
+
151
+
152
+ def __init_clients(
153
+ cfg: ConnectionConfig,
154
+ verify_ssl: bool,
155
+ ssl_ca_cert: Optional[str],
156
+ ):
157
+ # Verify that the server is reachable
158
+ version_url = urljoin(cfg.server_url, "version")
159
+ resp = requests.get(version_url)
160
+ if not (200 <= resp.status_code <= 299):
161
+ raise ConnectionError(
162
+ f"Server is not reachable. Status code: {resp.status_code}, Response body: {resp.text}"
163
+ )
164
+
165
+ oauth_client_client = OAuthClientClient(connection_config=cfg, verify_ssl=verify_ssl, ssl_ca_cert=ssl_ca_cert)
166
+ token_source_client = TokenSourceClient(connection_config=cfg, verify_ssl=verify_ssl, ssl_ca_cert=ssl_ca_cert)
167
+ secret_client = SecretClient(connection_config=cfg, verify_ssl=verify_ssl, ssl_ca_cert=ssl_ca_cert)
168
+ secret_version_client = SecretVersionClient(connection_config=cfg, verify_ssl=verify_ssl, ssl_ca_cert=ssl_ca_cert)
169
+
170
+ return Clients(
171
+ oauth_client_client=oauth_client_client,
172
+ token_source_client=token_source_client,
173
+ secret_client=secret_client,
174
+ secret_version_client=secret_version_client,
175
+ )