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,362 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'token_store'
|
|
4
|
+
require_relative 'exchanged_credential'
|
|
5
|
+
require_relative 'error'
|
|
6
|
+
|
|
7
|
+
module Legate
|
|
8
|
+
module Auth
|
|
9
|
+
# TokenManager is responsible for managing the lifecycle of authentication tokens.
|
|
10
|
+
# It provides a centralized system for token acquisition, refresh, and invalidation.
|
|
11
|
+
# This class works with the TokenStore for persistence and the various authentication
|
|
12
|
+
# schemes for token operations.
|
|
13
|
+
class TokenManager
|
|
14
|
+
# Default configuration values
|
|
15
|
+
DEFAULT_CONFIG = {
|
|
16
|
+
refresh_buffer: 60, # Seconds before expiration to trigger refresh
|
|
17
|
+
retry_max_attempts: 3, # Maximum number of refresh retry attempts
|
|
18
|
+
retry_delay: 2, # Initial delay between retries (seconds)
|
|
19
|
+
retry_backoff: 1.5, # Backoff multiplier for subsequent retries
|
|
20
|
+
auto_refresh: true, # Whether to automatically refresh tokens
|
|
21
|
+
background_refresh: false # Whether to refresh tokens in background
|
|
22
|
+
}.freeze
|
|
23
|
+
|
|
24
|
+
# Initialize a new TokenManager
|
|
25
|
+
# @param token_store [Legate::Auth::TokenStore] The token store for persistence
|
|
26
|
+
# @param config [Hash] Configuration options
|
|
27
|
+
def initialize(token_store, config = {})
|
|
28
|
+
@token_store = token_store
|
|
29
|
+
@config = DEFAULT_CONFIG.merge(config)
|
|
30
|
+
@callbacks = {
|
|
31
|
+
before_expiry: [],
|
|
32
|
+
refresh_success: [],
|
|
33
|
+
refresh_failure: [],
|
|
34
|
+
invalidated: []
|
|
35
|
+
}
|
|
36
|
+
@lock = Mutex.new
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Get a token for the given scheme and credential
|
|
40
|
+
# @param scheme [Legate::Auth::Scheme] The authentication scheme
|
|
41
|
+
# @param credential [Legate::Auth::Credential] The credential
|
|
42
|
+
# @param force_refresh [Boolean] Whether to force a token refresh
|
|
43
|
+
# @return [Legate::Auth::ExchangedCredential, nil] The token or nil if not available
|
|
44
|
+
def get_token(scheme, credential, force_refresh: false)
|
|
45
|
+
raise ArgumentError, 'Scheme must be an Legate::Auth::Scheme' unless scheme.is_a?(Legate::Auth::Scheme)
|
|
46
|
+
|
|
47
|
+
cache_key = generate_cache_key(scheme, credential)
|
|
48
|
+
|
|
49
|
+
# Use a mutex to prevent race conditions during token retrieval/refresh
|
|
50
|
+
@lock.synchronize do
|
|
51
|
+
# Try to get the token from the store
|
|
52
|
+
token = @token_store.get(cache_key)
|
|
53
|
+
|
|
54
|
+
# If no token, refresh it
|
|
55
|
+
return refresh_token(scheme, credential, nil, cache_key) if token.nil?
|
|
56
|
+
|
|
57
|
+
# Check if a scheme supports refresh
|
|
58
|
+
supports_refresh = scheme.respond_to?(:supports_refresh?) && scheme.supports_refresh?
|
|
59
|
+
is_refreshable = token.respond_to?(:refreshable?) && token.refreshable?
|
|
60
|
+
|
|
61
|
+
# If force refresh is requested, refresh the token regardless of expiration
|
|
62
|
+
if force_refresh
|
|
63
|
+
# Check if the token is refreshable before attempting to refresh
|
|
64
|
+
return refresh_token(scheme, credential, token, cache_key) if supports_refresh && is_refreshable
|
|
65
|
+
|
|
66
|
+
# For tokens that aren't refreshable, create a new one
|
|
67
|
+
invalidate_token(cache_key)
|
|
68
|
+
new_token = exchange_token(scheme, credential)
|
|
69
|
+
if new_token
|
|
70
|
+
@token_store.store(cache_key, new_token)
|
|
71
|
+
trigger_callback(:refresh_success, new_token, scheme, credential)
|
|
72
|
+
return new_token
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Check if token needs refresh based on expiration
|
|
78
|
+
if needs_refresh?(token)
|
|
79
|
+
# Only try to refresh if the scheme supports it and the token is refreshable
|
|
80
|
+
return refresh_token(scheme, credential, token, cache_key) if supports_refresh && is_refreshable
|
|
81
|
+
|
|
82
|
+
# If not refreshable, invalidate and return nil
|
|
83
|
+
invalidate_token(cache_key)
|
|
84
|
+
return nil
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Check if token is approaching expiration and trigger callback
|
|
89
|
+
if approaching_expiration?(token)
|
|
90
|
+
trigger_callback(:before_expiry, token, scheme, credential)
|
|
91
|
+
|
|
92
|
+
# If auto_refresh is enabled and we can refresh, do it
|
|
93
|
+
return refresh_token(scheme, credential, token, cache_key) if @config[:auto_refresh] && supports_refresh && is_refreshable
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
token
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# Explicitly refresh a token
|
|
101
|
+
# @param scheme [Legate::Auth::Scheme] The authentication scheme
|
|
102
|
+
# @param credential [Legate::Auth::Credential] The credential
|
|
103
|
+
# @param token [Legate::Auth::ExchangedCredential, nil] The current token, if available
|
|
104
|
+
# @return [Legate::Auth::ExchangedCredential, nil] The refreshed token or nil on failure
|
|
105
|
+
def refresh_token(scheme, credential, token = nil, cache_key = nil)
|
|
106
|
+
raise ArgumentError, 'Scheme must be an Legate::Auth::Scheme' unless scheme.is_a?(Legate::Auth::Scheme)
|
|
107
|
+
|
|
108
|
+
cache_key ||= generate_cache_key(scheme, credential)
|
|
109
|
+
|
|
110
|
+
# If we don't have a token and it's an oauth or service account scheme,
|
|
111
|
+
# we need to authenticate from scratch
|
|
112
|
+
if token.nil?
|
|
113
|
+
if %i[oauth2 oidc service_account].include?(scheme.scheme_type)
|
|
114
|
+
# For these schemes, we need a complete authentication flow
|
|
115
|
+
# which can't be handled here - return nil to indicate need for full auth
|
|
116
|
+
return nil
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# For other schemes, we can simply apply the credential
|
|
120
|
+
begin
|
|
121
|
+
# Basic auth, API key, etc. - create a new token directly
|
|
122
|
+
token = exchange_token(scheme, credential)
|
|
123
|
+
if token
|
|
124
|
+
@token_store.store(cache_key, token)
|
|
125
|
+
trigger_callback(:refresh_success, token, scheme, credential)
|
|
126
|
+
end
|
|
127
|
+
return token
|
|
128
|
+
rescue Legate::Auth::Error => e
|
|
129
|
+
Legate.logger.error("Failed to create token: #{e.message}")
|
|
130
|
+
trigger_callback(:refresh_failure, nil, scheme, credential, error: e)
|
|
131
|
+
return nil
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# Token exists - attempt to refresh it if scheme supports refresh
|
|
136
|
+
supports_refresh = scheme.respond_to?(:supports_refresh?) && scheme.supports_refresh?
|
|
137
|
+
is_refreshable = token.respond_to?(:refreshable?) && token.refreshable?
|
|
138
|
+
|
|
139
|
+
if supports_refresh && is_refreshable
|
|
140
|
+
begin
|
|
141
|
+
refreshed = scheme.refresh_token(token, credential)
|
|
142
|
+
if refreshed
|
|
143
|
+
@token_store.store(cache_key, refreshed)
|
|
144
|
+
trigger_callback(:refresh_success, refreshed, scheme, credential)
|
|
145
|
+
return refreshed
|
|
146
|
+
else
|
|
147
|
+
# Handle the case where refresh_token returns nil but doesn't raise an error
|
|
148
|
+
Legate.logger.error('Failed to refresh token: refresh_token returned nil')
|
|
149
|
+
trigger_callback(:refresh_failure, token, scheme, credential, error: nil)
|
|
150
|
+
return nil
|
|
151
|
+
end
|
|
152
|
+
rescue Legate::Auth::TokenRefreshError => e
|
|
153
|
+
Legate.logger.error("Failed to refresh token: #{e.message}")
|
|
154
|
+
trigger_callback(:refresh_failure, token, scheme, credential, error: e)
|
|
155
|
+
return nil
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
# Scheme doesn't support refresh or token isn't refreshable
|
|
160
|
+
# Return existing token if it's not expired
|
|
161
|
+
return token unless token.expired?
|
|
162
|
+
|
|
163
|
+
# Otherwise, invalidate it
|
|
164
|
+
invalidate_token(cache_key)
|
|
165
|
+
nil
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# Invalidate a token, removing it from the store
|
|
169
|
+
# @param cache_key [String] The cache key for the token
|
|
170
|
+
# @return [Boolean] True if the token was invalidated
|
|
171
|
+
def invalidate_token(cache_key)
|
|
172
|
+
result = @token_store.clear(cache_key)
|
|
173
|
+
trigger_callback(:invalidated, nil, nil, nil, cache_key: cache_key) if result
|
|
174
|
+
result
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Revoke a token with the authentication provider
|
|
178
|
+
# @param scheme [Legate::Auth::Scheme] The authentication scheme
|
|
179
|
+
# @param credential [Legate::Auth::Credential] The credential
|
|
180
|
+
# @param token [Legate::Auth::ExchangedCredential] The token to revoke
|
|
181
|
+
# @return [Boolean] True if the token was revoked
|
|
182
|
+
def revoke_token(scheme, credential, token)
|
|
183
|
+
raise ArgumentError, 'Scheme must be an Legate::Auth::Scheme' unless scheme.is_a?(Legate::Auth::Scheme)
|
|
184
|
+
raise ArgumentError, 'Token must be an ExchangedCredential' unless token.is_a?(Legate::Auth::ExchangedCredential)
|
|
185
|
+
|
|
186
|
+
# Check if scheme supports revocation
|
|
187
|
+
unless scheme.respond_to?(:revoke_token)
|
|
188
|
+
Legate.logger.warn("Scheme #{scheme.scheme_type} does not support token revocation")
|
|
189
|
+
return false
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
begin
|
|
193
|
+
# Attempt to revoke the token
|
|
194
|
+
result = scheme.revoke_token(token, credential)
|
|
195
|
+
|
|
196
|
+
# Invalidate the token in our store if revocation succeeded
|
|
197
|
+
if result
|
|
198
|
+
cache_key = generate_cache_key(scheme, credential)
|
|
199
|
+
invalidate_token(cache_key)
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
result
|
|
203
|
+
rescue Legate::Auth::Error => e
|
|
204
|
+
Legate.logger.error("Failed to revoke token: #{e.message}")
|
|
205
|
+
false
|
|
206
|
+
rescue NotImplementedError => e
|
|
207
|
+
Legate.logger.error("#{e.message}")
|
|
208
|
+
false
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# Register a callback for token lifecycle events
|
|
213
|
+
# @param event [Symbol] The event to register for (:before_expiry, :refresh_success, :refresh_failure, :invalidated)
|
|
214
|
+
# @param callback [Proc] The callback to execute
|
|
215
|
+
# @return [self]
|
|
216
|
+
def on(event, &callback)
|
|
217
|
+
raise ArgumentError, "Unknown event: #{event}. Valid events: #{@callbacks.keys.join(', ')}" unless @callbacks.key?(event)
|
|
218
|
+
|
|
219
|
+
@callbacks[event] << callback
|
|
220
|
+
self
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
private
|
|
224
|
+
|
|
225
|
+
# Check if a token needs to be refreshed
|
|
226
|
+
# @param token [Legate::Auth::ExchangedCredential] The token to check
|
|
227
|
+
# @return [Boolean] True if the token needs to be refreshed
|
|
228
|
+
def needs_refresh?(token)
|
|
229
|
+
token.expired?(@config[:refresh_buffer])
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# Check if a token is approaching expiration
|
|
233
|
+
# @param token [Legate::Auth::ExchangedCredential] The token to check
|
|
234
|
+
# @return [Boolean] True if the token is approaching expiration
|
|
235
|
+
def approaching_expiration?(token)
|
|
236
|
+
return false unless token.expires_at
|
|
237
|
+
|
|
238
|
+
# Consider a token approaching expiration if it's within 2x the refresh buffer
|
|
239
|
+
buffer = @config[:refresh_buffer] * 2
|
|
240
|
+
(token.expires_at - Time.now) <= buffer
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# Generate a cache key for the token
|
|
244
|
+
# @param scheme [Legate::Auth::Scheme] The authentication scheme
|
|
245
|
+
# @param credential [Legate::Auth::Credential] The credential
|
|
246
|
+
# @return [String] The cache key
|
|
247
|
+
def generate_cache_key(scheme, credential)
|
|
248
|
+
require 'digest/sha2'
|
|
249
|
+
|
|
250
|
+
# Create a unique key based on scheme and credential
|
|
251
|
+
parts = [
|
|
252
|
+
scheme.scheme_type.to_s,
|
|
253
|
+
credential.auth_type.to_s
|
|
254
|
+
]
|
|
255
|
+
|
|
256
|
+
# Add scheme-specific information
|
|
257
|
+
case scheme.scheme_type
|
|
258
|
+
when :api_key
|
|
259
|
+
parts << credential[:api_key, resolve_env: false].to_s
|
|
260
|
+
when :http_bearer
|
|
261
|
+
parts << credential[:bearer_token, resolve_env: false].to_s
|
|
262
|
+
when :oauth2, :oidc
|
|
263
|
+
parts << credential[:client_id, resolve_env: false].to_s
|
|
264
|
+
parts << (credential[:scope, resolve_env: false] || '').to_s
|
|
265
|
+
when :service_account
|
|
266
|
+
parts << credential[:client_email, resolve_env: false].to_s
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
"auth_#{Digest::SHA256.hexdigest(parts.join(':'))}"
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Perform token refresh with retry logic
|
|
273
|
+
# @param scheme [Legate::Auth::Scheme] The authentication scheme
|
|
274
|
+
# @param credential [Legate::Auth::Credential] The credential
|
|
275
|
+
# @param token [Legate::Auth::ExchangedCredential] The current token
|
|
276
|
+
# @param cache_key [String] The cache key
|
|
277
|
+
# @return [Legate::Auth::ExchangedCredential, nil] The refreshed token or nil on failure
|
|
278
|
+
def perform_token_refresh(scheme, credential, token, cache_key)
|
|
279
|
+
attempts = 0
|
|
280
|
+
delay = @config[:retry_delay]
|
|
281
|
+
|
|
282
|
+
loop do
|
|
283
|
+
refreshed = scheme.refresh_token(token, credential)
|
|
284
|
+
if refreshed
|
|
285
|
+
@token_store.store(cache_key, refreshed)
|
|
286
|
+
trigger_callback(:refresh_success, refreshed, scheme, credential)
|
|
287
|
+
return refreshed
|
|
288
|
+
else
|
|
289
|
+
# Handle the case where refresh_token returns nil but doesn't raise an error
|
|
290
|
+
Legate.logger.error('Failed to refresh token: refresh_token returned nil')
|
|
291
|
+
trigger_callback(:refresh_failure, token, scheme, credential, error: nil)
|
|
292
|
+
return nil
|
|
293
|
+
end
|
|
294
|
+
rescue Legate::Auth::TokenRefreshError => e
|
|
295
|
+
attempts += 1
|
|
296
|
+
|
|
297
|
+
# Check if we've exceeded max attempts
|
|
298
|
+
if attempts >= @config[:retry_max_attempts]
|
|
299
|
+
Legate.logger.error("Failed to refresh token after #{attempts} attempts: #{e.message}")
|
|
300
|
+
trigger_callback(:refresh_failure, token, scheme, credential, error: e)
|
|
301
|
+
return nil
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# Exponential backoff for retry
|
|
305
|
+
sleep delay
|
|
306
|
+
delay *= @config[:retry_backoff]
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
# Exchange a credential for a token
|
|
311
|
+
# @param scheme [Legate::Auth::Scheme] The authentication scheme
|
|
312
|
+
# @param credential [Legate::Auth::Credential] The credential
|
|
313
|
+
# @return [Legate::Auth::ExchangedCredential, nil] The exchanged token or nil on failure
|
|
314
|
+
def exchange_token(scheme, credential)
|
|
315
|
+
case scheme.scheme_type
|
|
316
|
+
when :api_key
|
|
317
|
+
# Create a simple exchanged credential for API key
|
|
318
|
+
Legate::Auth::ExchangedCredential.new(
|
|
319
|
+
auth_type: :api_key,
|
|
320
|
+
access_token: credential[:api_key],
|
|
321
|
+
token_type: 'ApiKey'
|
|
322
|
+
)
|
|
323
|
+
when :http_bearer
|
|
324
|
+
# Create a simple exchanged credential for Bearer token
|
|
325
|
+
Legate::Auth::ExchangedCredential.new(
|
|
326
|
+
auth_type: :http_bearer,
|
|
327
|
+
access_token: credential[:bearer_token],
|
|
328
|
+
token_type: 'Bearer'
|
|
329
|
+
)
|
|
330
|
+
else
|
|
331
|
+
# Other types like OAuth2 require a more complex flow
|
|
332
|
+
# and cannot be handled directly here
|
|
333
|
+
nil
|
|
334
|
+
end
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# Trigger a callback for the given event
|
|
338
|
+
# @param event [Symbol] The event that occurred
|
|
339
|
+
# @param token [Legate::Auth::ExchangedCredential, nil] The token involved in the event
|
|
340
|
+
# @param scheme [Legate::Auth::Scheme, nil] The authentication scheme
|
|
341
|
+
# @param credential [Legate::Auth::Credential, nil] The credential
|
|
342
|
+
# @param extras [Hash] Extra information to pass to the callback
|
|
343
|
+
def trigger_callback(event, token, scheme, credential, extras = {})
|
|
344
|
+
return unless @callbacks.key?(event)
|
|
345
|
+
|
|
346
|
+
@callbacks[event].each do |callback|
|
|
347
|
+
# Create a hash with all the data
|
|
348
|
+
data = {
|
|
349
|
+
event: event,
|
|
350
|
+
token: token,
|
|
351
|
+
scheme: scheme,
|
|
352
|
+
credential: credential
|
|
353
|
+
}.merge(extras)
|
|
354
|
+
|
|
355
|
+
callback.call(data)
|
|
356
|
+
rescue StandardError => e
|
|
357
|
+
Legate.logger.error("Error in #{event} callback: #{e.message}")
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# File: lib/legate/auth/token_store.rb
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
require_relative 'exchanged_credential'
|
|
5
|
+
|
|
6
|
+
module Legate
|
|
7
|
+
module Auth
|
|
8
|
+
# Provides a token store for caching authentication tokens
|
|
9
|
+
# This class wraps a session service and provides methods
|
|
10
|
+
# for storing, retrieving, and clearing tokens
|
|
11
|
+
class TokenStore
|
|
12
|
+
# Initialize a new token store
|
|
13
|
+
# @param session_service [Legate::SessionService::Base] The session service to use
|
|
14
|
+
def initialize(session_service)
|
|
15
|
+
@session_service = session_service
|
|
16
|
+
@scope = 'auth' # Scoped state namespace for authentication
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Store a token in the cache
|
|
20
|
+
# @param key [String] The cache key
|
|
21
|
+
# @param token [Legate::Auth::ExchangedCredential] The token to store
|
|
22
|
+
# @return [Boolean] True if the token was stored
|
|
23
|
+
def store(key, token)
|
|
24
|
+
return false unless token.is_a?(Legate::Auth::ExchangedCredential)
|
|
25
|
+
|
|
26
|
+
begin
|
|
27
|
+
# Serialize token to hash
|
|
28
|
+
token_data = token.to_h
|
|
29
|
+
|
|
30
|
+
# Store in scoped state
|
|
31
|
+
@session_service.save_scoped_state(@scope, key, token_data)
|
|
32
|
+
true
|
|
33
|
+
rescue StandardError => e
|
|
34
|
+
Legate.logger.error("Failed to store token: #{e.message}")
|
|
35
|
+
false
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Get a token from the cache
|
|
40
|
+
# @param key [String] The cache key
|
|
41
|
+
# @return [Legate::Auth::ExchangedCredential, nil] The token or nil if not found or expired
|
|
42
|
+
def get(key)
|
|
43
|
+
# Retrieve from scoped state
|
|
44
|
+
token_data = @session_service.load_scoped_state(@scope, key)
|
|
45
|
+
return nil unless token_data
|
|
46
|
+
|
|
47
|
+
# Deserialize to token object
|
|
48
|
+
token = Legate::Auth::ExchangedCredential.from_h(token_data)
|
|
49
|
+
|
|
50
|
+
# Check expiration
|
|
51
|
+
if token.expired?
|
|
52
|
+
Legate.logger.debug("Retrieved expired token from cache (key: #{key})")
|
|
53
|
+
# Clear expired token
|
|
54
|
+
clear(key)
|
|
55
|
+
return nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
token
|
|
59
|
+
rescue StandardError => e
|
|
60
|
+
Legate.logger.error("Failed to retrieve token: #{e.message}")
|
|
61
|
+
nil
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Clear a token from the cache
|
|
65
|
+
# @param key [String] The cache key to clear
|
|
66
|
+
# @return [Boolean] True if the token was cleared
|
|
67
|
+
def clear(key)
|
|
68
|
+
@session_service.clear_scoped_state(@scope, key)
|
|
69
|
+
true
|
|
70
|
+
rescue StandardError => e
|
|
71
|
+
Legate.logger.error("Failed to clear token: #{e.message}")
|
|
72
|
+
false
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Clear all tokens from the cache
|
|
76
|
+
# @return [Boolean] True if all tokens were cleared
|
|
77
|
+
def clear_all
|
|
78
|
+
@session_service.clear_scoped_state(@scope, '*')
|
|
79
|
+
true
|
|
80
|
+
rescue StandardError => e
|
|
81
|
+
Legate.logger.error("Failed to clear all tokens: #{e.message}")
|
|
82
|
+
false
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'runner'
|
|
4
|
+
require_relative 'token_manager'
|
|
5
|
+
require_relative 'token_store'
|
|
6
|
+
|
|
7
|
+
module Legate
|
|
8
|
+
module Auth
|
|
9
|
+
# Extension for Legate::ToolContext that adds fiber-based authentication support
|
|
10
|
+
# This module is meant to be included in the Legate::ToolContext class to add
|
|
11
|
+
# authentication-related methods for tools.
|
|
12
|
+
module ToolContextExtension
|
|
13
|
+
# Get or create an authentication runner for this context
|
|
14
|
+
# @return [Legate::Auth::Runner] The authentication runner
|
|
15
|
+
def auth_runner
|
|
16
|
+
@auth_runner ||= begin
|
|
17
|
+
# Create the token store
|
|
18
|
+
token_store = get_token_store
|
|
19
|
+
|
|
20
|
+
# Create a token manager
|
|
21
|
+
token_manager = Legate::Auth::TokenManager.new(token_store)
|
|
22
|
+
|
|
23
|
+
# Create the runner
|
|
24
|
+
Legate::Auth::Runner.new(
|
|
25
|
+
session_service: session_service,
|
|
26
|
+
token_store: token_store,
|
|
27
|
+
token_manager: token_manager
|
|
28
|
+
)
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Get a token store for this context
|
|
33
|
+
# @return [Legate::Auth::TokenStore] The token store
|
|
34
|
+
def get_token_store
|
|
35
|
+
@token_store ||= if session_service.respond_to?(:scoped_state_container)
|
|
36
|
+
Legate::Auth::TokenStore.new(session_service)
|
|
37
|
+
elsif defined?(Legate::Auth) && Legate::Auth.respond_to?(:token_store)
|
|
38
|
+
Legate::Auth.token_store
|
|
39
|
+
else
|
|
40
|
+
Legate::Auth::TokenStore.new
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Run a block with authentication support
|
|
45
|
+
# @param handler [Proc, nil] Optional handler for authentication requests
|
|
46
|
+
# @yield The block to run
|
|
47
|
+
# @return [Object] The result of the block
|
|
48
|
+
def with_authentication(&block)
|
|
49
|
+
raise ArgumentError, 'Block is required' unless block_given?
|
|
50
|
+
|
|
51
|
+
# Get or create the authentication runner
|
|
52
|
+
runner = auth_runner
|
|
53
|
+
|
|
54
|
+
# Run the block with authentication support
|
|
55
|
+
runner.run(block, self) do |auth_request|
|
|
56
|
+
# Here we return nil to indicate that the auth request should be yielded
|
|
57
|
+
# to the tool's caller for handling. In a real implementation, this could
|
|
58
|
+
# handle authentication UI or delegate to another component.
|
|
59
|
+
nil
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Start an authentication session
|
|
64
|
+
# @param scheme [Legate::Auth::Scheme] The authentication scheme to use
|
|
65
|
+
# @param credential [Legate::Auth::Credential] The credential to use
|
|
66
|
+
# @param options [Hash] Additional options for the authentication session
|
|
67
|
+
# @return [Legate::Auth::ExchangedCredential] The authenticated credential
|
|
68
|
+
def auth_session(scheme, credential, **options)
|
|
69
|
+
# This method will be dynamically replaced by the auth_runner when
|
|
70
|
+
# running in a fiber context. This implementation is just for fallback
|
|
71
|
+
# when not running in a fiber.
|
|
72
|
+
raise NotImplementedError, 'Authentication session not available outside of with_authentication block'
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Handle an authentication response (for tools that handle responses)
|
|
76
|
+
# @param request_id [String] The request ID
|
|
77
|
+
# @param response [Hash] The response
|
|
78
|
+
# @return [Hash] The result of handling the response
|
|
79
|
+
def handle_auth_response(request_id, response)
|
|
80
|
+
runner = auth_runner
|
|
81
|
+
runner.handle_auth_response(request_id, response)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
# Cancel an authentication flow (for tools that handle responses)
|
|
85
|
+
# @param request_id [String] The request ID
|
|
86
|
+
# @param reason [String, nil] Optional reason for cancellation
|
|
87
|
+
# @return [Boolean] True if the flow was successfully cancelled
|
|
88
|
+
def cancel_auth_flow(request_id, reason = nil)
|
|
89
|
+
runner = auth_runner
|
|
90
|
+
runner.cancel_auth_flow(request_id, reason)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Extend the ToolContext class if it's already defined
|
|
97
|
+
Legate::ToolContext.include(Legate::Auth::ToolContextExtension) if defined?(Legate::ToolContext)
|