legate 0.1.0
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.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +345 -0
- data/bin/legate +13 -0
- data/examples/00_quickstart.rb +51 -0
- data/examples/01_simple_agent.rb +105 -0
- data/examples/02_multi_tool_agent.rb +140 -0
- data/examples/03_custom_tool.rb +93 -0
- data/examples/04_agent_instructions.rb +84 -0
- data/examples/05_state_and_sessions.rb +91 -0
- data/examples/06_callbacks.rb +186 -0
- data/examples/07_async_jobs.rb +112 -0
- data/examples/08_loop_agent.rb +197 -0
- data/examples/09_sequential_workflow.rb +40 -0
- data/examples/10_parallel_workflow.rb +34 -0
- data/examples/11_agent_delegation.rb +24 -0
- data/examples/12_http_client_tool.rb +156 -0
- data/examples/13_authentication.rb +220 -0
- data/examples/14_mcp_client.rb +154 -0
- data/examples/15_mcp_server.rb +79 -0
- data/examples/16_webhooks.rb +91 -0
- data/examples/README_sequential_agents.md +164 -0
- data/examples/advanced/auth/cookie_auth_tool.rb +146 -0
- data/examples/advanced/auth/custom_auth_flows_example.rb +626 -0
- data/examples/advanced/auth/excon_middleware.rb +317 -0
- data/examples/advanced/auth/excon_middleware_auth.rb +399 -0
- data/examples/advanced/auth/fiber_auth_example.rb +281 -0
- data/examples/advanced/auth/fiber_oidc_example.rb +403 -0
- data/examples/advanced/auth/httpbin_bearer_tool.rb +159 -0
- data/examples/advanced/auth/oauth2_auth.rb +419 -0
- data/examples/advanced/auth/oidc_auth.rb +514 -0
- data/examples/advanced/auth/openweather_api.rb +251 -0
- data/examples/advanced/auth/openweather_tool.rb +153 -0
- data/examples/advanced/auth/query_param_middleware_test.rb +138 -0
- data/examples/advanced/auth/service_account.rb +135 -0
- data/examples/advanced/auth/test_with_httpbin.rb +202 -0
- data/examples/advanced/auth/token_lifecycle_example.rb +428 -0
- data/examples/advanced/callback_monitoring.rb +679 -0
- data/examples/advanced/mas/fixed_delegation_example.rb +191 -0
- data/examples/advanced/mas/loop_workflow.rb +28 -0
- data/examples/advanced/mas/mock_planner.rb +77 -0
- data/examples/advanced/mas/proper_delegation_example.rb +276 -0
- data/examples/advanced/mcp/legate_mcp_server_resource_example.rb +182 -0
- data/examples/advanced/mcp/mcp_resource_server_example.rb +309 -0
- data/examples/advanced/mcp/mcp_server_async.rb +76 -0
- data/examples/advanced/mcp/mcp_server_async_tools.rb +122 -0
- data/examples/advanced/mcp/mcp_server_legate_agent.rb +95 -0
- data/examples/advanced/mcp/mcp_server_rack.rb +89 -0
- data/examples/advanced/random_calculator.rb +104 -0
- data/examples/advanced/sleep_agent.rb +153 -0
- data/examples/advanced/webhooks/webhook_e2e_runner.rb +110 -0
- data/examples/advanced/webhooks/webhook_receiver_agent.rb +58 -0
- data/examples/advanced/workflows/task_refinement_loop_agent.rb +278 -0
- data/examples/advanced/workflows/travel_planner_auto_sequential.rb +444 -0
- data/examples/advanced/workflows/travel_planner_parallel.rb +656 -0
- data/examples/advanced/workflows/travel_planner_sequential.rb +512 -0
- data/examples/tools/oauth2_example.rb +136 -0
- data/examples/tools/sleepy_tool.rb +42 -0
- data/lib/legate/activity_log.rb +71 -0
- data/lib/legate/agent.rb +959 -0
- data/lib/legate/agent_code_generator.rb +185 -0
- data/lib/legate/agent_definition.rb +812 -0
- data/lib/legate/agentic/decision.rb +49 -0
- data/lib/legate/agentic/loop.rb +134 -0
- data/lib/legate/agentic.rb +5 -0
- data/lib/legate/agents/loop_agent.rb +248 -0
- data/lib/legate/agents/parallel_agent.rb +163 -0
- data/lib/legate/agents/sequential_agent.rb +190 -0
- data/lib/legate/agents.rb +14 -0
- data/lib/legate/auth/config.rb +148 -0
- data/lib/legate/auth/coordinator.rb +218 -0
- data/lib/legate/auth/coordinators/oauth2_coordinator.rb +99 -0
- data/lib/legate/auth/coordinators/oidc_coordinator.rb +68 -0
- data/lib/legate/auth/coordinators/service_account_coordinator.rb +122 -0
- data/lib/legate/auth/credential.rb +157 -0
- data/lib/legate/auth/encryption.rb +108 -0
- data/lib/legate/auth/error.rb +94 -0
- data/lib/legate/auth/exchanged_credential.rb +180 -0
- data/lib/legate/auth/excon_middleware.rb +285 -0
- data/lib/legate/auth/http_client_utils.rb +364 -0
- data/lib/legate/auth/manager.rb +531 -0
- data/lib/legate/auth/manager_store.rb +394 -0
- data/lib/legate/auth/middleware_factory.rb +290 -0
- data/lib/legate/auth/runner.rb +279 -0
- data/lib/legate/auth/scheme.rb +125 -0
- data/lib/legate/auth/schemes/api_key.rb +212 -0
- data/lib/legate/auth/schemes/google_service_account.rb +108 -0
- data/lib/legate/auth/schemes/http_bearer.rb +98 -0
- data/lib/legate/auth/schemes/oauth2.rb +396 -0
- data/lib/legate/auth/schemes/openid_connect.rb +346 -0
- data/lib/legate/auth/schemes/service_account.rb +388 -0
- data/lib/legate/auth/schemes.rb +40 -0
- data/lib/legate/auth/token_manager.rb +362 -0
- data/lib/legate/auth/token_store.rb +86 -0
- data/lib/legate/auth/tool_context_extension.rb +97 -0
- data/lib/legate/auth/tool_integration.rb +188 -0
- data/lib/legate/auth/url_guard.rb +81 -0
- data/lib/legate/auth.rb +453 -0
- data/lib/legate/callbacks/callback_context.rb +71 -0
- data/lib/legate/cli/agent_commands.rb +950 -0
- data/lib/legate/cli/auth_commands.rb +520 -0
- data/lib/legate/cli/base_command.rb +24 -0
- data/lib/legate/cli/deployment_commands.rb +934 -0
- data/lib/legate/cli/output_helper.rb +108 -0
- data/lib/legate/cli/session_commands.rb +138 -0
- data/lib/legate/cli/skaffold_commands.rb +223 -0
- data/lib/legate/cli/tool_commands.rb +261 -0
- data/lib/legate/cli/web_commands.rb +182 -0
- data/lib/legate/cli.rb +40 -0
- data/lib/legate/configuration/webhooks.rb +113 -0
- data/lib/legate/configuration.rb +39 -0
- data/lib/legate/definition_store.rb +23 -0
- data/lib/legate/errors.rb +118 -0
- data/lib/legate/event.rb +161 -0
- data/lib/legate/gemini_ai_beta_patch.rb +39 -0
- data/lib/legate/generators/agent_generator.rb +412 -0
- data/lib/legate/generators/code_validator.rb +48 -0
- data/lib/legate/generators/legate/install_generator.rb +35 -0
- data/lib/legate/generators/legate/templates/create_legate_tables.rb.tt +36 -0
- data/lib/legate/generators/legate/templates/initializer.rb +18 -0
- data/lib/legate/generators/runtime_tool_loader.rb +76 -0
- data/lib/legate/generators/tool_generator.rb +408 -0
- data/lib/legate/generators.rb +11 -0
- data/lib/legate/global_definition_registry.rb +506 -0
- data/lib/legate/global_tool_manager.rb +135 -0
- data/lib/legate/llm/adapter.rb +69 -0
- data/lib/legate/llm/gemini.rb +172 -0
- data/lib/legate/llm/ollama.rb +80 -0
- data/lib/legate/llm.rb +34 -0
- data/lib/legate/mcp/client.rb +320 -0
- data/lib/legate/mcp/connection/sse.rb +292 -0
- data/lib/legate/mcp/connection/stdio.rb +273 -0
- data/lib/legate/mcp/connection_manager.rb +103 -0
- data/lib/legate/mcp/server/legate_agent_adapter.rb +170 -0
- data/lib/legate/mcp/server/legate_direct_agent_adapter.rb +140 -0
- data/lib/legate/mcp/server/legate_tool_adapter.rb +119 -0
- data/lib/legate/mcp/tool_wrapper.rb +138 -0
- data/lib/legate/mcp/util/schema_converter.rb +134 -0
- data/lib/legate/mcp.rb +23 -0
- data/lib/legate/plan_executor.rb +375 -0
- data/lib/legate/planner.rb +839 -0
- data/lib/legate/rails/railtie.rb +43 -0
- data/lib/legate/rails.rb +9 -0
- data/lib/legate/redaction.rb +32 -0
- data/lib/legate/session.rb +299 -0
- data/lib/legate/session_service/active_record.rb +300 -0
- data/lib/legate/session_service/base.rb +68 -0
- data/lib/legate/session_service/event_broadcast.rb +74 -0
- data/lib/legate/session_service/in_memory.rb +188 -0
- data/lib/legate/tool/metadata_dsl.rb +122 -0
- data/lib/legate/tool.rb +276 -0
- data/lib/legate/tool_code_generator.rb +103 -0
- data/lib/legate/tool_context.rb +350 -0
- data/lib/legate/tool_loader.rb +39 -0
- data/lib/legate/tool_registry.rb +73 -0
- data/lib/legate/tool_result.rb +61 -0
- data/lib/legate/tools/agent_tool.rb +187 -0
- data/lib/legate/tools/base/http_client.rb +319 -0
- data/lib/legate/tools/base/safe_url.rb +56 -0
- data/lib/legate/tools/base_async_job_tool.rb +91 -0
- data/lib/legate/tools/calculator.rb +89 -0
- data/lib/legate/tools/cat_facts.rb +81 -0
- data/lib/legate/tools/check_job_status_tool.rb +48 -0
- data/lib/legate/tools/current_time_tool.rb +64 -0
- data/lib/legate/tools/echo.rb +43 -0
- data/lib/legate/tools/http_request_tool.rb +105 -0
- data/lib/legate/tools/random_number_tool.rb +64 -0
- data/lib/legate/tools/read_webpage_tool.rb +92 -0
- data/lib/legate/tools/sleepy_tool.rb +74 -0
- data/lib/legate/tools/webhook_tool.rb +146 -0
- data/lib/legate/version.rb +5 -0
- data/lib/legate/web/app.rb +984 -0
- data/lib/legate/web/public/css/main.css +4980 -0
- data/lib/legate/web/public/images/favicon-256.png +0 -0
- data/lib/legate/web/public/images/favicon-32.png +0 -0
- data/lib/legate/web/public/images/legate-logo-dark.png +0 -0
- data/lib/legate/web/public/images/legate-logo-light.png +0 -0
- data/lib/legate/web/public/js/legate.js +616 -0
- data/lib/legate/web/public/styles/main.scss +4402 -0
- data/lib/legate/web/routes/agent_authentication_routes.rb +530 -0
- data/lib/legate/web/routes/agent_definition_routes.rb +803 -0
- data/lib/legate/web/routes/agent_generator_routes.rb +80 -0
- data/lib/legate/web/routes/agent_interaction_routes.rb +734 -0
- data/lib/legate/web/routes/agent_runtime_routes.rb +323 -0
- data/lib/legate/web/routes/api_routes.rb +56 -0
- data/lib/legate/web/routes/authentication_routes.rb +1541 -0
- data/lib/legate/web/routes/core_routes.rb +111 -0
- data/lib/legate/web/routes/documentation_routes.rb +220 -0
- data/lib/legate/web/routes/tool_generator_routes.rb +81 -0
- data/lib/legate/web/routes/tools_ui_routes.rb +207 -0
- data/lib/legate/web/sass_compiler.rb +73 -0
- data/lib/legate/web/views/_active_session_info.slim +25 -0
- data/lib/legate/web/views/_activity_list.slim +55 -0
- data/lib/legate/web/views/_agent_card.slim +56 -0
- data/lib/legate/web/views/_agent_generator_modal.slim +382 -0
- data/lib/legate/web/views/_agent_status_controls.slim +71 -0
- data/lib/legate/web/views/_agent_tool_table.slim +74 -0
- data/lib/legate/web/views/_chat_message.slim +95 -0
- data/lib/legate/web/views/_display_agent_configuration.slim +26 -0
- data/lib/legate/web/views/_display_agent_description.slim +11 -0
- data/lib/legate/web/views/_display_agent_fallback.slim +15 -0
- data/lib/legate/web/views/_display_agent_hierarchy.slim +93 -0
- data/lib/legate/web/views/_display_agent_instruction.slim +17 -0
- data/lib/legate/web/views/_display_agent_mcp.slim +13 -0
- data/lib/legate/web/views/_display_agent_model.slim +17 -0
- data/lib/legate/web/views/_display_agent_name.slim +42 -0
- data/lib/legate/web/views/_display_agent_output_key.slim +26 -0
- data/lib/legate/web/views/_display_agent_type.slim +65 -0
- data/lib/legate/web/views/_edit_agent_configuration.slim +74 -0
- data/lib/legate/web/views/_edit_agent_description.slim +16 -0
- data/lib/legate/web/views/_edit_agent_fallback.slim +25 -0
- data/lib/legate/web/views/_edit_agent_hierarchy.slim +98 -0
- data/lib/legate/web/views/_edit_agent_instruction.slim +49 -0
- data/lib/legate/web/views/_edit_agent_mcp.slim +33 -0
- data/lib/legate/web/views/_edit_agent_model.slim +23 -0
- data/lib/legate/web/views/_edit_agent_output_key.slim +36 -0
- data/lib/legate/web/views/_edit_agent_tools.slim +40 -0
- data/lib/legate/web/views/_edit_agent_type.slim +67 -0
- data/lib/legate/web/views/_session_error.slim +4 -0
- data/lib/legate/web/views/_skeleton.slim +69 -0
- data/lib/legate/web/views/_tool_card.slim +9 -0
- data/lib/legate/web/views/_tool_generator_modal.slim +311 -0
- data/lib/legate/web/views/agent.slim +436 -0
- data/lib/legate/web/views/agent_auth.slim +562 -0
- data/lib/legate/web/views/agents.slim +369 -0
- data/lib/legate/web/views/auth.slim +112 -0
- data/lib/legate/web/views/auth_credential_detail.slim +327 -0
- data/lib/legate/web/views/auth_credentials.slim +261 -0
- data/lib/legate/web/views/auth_debug.slim +94 -0
- data/lib/legate/web/views/auth_mapping_detail.slim +151 -0
- data/lib/legate/web/views/auth_mapping_new.slim +123 -0
- data/lib/legate/web/views/auth_mappings.slim +120 -0
- data/lib/legate/web/views/auth_scheme_detail.slim +274 -0
- data/lib/legate/web/views/auth_schemes.slim +259 -0
- data/lib/legate/web/views/auth_test.slim +418 -0
- data/lib/legate/web/views/chat.slim +192 -0
- data/lib/legate/web/views/docs_index.slim +105 -0
- data/lib/legate/web/views/docs_show.slim +105 -0
- data/lib/legate/web/views/error_404.slim +5 -0
- data/lib/legate/web/views/index.slim +148 -0
- data/lib/legate/web/views/layout.slim +144 -0
- data/lib/legate/web/views/tool_detail.slim +87 -0
- data/lib/legate/web/views/tools.slim +50 -0
- data/lib/legate/web/webhook_listener.rb +367 -0
- data/lib/legate/web.rb +9 -0
- data/lib/legate.rb +220 -0
- data/public/docs/advanced/callbacks.md +828 -0
- data/public/docs/advanced/mcp_schema_conversion.md +59 -0
- data/public/docs/authentication/api_reference/config.md +210 -0
- data/public/docs/authentication/api_reference/credential.md +246 -0
- data/public/docs/authentication/api_reference/encryption.md +218 -0
- data/public/docs/authentication/api_reference/exchanged_credential.md +271 -0
- data/public/docs/authentication/api_reference/excon_middleware.md +175 -0
- data/public/docs/authentication/api_reference/index.md +30 -0
- data/public/docs/authentication/api_reference/scheme.md +250 -0
- data/public/docs/authentication/api_reference/schemes/api_key.md +175 -0
- data/public/docs/authentication/api_reference/schemes/google_service_account.md +221 -0
- data/public/docs/authentication/api_reference/schemes/http_bearer.md +169 -0
- data/public/docs/authentication/api_reference/schemes/oauth2.md +343 -0
- data/public/docs/authentication/api_reference/schemes/oidc.md +73 -0
- data/public/docs/authentication/api_reference/schemes/openid_connect.md +311 -0
- data/public/docs/authentication/api_reference/schemes/service_account.md +287 -0
- data/public/docs/authentication/api_reference/token_manager.md +221 -0
- data/public/docs/authentication/api_reference/token_store.md +146 -0
- data/public/docs/authentication/api_reference/tool_context_extension.md +166 -0
- data/public/docs/authentication/guides/api_key.md +190 -0
- data/public/docs/authentication/guides/bearer.md +172 -0
- data/public/docs/authentication/guides/configuration.md +255 -0
- data/public/docs/authentication/guides/custom_flow.md +523 -0
- data/public/docs/authentication/guides/index.md +24 -0
- data/public/docs/authentication/guides/migration.md +435 -0
- data/public/docs/authentication/guides/oauth2.md +252 -0
- data/public/docs/authentication/guides/oidc.md +241 -0
- data/public/docs/authentication/guides/overview.md +155 -0
- data/public/docs/authentication/guides/secure_storage.md +301 -0
- data/public/docs/authentication/guides/service_account.md +228 -0
- data/public/docs/authentication/guides/token_lifecycle.md +295 -0
- data/public/docs/authentication/guides/web_ui_integration.md +504 -0
- data/public/docs/authentication/index.md +58 -0
- data/public/docs/authentication/troubleshooting/credential_storage.md +550 -0
- data/public/docs/authentication/troubleshooting/environment_variables.md +540 -0
- data/public/docs/authentication/troubleshooting/index.md +11 -0
- data/public/docs/authentication/troubleshooting/oauth2_issues.md +220 -0
- data/public/docs/authentication/troubleshooting/oidc_issues.md +412 -0
- data/public/docs/authentication/troubleshooting/token_refresh.md +338 -0
- data/public/docs/cli/legate_cli_usage.md +363 -0
- data/public/docs/core_concepts/legate_agent_lifecycle.md +124 -0
- data/public/docs/core_concepts/legate_architecture_overview.md +110 -0
- data/public/docs/core_concepts/legate_configuration.md +116 -0
- data/public/docs/core_concepts/legate_definition_store.md +102 -0
- data/public/docs/core_concepts/legate_planner.md +94 -0
- data/public/docs/core_concepts/legate_session_service.md +104 -0
- data/public/docs/error_handling/legate_error_handling.md +122 -0
- data/public/docs/examples.md +199 -0
- data/public/docs/getting_started.md +111 -0
- data/public/docs/guides/agentic_agents.md +137 -0
- data/public/docs/guides/ai_code_generators.md +437 -0
- data/public/docs/guides/auto_loading.md +326 -0
- data/public/docs/guides/configuring_agent_webhooks.md +219 -0
- data/public/docs/guides/http_client_usage.md +264 -0
- data/public/docs/guides/llm_providers.md +137 -0
- data/public/docs/guides/mcp_client_integration.md +232 -0
- data/public/docs/guides/mcp_server_exposure.md +206 -0
- data/public/docs/guides/rails_integration.md +128 -0
- data/public/docs/guides/sending_outbound_webhooks.md +227 -0
- data/public/docs/guides/streaming.md +112 -0
- data/public/docs/guides/webhooks.md +288 -0
- data/public/docs/introduction.md +51 -0
- data/public/docs/multi_agent_systems/advanced_features.md +57 -0
- data/public/docs/multi_agent_systems/agent_delegation.md +190 -0
- data/public/docs/multi_agent_systems/agent_hierarchy.md +49 -0
- data/public/docs/multi_agent_systems/state_management.md +47 -0
- data/public/docs/multi_agent_systems/workflow_agents.md +72 -0
- data/public/docs/tools/legate_built_in_tools.md +332 -0
- data/public/docs/tools/legate_tools_and_registry.md +263 -0
- data/public/docs/web_ui/legate_web_ui.md +137 -0
- metadata +823 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
# Encryption Utilities
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `Legate::Auth::Encryption` module provides utilities for securely encrypting sensitive authentication data, such as access tokens and refresh tokens. It provides class-level methods for encryption and decryption operations.
|
|
6
|
+
|
|
7
|
+
Encryption is **opt-in**: it is not wired into `TokenStore` automatically (see [Integration with TokenStore](#integration-with-tokenstore) below). The module uses the [rbnacl](https://github.com/RubyCrypto/rbnacl) gem (libsodium SecretBox) for authenticated encryption. `rbnacl` is an **optional/development dependency** — the encryption methods lazily `require 'rbnacl'` and raise `LoadError` if it (or libsodium) is not installed. Add `gem 'rbnacl'` to your Gemfile and ensure libsodium is available to use this module.
|
|
8
|
+
|
|
9
|
+
## Module Definition
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
module Legate
|
|
13
|
+
module Auth
|
|
14
|
+
module Encryption
|
|
15
|
+
class << self
|
|
16
|
+
# Encryption class methods
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Key Features
|
|
24
|
+
|
|
25
|
+
- Secure encryption of sensitive authentication data
|
|
26
|
+
- Authenticated encryption to prevent tampering
|
|
27
|
+
- Base64 encoding for safe storage and transmission
|
|
28
|
+
- Simple class-level interface for encryption and decryption
|
|
29
|
+
- Key generation utility
|
|
30
|
+
- Detection of already-encrypted data
|
|
31
|
+
|
|
32
|
+
## Class Methods
|
|
33
|
+
|
|
34
|
+
### `encrypt`
|
|
35
|
+
|
|
36
|
+
Encrypts the provided data.
|
|
37
|
+
|
|
38
|
+
**Parameters:**
|
|
39
|
+
- `data` (String): The data to encrypt (coerced to a string)
|
|
40
|
+
- `key` (String, optional): The Base64-encoded encryption key. When omitted (`nil`), the key is read from the `LEGATE_AUTH_ENCRYPTION_KEY` environment variable.
|
|
41
|
+
|
|
42
|
+
**Returns:**
|
|
43
|
+
- String: The encrypted data, prefixed with the `LGTAUTH` header followed by Base64-encoded ciphertext
|
|
44
|
+
|
|
45
|
+
**Raises:**
|
|
46
|
+
- `LoadError`: If the `rbnacl` gem is not available
|
|
47
|
+
- `ArgumentError`: If no key is supplied and `LEGATE_AUTH_ENCRYPTION_KEY` is unset, or the key is not valid Base64
|
|
48
|
+
|
|
49
|
+
**Examples:**
|
|
50
|
+
|
|
51
|
+
```ruby
|
|
52
|
+
# Encrypt using the key from LEGATE_AUTH_ENCRYPTION_KEY
|
|
53
|
+
encrypted = Legate::Auth::Encryption.encrypt(sensitive_data)
|
|
54
|
+
|
|
55
|
+
# Encrypt data with a specific (Base64-encoded) key
|
|
56
|
+
encrypted = Legate::Auth::Encryption.encrypt(sensitive_data, my_key)
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
> There is no built-in default key. If neither an explicit key nor `LEGATE_AUTH_ENCRYPTION_KEY` is provided, an `ArgumentError` is raised.
|
|
60
|
+
|
|
61
|
+
### `decrypt`
|
|
62
|
+
|
|
63
|
+
Decrypts previously encrypted data.
|
|
64
|
+
|
|
65
|
+
**Parameters:**
|
|
66
|
+
- `encrypted_data` (String): The encrypted data (the `LGTAUTH`-prefixed string returned by `encrypt`)
|
|
67
|
+
- `key` (String, optional): The Base64-encoded encryption key. When omitted (`nil`), the key is read from `LEGATE_AUTH_ENCRYPTION_KEY`.
|
|
68
|
+
|
|
69
|
+
**Returns:**
|
|
70
|
+
- String: The decrypted data
|
|
71
|
+
|
|
72
|
+
**Raises:**
|
|
73
|
+
- `LoadError`: If the `rbnacl` gem is not available
|
|
74
|
+
- `ArgumentError`: If the data is not in the expected format, the key is missing/invalid, or decryption fails
|
|
75
|
+
|
|
76
|
+
**Examples:**
|
|
77
|
+
|
|
78
|
+
```ruby
|
|
79
|
+
# Decrypt using the key from LEGATE_AUTH_ENCRYPTION_KEY
|
|
80
|
+
decrypted = Legate::Auth::Encryption.decrypt(encrypted_data)
|
|
81
|
+
|
|
82
|
+
# Decrypt data with a specific (Base64-encoded) key
|
|
83
|
+
decrypted = Legate::Auth::Encryption.decrypt(encrypted_data, my_key)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### `generate_key`
|
|
87
|
+
|
|
88
|
+
Generates a new random encryption key, suitable for use as the `key` argument or `LEGATE_AUTH_ENCRYPTION_KEY`.
|
|
89
|
+
|
|
90
|
+
**Returns:**
|
|
91
|
+
- String: A new random key, Base64-encoded
|
|
92
|
+
|
|
93
|
+
**Raises:**
|
|
94
|
+
- `LoadError`: If the `rbnacl` gem is not available
|
|
95
|
+
|
|
96
|
+
**Examples:**
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
key = Legate::Auth::Encryption.generate_key
|
|
100
|
+
# => Base64-encoded string, e.g. "k7Qz...=="
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### `encrypted?`
|
|
104
|
+
|
|
105
|
+
Checks if the provided data appears to be encrypted.
|
|
106
|
+
|
|
107
|
+
**Parameters:**
|
|
108
|
+
- `data` (Object): The data to check
|
|
109
|
+
|
|
110
|
+
**Returns:**
|
|
111
|
+
- Boolean: `true` if the data appears to be encrypted
|
|
112
|
+
|
|
113
|
+
**Examples:**
|
|
114
|
+
|
|
115
|
+
```ruby
|
|
116
|
+
if Legate::Auth::Encryption.encrypted?(data)
|
|
117
|
+
# Data is already encrypted
|
|
118
|
+
else
|
|
119
|
+
# Data needs to be encrypted
|
|
120
|
+
end
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Usage Examples
|
|
124
|
+
|
|
125
|
+
### Encrypting Authentication Tokens
|
|
126
|
+
|
|
127
|
+
```ruby
|
|
128
|
+
# Encrypt authentication tokens
|
|
129
|
+
tokens = {
|
|
130
|
+
access_token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...',
|
|
131
|
+
refresh_token: 'rtok_abc123...',
|
|
132
|
+
expires_at: Time.now.to_i + 3600
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
encrypted_tokens = Legate::Auth::Encryption.encrypt(tokens.to_json)
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Decrypting Authentication Tokens
|
|
139
|
+
|
|
140
|
+
```ruby
|
|
141
|
+
# Decrypt authentication tokens
|
|
142
|
+
decrypted_json = Legate::Auth::Encryption.decrypt(encrypted_tokens)
|
|
143
|
+
decrypted_tokens = JSON.parse(decrypted_json, symbolize_names: true)
|
|
144
|
+
|
|
145
|
+
access_token = decrypted_tokens[:access_token]
|
|
146
|
+
refresh_token = decrypted_tokens[:refresh_token]
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Using a Custom Key
|
|
150
|
+
|
|
151
|
+
```ruby
|
|
152
|
+
# Generate a key
|
|
153
|
+
key = Legate::Auth::Encryption.generate_key
|
|
154
|
+
|
|
155
|
+
# Encrypt with the key
|
|
156
|
+
encrypted = Legate::Auth::Encryption.encrypt(data, key)
|
|
157
|
+
|
|
158
|
+
# Decrypt with the same key
|
|
159
|
+
decrypted = Legate::Auth::Encryption.decrypt(encrypted, key)
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
## Integration with TokenStore
|
|
163
|
+
|
|
164
|
+
> **Note:** `Encryption` is **not** wired into `TokenStore`. `TokenStore#store` persists the plaintext result of `token.to_h` into scoped session state, and `TokenStore#get` reads it back as-is. There is no transparent encryption layer.
|
|
165
|
+
|
|
166
|
+
If you need at-rest encryption, apply the `Encryption` module yourself — for example, encrypt the serialized token before persisting it through your own storage layer, and decrypt on read:
|
|
167
|
+
|
|
168
|
+
```ruby
|
|
169
|
+
# Opt-in: encrypt the serialized token yourself before persisting
|
|
170
|
+
require 'json'
|
|
171
|
+
|
|
172
|
+
key = ENV['LEGATE_AUTH_ENCRYPTION_KEY'] # or Legate::Auth::Encryption.generate_key
|
|
173
|
+
ciphertext = Legate::Auth::Encryption.encrypt(token.to_h.to_json, key)
|
|
174
|
+
# ...persist `ciphertext` wherever you control storage...
|
|
175
|
+
|
|
176
|
+
# On read:
|
|
177
|
+
plaintext = Legate::Auth::Encryption.decrypt(ciphertext, key)
|
|
178
|
+
token = Legate::Auth::ExchangedCredential.from_h(JSON.parse(plaintext, symbolize_names: true))
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Key Management
|
|
182
|
+
|
|
183
|
+
Best practices for key management include:
|
|
184
|
+
|
|
185
|
+
1. **Environment Variables**: Store the Base64-encoded key in `LEGATE_AUTH_ENCRYPTION_KEY`
|
|
186
|
+
2. **Secrets Manager**: Use a secrets manager to securely store and retrieve the key
|
|
187
|
+
3. **Key Rotation**: Implement a key rotation strategy for enhanced security
|
|
188
|
+
4. **Consistent Key**: Ensure the same key is used for encryption and decryption
|
|
189
|
+
|
|
190
|
+
## Security Considerations
|
|
191
|
+
|
|
192
|
+
- **Key Security**: Protect the encryption key and never hard-code it
|
|
193
|
+
- **Secure Key Generation**: Use `generate_key` for cryptographically secure keys
|
|
194
|
+
- **Token TTL**: Implement a time-to-live (TTL) for tokens to limit exposure
|
|
195
|
+
- **Memory Handling**: Clear sensitive data from memory after use when possible
|
|
196
|
+
|
|
197
|
+
## Error Handling
|
|
198
|
+
|
|
199
|
+
Decryption failures (bad format, wrong key, tampered data) raise `ArgumentError`. A missing `rbnacl` gem raises `LoadError`. There is no dedicated `EncryptionError` class.
|
|
200
|
+
|
|
201
|
+
```ruby
|
|
202
|
+
begin
|
|
203
|
+
decrypted_data = Legate::Auth::Encryption.decrypt(encrypted_data)
|
|
204
|
+
rescue LoadError => e
|
|
205
|
+
# rbnacl / libsodium not installed
|
|
206
|
+
log.error("Encryption unavailable: #{e.message}")
|
|
207
|
+
nil
|
|
208
|
+
rescue ArgumentError => e
|
|
209
|
+
# Decryption failed: invalid format, key, or tampered data
|
|
210
|
+
log.error("Decryption failed: #{e.message}")
|
|
211
|
+
nil
|
|
212
|
+
end
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Related Classes
|
|
216
|
+
|
|
217
|
+
- [`Legate::Auth::TokenStore`](./token_store): Secure storage for authentication tokens
|
|
218
|
+
- [`Legate::Auth::TokenManager`](./token_manager): Token lifecycle management
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# Legate::Auth::ExchangedCredential
|
|
2
|
+
|
|
3
|
+
The `ExchangedCredential` class represents authentication tokens obtained through credential exchange (e.g., OAuth2 access tokens, service account tokens). It provides a consistent interface for handling different types of tokens and their associated metadata.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
After authenticating with an authentication scheme, a credential is exchanged for a token. The `ExchangedCredential` class encapsulates this token along with additional information like token type, expiration time, and refresh tokens.
|
|
8
|
+
|
|
9
|
+
## Class Methods
|
|
10
|
+
|
|
11
|
+
### `new`
|
|
12
|
+
|
|
13
|
+
Creates a new exchanged credential (token) instance.
|
|
14
|
+
|
|
15
|
+
**Parameters:**
|
|
16
|
+
- `auth_type` (Symbol, required keyword): The type of authentication (e.g., `:oauth2`, `:service_account`)
|
|
17
|
+
- `access_token` (String, required keyword): The access token
|
|
18
|
+
- `refresh_token` (String, optional keyword): The refresh token (default: nil)
|
|
19
|
+
- `token_type` (String, optional keyword): The type of token (default: 'Bearer')
|
|
20
|
+
- `expires_in` (Integer, optional keyword): Seconds until expiration (default: nil)
|
|
21
|
+
- `id_token` (String, optional keyword): The ID token for OIDC flows (default: nil)
|
|
22
|
+
- `provider_id` (String, optional keyword): The provider identifier (default: nil)
|
|
23
|
+
- `**attributes` (Hash): Additional attributes specific to the token type
|
|
24
|
+
|
|
25
|
+
**Examples:**
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
# Create an OAuth2 token
|
|
29
|
+
token = Legate::Auth::ExchangedCredential.new(
|
|
30
|
+
auth_type: :oauth2,
|
|
31
|
+
access_token: 'your-access-token',
|
|
32
|
+
refresh_token: 'your-refresh-token',
|
|
33
|
+
expires_in: 3600,
|
|
34
|
+
token_type: 'Bearer'
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
# Create a service account token
|
|
38
|
+
token = Legate::Auth::ExchangedCredential.new(
|
|
39
|
+
auth_type: :service_account,
|
|
40
|
+
access_token: 'your-access-token',
|
|
41
|
+
expires_in: 3600
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Create an OIDC token with id_token
|
|
45
|
+
token = Legate::Auth::ExchangedCredential.new(
|
|
46
|
+
auth_type: :oauth2,
|
|
47
|
+
access_token: 'your-access-token',
|
|
48
|
+
refresh_token: 'your-refresh-token',
|
|
49
|
+
id_token: 'jwt-id-token',
|
|
50
|
+
expires_in: 3600
|
|
51
|
+
)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### `from_h`
|
|
55
|
+
|
|
56
|
+
Creates an ExchangedCredential from a hash representation.
|
|
57
|
+
|
|
58
|
+
**Parameters:**
|
|
59
|
+
- `hash` (Hash): The hash to create the credential from
|
|
60
|
+
|
|
61
|
+
**Returns:**
|
|
62
|
+
- Legate::Auth::ExchangedCredential: A new ExchangedCredential instance
|
|
63
|
+
|
|
64
|
+
**Examples:**
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
token = Legate::Auth::ExchangedCredential.from_h(saved_token_hash)
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Instance Methods
|
|
71
|
+
|
|
72
|
+
### `[]` (accessor)
|
|
73
|
+
|
|
74
|
+
Gets an attribute from the token.
|
|
75
|
+
|
|
76
|
+
**Parameters:**
|
|
77
|
+
- `name` (Symbol, String): The attribute name
|
|
78
|
+
|
|
79
|
+
**Returns:**
|
|
80
|
+
- Object: The attribute value, or nil if not present
|
|
81
|
+
|
|
82
|
+
**Examples:**
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
token = Legate::Auth::ExchangedCredential.new(
|
|
86
|
+
auth_type: :oauth2,
|
|
87
|
+
access_token: 'your-access-token',
|
|
88
|
+
refresh_token: 'your-refresh-token'
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
access_token = token[:access_token]
|
|
92
|
+
refresh_token = token[:refresh_token]
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### `to_h`
|
|
96
|
+
|
|
97
|
+
Converts the token to a hash.
|
|
98
|
+
|
|
99
|
+
**Returns:**
|
|
100
|
+
- Hash: A hash representation of the token
|
|
101
|
+
|
|
102
|
+
**Examples:**
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
token = Legate::Auth::ExchangedCredential.new(
|
|
106
|
+
auth_type: :oauth2,
|
|
107
|
+
access_token: 'your-access-token',
|
|
108
|
+
refresh_token: 'your-refresh-token',
|
|
109
|
+
expires_in: 3600
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
token_hash = token.to_h
|
|
113
|
+
# => {auth_type: :oauth2, access_token: "your-access-token", refresh_token: "your-refresh-token", ...}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### `with`
|
|
117
|
+
|
|
118
|
+
Returns a new ExchangedCredential with updated attributes.
|
|
119
|
+
|
|
120
|
+
**Parameters:**
|
|
121
|
+
- `attrs` (Hash): The attributes to update
|
|
122
|
+
|
|
123
|
+
**Returns:**
|
|
124
|
+
- Legate::Auth::ExchangedCredential: A new instance with the updated attributes
|
|
125
|
+
|
|
126
|
+
**Examples:**
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
new_token = token.with(access_token: 'new-access-token', expires_in: 7200)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### `expired?`
|
|
133
|
+
|
|
134
|
+
Checks if the token is expired.
|
|
135
|
+
|
|
136
|
+
**Parameters:**
|
|
137
|
+
- `buffer_seconds` (Integer, optional): Buffer time in seconds before actual expiration (default: 30)
|
|
138
|
+
|
|
139
|
+
**Returns:**
|
|
140
|
+
- Boolean: `true` if the token is expired or will expire within the buffer time
|
|
141
|
+
|
|
142
|
+
**Examples:**
|
|
143
|
+
|
|
144
|
+
```ruby
|
|
145
|
+
token = Legate::Auth::ExchangedCredential.new(
|
|
146
|
+
auth_type: :oauth2,
|
|
147
|
+
access_token: 'your-access-token',
|
|
148
|
+
expires_in: 3600
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
# Check if expired (with default 30-second buffer)
|
|
152
|
+
puts token.expired?
|
|
153
|
+
# => false
|
|
154
|
+
|
|
155
|
+
# Check if expires within the next 5 minutes
|
|
156
|
+
puts token.expired?(300)
|
|
157
|
+
# => false (if more than 5 minutes remaining)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### `refreshable?`
|
|
161
|
+
|
|
162
|
+
Checks if the token can be refreshed (i.e., has a refresh token).
|
|
163
|
+
|
|
164
|
+
**Returns:**
|
|
165
|
+
- Boolean: `true` if the token has a refresh token and can be refreshed
|
|
166
|
+
|
|
167
|
+
**Examples:**
|
|
168
|
+
|
|
169
|
+
```ruby
|
|
170
|
+
token = Legate::Auth::ExchangedCredential.new(
|
|
171
|
+
auth_type: :oauth2,
|
|
172
|
+
access_token: 'your-access-token',
|
|
173
|
+
refresh_token: 'your-refresh-token'
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
puts token.refreshable?
|
|
177
|
+
# => true
|
|
178
|
+
|
|
179
|
+
token_without_refresh = Legate::Auth::ExchangedCredential.new(
|
|
180
|
+
auth_type: :api_key,
|
|
181
|
+
access_token: 'your-api-key'
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
puts token_without_refresh.refreshable?
|
|
185
|
+
# => false
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### `id_token_claims`
|
|
189
|
+
|
|
190
|
+
Decodes and returns the claims from the ID token (for OIDC tokens).
|
|
191
|
+
|
|
192
|
+
**Returns:**
|
|
193
|
+
- Hash: The decoded ID token claims, or nil if no ID token is present
|
|
194
|
+
|
|
195
|
+
**Examples:**
|
|
196
|
+
|
|
197
|
+
```ruby
|
|
198
|
+
token = Legate::Auth::ExchangedCredential.new(
|
|
199
|
+
auth_type: :oauth2,
|
|
200
|
+
access_token: 'your-access-token',
|
|
201
|
+
id_token: 'jwt-id-token'
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
claims = token.id_token_claims
|
|
205
|
+
puts claims['sub'] # => "user-id"
|
|
206
|
+
puts claims['email'] # => "user@example.com"
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Common Token Attributes
|
|
210
|
+
|
|
211
|
+
Different token types have different attributes, but some common ones include:
|
|
212
|
+
|
|
213
|
+
| Attribute | Description | Token Types |
|
|
214
|
+
|-----------|-------------|------------|
|
|
215
|
+
| `access_token` | The access token used for authentication | All |
|
|
216
|
+
| `refresh_token` | Token used to refresh the access token | OAuth2, OIDC |
|
|
217
|
+
| `id_token` | JWT token containing user identity | OIDC |
|
|
218
|
+
| `expires_in` | Seconds until the token expires | OAuth2, OIDC, Service Account |
|
|
219
|
+
| `token_type` | Type of token (default: 'Bearer') | OAuth2, OIDC |
|
|
220
|
+
| `provider_id` | The provider identifier | Any |
|
|
221
|
+
|
|
222
|
+
## Working with Token Expiration
|
|
223
|
+
|
|
224
|
+
Managing token expiration is a common task:
|
|
225
|
+
|
|
226
|
+
```ruby
|
|
227
|
+
token = Legate::Auth::ExchangedCredential.new(
|
|
228
|
+
auth_type: :oauth2,
|
|
229
|
+
access_token: 'your-access-token',
|
|
230
|
+
expires_in: 3600
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
# Check if expired (30-second buffer by default)
|
|
234
|
+
if token.expired?
|
|
235
|
+
# Token needs to be refreshed
|
|
236
|
+
else
|
|
237
|
+
# Token is still valid
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Check if expiring soon (within 5 minutes)
|
|
241
|
+
if token.expired?(300)
|
|
242
|
+
# Token will expire soon, consider refreshing
|
|
243
|
+
end
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Secure Token Storage
|
|
247
|
+
|
|
248
|
+
ExchangedCredential objects contain sensitive information and should be handled securely:
|
|
249
|
+
|
|
250
|
+
1. Never log the full token
|
|
251
|
+
2. Store tokens securely — note that `TokenStore` does not encrypt them; apply the opt-in [`Legate::Auth::Encryption`](./encryption) module yourself if at-rest encryption is required
|
|
252
|
+
3. Implement proper token lifecycle management
|
|
253
|
+
|
|
254
|
+
```ruby
|
|
255
|
+
# Example of secure logging
|
|
256
|
+
token = Legate::Auth::ExchangedCredential.new(
|
|
257
|
+
auth_type: :oauth2,
|
|
258
|
+
access_token: 'your-access-token',
|
|
259
|
+
refresh_token: 'your-refresh-token'
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
# Log safely (truncate sensitive values)
|
|
263
|
+
logger.info "Token type: #{token[:auth_type]}, " \
|
|
264
|
+
"Access token: #{token[:access_token].to_s[0..5]}..."
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
## See Also
|
|
268
|
+
|
|
269
|
+
- [Legate::Auth::Credential](./credential)
|
|
270
|
+
- [Legate::Auth::Scheme](./scheme)
|
|
271
|
+
- [Legate::Auth::TokenManager](./token_manager)
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# Excon Middleware for Authentication
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
The `Legate::Auth::ExconMiddleware` provides automatic authentication header injection for HTTP requests made using the Excon HTTP client. This middleware simplifies authentication by seamlessly handling token lifecycle, automatic retries for authentication failures, and integrating with the Legate authentication system.
|
|
6
|
+
|
|
7
|
+
> **Wiring:** You normally don't construct this middleware directly or pass scheme/credential as top-level `Excon.new` keyword arguments. Instead use the helper methods `Legate::Auth.create_connection(url, scheme:, credential:, ...)` or `Legate::Auth.create_middleware(scheme:, credential:, ...)`. When the middleware runs inside Excon's stack it operates as a "shell" instance and reads its configuration from `datum[:connection].data[:auth_middleware_config]`, which the helpers set up for you.
|
|
8
|
+
|
|
9
|
+
## Class Definition
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
module Legate
|
|
13
|
+
module Auth
|
|
14
|
+
class ExconMiddleware < Excon::Middleware::Base
|
|
15
|
+
# Implementation of Excon middleware for authentication
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Key Features
|
|
22
|
+
|
|
23
|
+
- Automatic injection of authentication headers based on scheme type
|
|
24
|
+
- Token refresh handling for expired credentials
|
|
25
|
+
- Configurable retry behavior for authentication failures
|
|
26
|
+
- Integration with the Legate token lifecycle management
|
|
27
|
+
- Support for all authentication schemes (API Key, Bearer, OAuth2, OIDC, Service Account)
|
|
28
|
+
|
|
29
|
+
## Constructor
|
|
30
|
+
|
|
31
|
+
### `initialize`
|
|
32
|
+
|
|
33
|
+
Creates a new ExconMiddleware instance.
|
|
34
|
+
|
|
35
|
+
**Parameters:**
|
|
36
|
+
- `stack` (Object): The Excon middleware stack (positional argument)
|
|
37
|
+
- `options` (Hash, optional): Configuration options (positional argument, default: {})
|
|
38
|
+
|
|
39
|
+
**Options Keys:**
|
|
40
|
+
- `:scheme` (Legate::Auth::Scheme): Authentication scheme to use
|
|
41
|
+
- `:credential` (Legate::Auth::Credential): Initial authentication credential
|
|
42
|
+
- `:token_store` (Legate::Auth::TokenStore): Store for caching tokens
|
|
43
|
+
- `:token_manager` (Legate::Auth::TokenManager): Token lifecycle manager
|
|
44
|
+
- `:auto_retry` (Boolean): Whether to automatically retry on auth failure
|
|
45
|
+
- `:max_retries` (Integer): Maximum number of retry attempts for auth failures (default: 3)
|
|
46
|
+
- `:backoff_strategy` (Symbol): Strategy for retry delay (`:none`, `:linear`, `:exponential`)
|
|
47
|
+
- `:backoff_factor` (Float): Factor for backoff calculation
|
|
48
|
+
- `:retry_non_idempotent` (Boolean): Whether to retry non-idempotent requests
|
|
49
|
+
- `:retry_on` (Array): HTTP status codes or exceptions that trigger retries
|
|
50
|
+
|
|
51
|
+
## Instance Methods
|
|
52
|
+
|
|
53
|
+
### `request_call`
|
|
54
|
+
|
|
55
|
+
Called before each request to inject authentication headers.
|
|
56
|
+
|
|
57
|
+
**Parameters:**
|
|
58
|
+
- `datum` (Hash): The Excon request datum
|
|
59
|
+
|
|
60
|
+
**Returns:**
|
|
61
|
+
- Hash: The modified request datum with authentication headers
|
|
62
|
+
|
|
63
|
+
### `response_call`
|
|
64
|
+
|
|
65
|
+
Called after each response to check for authentication failures and handle retries.
|
|
66
|
+
|
|
67
|
+
**Parameters:**
|
|
68
|
+
- `datum` (Hash): The Excon response datum
|
|
69
|
+
|
|
70
|
+
**Returns:**
|
|
71
|
+
- Hash: The response datum
|
|
72
|
+
|
|
73
|
+
### `should_retry?`
|
|
74
|
+
|
|
75
|
+
Determines if a request should be retried based on the response.
|
|
76
|
+
|
|
77
|
+
**Parameters:**
|
|
78
|
+
- `request_datum` (Hash): The original request datum
|
|
79
|
+
- `response_details` (Hash): Details about the response
|
|
80
|
+
|
|
81
|
+
**Returns:**
|
|
82
|
+
- Boolean: `true` if the request should be retried
|
|
83
|
+
|
|
84
|
+
## Usage
|
|
85
|
+
|
|
86
|
+
### Basic Usage
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
# Create a connection with authentication middleware via the helper
|
|
90
|
+
connection = Legate::Auth.create_connection('https://api.example.com',
|
|
91
|
+
scheme: api_key_scheme,
|
|
92
|
+
credential: api_key_credential
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Make authenticated requests
|
|
96
|
+
response = connection.get(path: '/protected-resource')
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### With Token Store
|
|
100
|
+
|
|
101
|
+
```ruby
|
|
102
|
+
# Pass a token store/manager for caching and lifecycle management
|
|
103
|
+
connection = Legate::Auth.create_connection('https://api.example.com',
|
|
104
|
+
scheme: oauth2_scheme,
|
|
105
|
+
credential: oauth2_credential,
|
|
106
|
+
token_store: token_store,
|
|
107
|
+
token_manager: token_manager
|
|
108
|
+
)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### With Retry Configuration
|
|
112
|
+
|
|
113
|
+
```ruby
|
|
114
|
+
connection = Legate::Auth.create_connection('https://api.example.com',
|
|
115
|
+
scheme: scheme,
|
|
116
|
+
credential: credential,
|
|
117
|
+
auto_retry: true,
|
|
118
|
+
max_retries: 3,
|
|
119
|
+
backoff_strategy: :exponential,
|
|
120
|
+
backoff_factor: 2.0,
|
|
121
|
+
retry_on: [401, 403]
|
|
122
|
+
)
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
These helpers add `ExconMiddleware` to the connection's middleware stack and store the configured middleware instance on `connection.data[:auth_middleware_config]`, where the shell middleware reads it at request time.
|
|
126
|
+
|
|
127
|
+
## Example with OAuth2
|
|
128
|
+
|
|
129
|
+
```ruby
|
|
130
|
+
# Create OAuth2 scheme and credential
|
|
131
|
+
scheme = Legate::Auth::Schemes::OAuth2.new(
|
|
132
|
+
token_url: 'https://auth.example.com/token',
|
|
133
|
+
authorization_url: 'https://auth.example.com/authorize',
|
|
134
|
+
scopes: ['read', 'write']
|
|
135
|
+
)
|
|
136
|
+
credential = Legate::Auth::Credential.new(
|
|
137
|
+
auth_type: :oauth2,
|
|
138
|
+
client_id: ENV['CLIENT_ID'],
|
|
139
|
+
client_secret: ENV['CLIENT_SECRET']
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
# Create connection with OAuth2 authentication
|
|
143
|
+
token_store = Legate::Auth::TokenStore.new(session_service)
|
|
144
|
+
token_manager = Legate::Auth::TokenManager.new(token_store)
|
|
145
|
+
|
|
146
|
+
connection = Legate::Auth.create_connection('https://api.example.com',
|
|
147
|
+
scheme: scheme,
|
|
148
|
+
credential: credential,
|
|
149
|
+
token_store: token_store,
|
|
150
|
+
token_manager: token_manager
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# Make authenticated request
|
|
154
|
+
response = connection.get(path: '/user/profile')
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Middleware Stack Position
|
|
158
|
+
|
|
159
|
+
For proper operation, the `ExconMiddleware` should be positioned after any middleware that modifies the request parameters and before middleware that actually makes the HTTP request.
|
|
160
|
+
|
|
161
|
+
## Integration with Token Lifecycle
|
|
162
|
+
|
|
163
|
+
The middleware automatically integrates with the Legate token lifecycle management:
|
|
164
|
+
|
|
165
|
+
1. When a request is made, it checks for existing valid tokens
|
|
166
|
+
2. If tokens are expired, it attempts to refresh them automatically
|
|
167
|
+
3. If refresh fails or tokens are invalid, it triggers the appropriate authentication flow
|
|
168
|
+
4. On successful authentication, it retries the original request
|
|
169
|
+
|
|
170
|
+
## Related Classes
|
|
171
|
+
|
|
172
|
+
- [`Legate::Auth::Scheme`](./scheme): Base class for authentication schemes
|
|
173
|
+
- [`Legate::Auth::Credential`](./credential): Container for authentication credentials
|
|
174
|
+
- [`Legate::Auth::TokenManager`](./token_manager): Manages token lifecycle
|
|
175
|
+
- [`Legate::Auth::ToolContextExtension`](./tool_context_extension): Tool context integration
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Authentication API Reference
|
|
2
|
+
|
|
3
|
+
This section provides comprehensive documentation for all authentication-related classes and methods in the Legate Ruby library.
|
|
4
|
+
|
|
5
|
+
## Core Classes
|
|
6
|
+
|
|
7
|
+
- [Legate::Auth::Scheme](./scheme) - Abstract base class for authentication schemes
|
|
8
|
+
- [Legate::Auth::Credential](./credential) - Container for authentication credentials
|
|
9
|
+
- [Legate::Auth::Config](./config) - Configuration for authentication flows
|
|
10
|
+
- [Legate::Auth::ExchangedCredential](./exchanged_credential) - Container for exchanged credentials
|
|
11
|
+
|
|
12
|
+
## Authentication Schemes
|
|
13
|
+
|
|
14
|
+
- [Legate::Auth::Schemes::ApiKey](./schemes/api_key) - API Key authentication scheme
|
|
15
|
+
- [Legate::Auth::Schemes::HTTPBearer](./schemes/http_bearer) - HTTP Bearer authentication scheme
|
|
16
|
+
- [Legate::Auth::Schemes::OAuth2](./schemes/oauth2) - OAuth2 authentication scheme
|
|
17
|
+
- [Legate::Auth::Schemes::OpenIDConnect](./schemes/openid_connect) - OpenID Connect authentication scheme
|
|
18
|
+
- [Legate::Auth::Schemes::ServiceAccount](./schemes/service_account) - Service Account authentication scheme
|
|
19
|
+
- [Legate::Auth::Schemes::GoogleServiceAccount](./schemes/google_service_account) - Google Service Account authentication scheme
|
|
20
|
+
|
|
21
|
+
## Authentication Management
|
|
22
|
+
|
|
23
|
+
- [Legate::Auth::TokenManager](./token_manager) - Token lifecycle management
|
|
24
|
+
- [Legate::Auth::TokenStore](./token_store) - Secure token storage
|
|
25
|
+
- [Legate::Auth::Encryption](./encryption) - Opt-in encryption utilities (not wired into TokenStore)
|
|
26
|
+
|
|
27
|
+
## Integration
|
|
28
|
+
|
|
29
|
+
- [Legate::Auth::ToolContextExtension](./tool_context_extension) - Tool context authentication extensions
|
|
30
|
+
- [Legate::Auth::ExconMiddleware](./excon_middleware) - Middleware for Excon HTTP client
|