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,202 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Test with httpbin.org which is more reliable than OpenWeatherMap API
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# ruby examples/advanced/auth/test_with_httpbin.rb
|
|
8
|
+
|
|
9
|
+
require 'bundler/setup'
|
|
10
|
+
require 'legate'
|
|
11
|
+
require 'legate/auth'
|
|
12
|
+
require 'json'
|
|
13
|
+
require 'excon'
|
|
14
|
+
require 'legate/session_service/in_memory'
|
|
15
|
+
|
|
16
|
+
# Enable debug mode
|
|
17
|
+
ENV['DEBUG'] = 'true'
|
|
18
|
+
|
|
19
|
+
puts 'Testing Legate::Auth::ExconMiddleware with httpbin.org'
|
|
20
|
+
puts '--------------------------------------------'
|
|
21
|
+
|
|
22
|
+
# Create session service and token store
|
|
23
|
+
session_service = Legate::SessionService::InMemory.new
|
|
24
|
+
token_store = Legate::Auth::TokenStore.new(session_service)
|
|
25
|
+
|
|
26
|
+
# Test API Key
|
|
27
|
+
API_KEY = 'test-api-key-123'
|
|
28
|
+
|
|
29
|
+
# Create the ApiKey scheme and credential
|
|
30
|
+
api_key_scheme = Legate::Auth::Schemes::ApiKey.new
|
|
31
|
+
api_key_credential = Legate::Auth::Credential.new(
|
|
32
|
+
auth_type: :api_key,
|
|
33
|
+
api_key: API_KEY,
|
|
34
|
+
location: 'query',
|
|
35
|
+
name: 'apikey'
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
puts "\nTest 1: Direct API call with Excon"
|
|
39
|
+
puts '-------------------------------'
|
|
40
|
+
|
|
41
|
+
begin
|
|
42
|
+
# Make a direct Excon request
|
|
43
|
+
url = "https://httpbin.org/get?test=value&apikey=#{API_KEY}"
|
|
44
|
+
|
|
45
|
+
puts "Making direct request to: #{url}"
|
|
46
|
+
|
|
47
|
+
# Create the connection with normal timeouts
|
|
48
|
+
response = Excon.get(url,
|
|
49
|
+
connect_timeout: 10,
|
|
50
|
+
read_timeout: 10,
|
|
51
|
+
write_timeout: 10)
|
|
52
|
+
|
|
53
|
+
puts "Response Status: #{response.status}"
|
|
54
|
+
|
|
55
|
+
if response.status == 200
|
|
56
|
+
data = JSON.parse(response.body)
|
|
57
|
+
puts "Data received: #{data['args'].inspect}"
|
|
58
|
+
else
|
|
59
|
+
puts "Error: #{response.status} - #{response.body}"
|
|
60
|
+
end
|
|
61
|
+
rescue StandardError => e
|
|
62
|
+
puts "Request Error: #{e.message}"
|
|
63
|
+
puts e.backtrace.join("\n") if ENV['DEBUG']
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
puts "\nTest 2: Fixed Legate::Auth::ExconMiddleware"
|
|
67
|
+
puts '------------------------------------'
|
|
68
|
+
|
|
69
|
+
begin
|
|
70
|
+
# Create our middleware instance directly
|
|
71
|
+
middleware = Legate::Auth::ExconMiddleware.new(
|
|
72
|
+
nil,
|
|
73
|
+
scheme: api_key_scheme,
|
|
74
|
+
credential: api_key_credential,
|
|
75
|
+
token_store: token_store
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Create a connection and add our middleware directly
|
|
79
|
+
connection = Excon.new('https://httpbin.org',
|
|
80
|
+
connect_timeout: 10,
|
|
81
|
+
read_timeout: 10,
|
|
82
|
+
write_timeout: 10)
|
|
83
|
+
|
|
84
|
+
# Get the default middleware stack
|
|
85
|
+
default_middlewares = connection.data[:middlewares].dup
|
|
86
|
+
|
|
87
|
+
# Append our middleware to the stack
|
|
88
|
+
connection.data[:middlewares] = default_middlewares + [Legate::Auth::ExconMiddleware]
|
|
89
|
+
|
|
90
|
+
# Store our middleware instance in the connection
|
|
91
|
+
connection.data[:auth_middleware] = middleware
|
|
92
|
+
|
|
93
|
+
puts 'Connection created with middleware'
|
|
94
|
+
puts 'Making request with Legate::Auth::ExconMiddleware...'
|
|
95
|
+
|
|
96
|
+
# Make the request
|
|
97
|
+
response = connection.request(
|
|
98
|
+
method: :get,
|
|
99
|
+
path: '/get',
|
|
100
|
+
query: {
|
|
101
|
+
test: 'value'
|
|
102
|
+
}
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
puts "Response Status: #{response.status}"
|
|
106
|
+
|
|
107
|
+
if response.status == 200
|
|
108
|
+
data = JSON.parse(response.body)
|
|
109
|
+
puts "Data received: #{data['args'].inspect}"
|
|
110
|
+
else
|
|
111
|
+
puts "Error: #{response.status} - #{response.body}"
|
|
112
|
+
end
|
|
113
|
+
rescue StandardError => e
|
|
114
|
+
puts "Request Error: #{e.message}"
|
|
115
|
+
puts e.backtrace.join("\n") if ENV['DEBUG']
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
puts "\nTest 3: Using HttpClientUtils.create_connection"
|
|
119
|
+
puts '-------------------------------------------'
|
|
120
|
+
|
|
121
|
+
begin
|
|
122
|
+
# Use the Legate::Auth::HttpClientUtils.create_connection method
|
|
123
|
+
puts 'Creating connection using HttpClientUtils...'
|
|
124
|
+
|
|
125
|
+
connection = Legate::Auth::HttpClientUtils.create_connection(
|
|
126
|
+
'https://httpbin.org',
|
|
127
|
+
scheme: api_key_scheme,
|
|
128
|
+
credential: api_key_credential,
|
|
129
|
+
token_store: token_store,
|
|
130
|
+
connect_timeout: 10,
|
|
131
|
+
read_timeout: 10,
|
|
132
|
+
write_timeout: 10
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
puts 'Connection created using factory method'
|
|
136
|
+
puts 'Making request with connection from HttpClientUtils...'
|
|
137
|
+
|
|
138
|
+
# Make the request
|
|
139
|
+
response = connection.request(
|
|
140
|
+
method: :get,
|
|
141
|
+
path: '/get',
|
|
142
|
+
query: {
|
|
143
|
+
test: 'utils'
|
|
144
|
+
}
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
puts "Response Status: #{response.status}"
|
|
148
|
+
|
|
149
|
+
if response.status == 200
|
|
150
|
+
data = JSON.parse(response.body)
|
|
151
|
+
puts "Data received: #{data['args'].inspect}"
|
|
152
|
+
else
|
|
153
|
+
puts "Error: #{response.status} - #{response.body}"
|
|
154
|
+
end
|
|
155
|
+
rescue StandardError => e
|
|
156
|
+
puts "Request Error: #{e.message}"
|
|
157
|
+
puts e.backtrace.join("\n") if ENV['DEBUG']
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
puts "\nTest 4: Using convenience method for API Key"
|
|
161
|
+
puts '-----------------------------------------'
|
|
162
|
+
|
|
163
|
+
begin
|
|
164
|
+
# Use the convenience method
|
|
165
|
+
puts 'Creating connection with convenience method...'
|
|
166
|
+
|
|
167
|
+
connection = Legate::Auth.create_api_key_connection(
|
|
168
|
+
'https://httpbin.org',
|
|
169
|
+
api_key: API_KEY,
|
|
170
|
+
location: :query,
|
|
171
|
+
name: 'apikey',
|
|
172
|
+
token_store: token_store,
|
|
173
|
+
connect_timeout: 10,
|
|
174
|
+
read_timeout: 10,
|
|
175
|
+
write_timeout: 10
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
puts 'Connection created with convenience method'
|
|
179
|
+
puts 'Making request with middleware...'
|
|
180
|
+
|
|
181
|
+
response = connection.request(
|
|
182
|
+
method: :get,
|
|
183
|
+
path: '/get',
|
|
184
|
+
query: {
|
|
185
|
+
test: 'convenience'
|
|
186
|
+
}
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
puts "Response Status: #{response.status}"
|
|
190
|
+
|
|
191
|
+
if response.status == 200
|
|
192
|
+
data = JSON.parse(response.body)
|
|
193
|
+
puts "Data received: #{data['args'].inspect}"
|
|
194
|
+
else
|
|
195
|
+
puts "Error: #{response.status} - #{response.body}"
|
|
196
|
+
end
|
|
197
|
+
rescue StandardError => e
|
|
198
|
+
puts "Request Error: #{e.message}"
|
|
199
|
+
puts e.backtrace.join("\n") if ENV['DEBUG']
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
puts "\nTest complete."
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Token Lifecycle Management Example
|
|
5
|
+
#
|
|
6
|
+
# This example demonstrates comprehensive token lifecycle management including:
|
|
7
|
+
# - Token acquisition and storage
|
|
8
|
+
# - Automatic token refresh on expiration
|
|
9
|
+
# - Token invalidation and error handling
|
|
10
|
+
# - Manual token management operations
|
|
11
|
+
# - Integration with different authentication schemes
|
|
12
|
+
#
|
|
13
|
+
# Usage:
|
|
14
|
+
# ruby examples/advanced/auth/token_lifecycle_example.rb [--scheme oauth2|service_account] [--demo-mode]
|
|
15
|
+
|
|
16
|
+
require 'bundler/setup'
|
|
17
|
+
require 'legate'
|
|
18
|
+
require 'legate/auth'
|
|
19
|
+
require 'legate/auth/token_manager'
|
|
20
|
+
require 'legate/auth/token_store'
|
|
21
|
+
require 'optparse'
|
|
22
|
+
require 'json'
|
|
23
|
+
require 'time'
|
|
24
|
+
|
|
25
|
+
# Helper method to get auth-related keys from the session service
|
|
26
|
+
def get_auth_keys(session_service)
|
|
27
|
+
if session_service.respond_to?(:scoped_states)
|
|
28
|
+
# For InMemory session service, check the scoped_states directly
|
|
29
|
+
session_service.scoped_states.keys.select { |key| key.start_with?('auth:') }
|
|
30
|
+
|
|
31
|
+
elsif session_service.respond_to?(:keys)
|
|
32
|
+
# For Redis-based session service
|
|
33
|
+
session_service.keys('auth:*')
|
|
34
|
+
else
|
|
35
|
+
[]
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Parse command line options
|
|
40
|
+
options = {
|
|
41
|
+
scheme: 'oauth2',
|
|
42
|
+
demo_mode: false,
|
|
43
|
+
verbose: false
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
OptionParser.new do |opts|
|
|
47
|
+
opts.banner = "Usage: ruby #{__FILE__} [options]"
|
|
48
|
+
|
|
49
|
+
opts.on('--scheme SCHEME', %w[oauth2 service_account], 'Authentication scheme to demonstrate (oauth2, service_account)') do |scheme|
|
|
50
|
+
options[:scheme] = scheme
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
opts.on('--demo-mode', 'Run in demo mode with simulated tokens') do
|
|
54
|
+
options[:demo_mode] = true
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
opts.on('--verbose', 'Enable verbose output') do
|
|
58
|
+
options[:verbose] = true
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
opts.on('--help', 'Show this help') do
|
|
62
|
+
puts opts
|
|
63
|
+
exit
|
|
64
|
+
end
|
|
65
|
+
end.parse!
|
|
66
|
+
|
|
67
|
+
puts '=== Token Lifecycle Management Example ==='
|
|
68
|
+
puts "Scheme: #{options[:scheme]}"
|
|
69
|
+
puts "Demo Mode: #{options[:demo_mode] ? 'enabled' : 'disabled'}"
|
|
70
|
+
puts
|
|
71
|
+
|
|
72
|
+
# Setup session service for token storage
|
|
73
|
+
session_service = Legate::SessionService::InMemory.new
|
|
74
|
+
puts '✓ Session service initialized'
|
|
75
|
+
|
|
76
|
+
# Create token store for persistent token management
|
|
77
|
+
token_store = Legate::Auth::TokenStore.new(session_service)
|
|
78
|
+
puts '✓ Token store created'
|
|
79
|
+
|
|
80
|
+
# Create token manager for automatic lifecycle management
|
|
81
|
+
token_manager = Legate::Auth::TokenManager.new(token_store)
|
|
82
|
+
puts '✓ Token manager initialized'
|
|
83
|
+
|
|
84
|
+
# Configure callbacks for token lifecycle events
|
|
85
|
+
token_manager.on(:before_expiry) do |event|
|
|
86
|
+
puts "⏰ Token approaching expiration: #{event[:token]&.access_token&.[](0..15)}..."
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
token_manager.on(:refresh_success) do |event|
|
|
90
|
+
expires_in = event[:token]&.expires_at ? (event[:token].expires_at - Time.now).to_i : 0
|
|
91
|
+
puts "🔄 Token refreshed successfully: #{event[:token]&.access_token&.[](0..15)}... (expires in #{expires_in} seconds)"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
token_manager.on(:refresh_failure) do |event|
|
|
95
|
+
puts "⚠️ Token refresh failed: #{event[:error]&.message || 'Unknown error'}"
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
token_manager.on(:invalidated) do |event|
|
|
99
|
+
puts "❌ Token invalidated: #{event[:cache_key]}"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
puts '✓ Token lifecycle callbacks configured'
|
|
103
|
+
|
|
104
|
+
# Helper method to create credentials and schemes
|
|
105
|
+
def create_auth_components(scheme_type, demo_mode: false)
|
|
106
|
+
case scheme_type
|
|
107
|
+
when 'oauth2'
|
|
108
|
+
scheme = if demo_mode
|
|
109
|
+
# Create a mock OAuth2 scheme for demo
|
|
110
|
+
Legate::Auth::Schemes::OAuth2.new(
|
|
111
|
+
authorization_url: 'https://example.com/oauth/authorize',
|
|
112
|
+
token_url: 'https://example.com/oauth/token',
|
|
113
|
+
scopes: %w[read write]
|
|
114
|
+
)
|
|
115
|
+
else
|
|
116
|
+
Legate::Auth::Schemes::OAuth2.new(
|
|
117
|
+
authorization_url: ENV['OAUTH_AUTH_URL'] || 'https://accounts.google.com/o/oauth2/auth',
|
|
118
|
+
token_url: ENV['OAUTH_TOKEN_URL'] || 'https://oauth2.googleapis.com/token',
|
|
119
|
+
scopes: %w[email profile]
|
|
120
|
+
)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
credential = Legate::Auth::Credential.new(
|
|
124
|
+
auth_type: :oauth2,
|
|
125
|
+
client_id: ENV['OAUTH_CLIENT_ID'] || 'demo-client-id',
|
|
126
|
+
client_secret: ENV['OAUTH_CLIENT_SECRET'] || 'demo-client-secret'
|
|
127
|
+
)
|
|
128
|
+
|
|
129
|
+
[scheme, credential]
|
|
130
|
+
|
|
131
|
+
when 'service_account'
|
|
132
|
+
# Set test environment for demo mode to skip full validation
|
|
133
|
+
ENV['RSPEC_ENV'] = 'test' if demo_mode
|
|
134
|
+
|
|
135
|
+
scheme = Legate::Auth::Schemes::GoogleServiceAccount.new(
|
|
136
|
+
scopes: ['https://www.googleapis.com/auth/cloud-platform']
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
if demo_mode
|
|
140
|
+
# Create demo service account credential
|
|
141
|
+
demo_key = {
|
|
142
|
+
'type' => 'service_account',
|
|
143
|
+
'project_id' => 'demo-project',
|
|
144
|
+
'private_key_id' => 'demo-key-id',
|
|
145
|
+
'private_key' => "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC...\n-----END PRIVATE KEY-----\n",
|
|
146
|
+
'client_email' => 'demo@demo-project.iam.gserviceaccount.com',
|
|
147
|
+
'client_id' => '123456789',
|
|
148
|
+
'auth_uri' => 'https://accounts.google.com/o/oauth2/auth',
|
|
149
|
+
'token_uri' => 'https://oauth2.googleapis.com/token'
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
credential = Legate::Auth::Credential.new(
|
|
153
|
+
auth_type: :google_service_account,
|
|
154
|
+
service_account_key: demo_key.to_json,
|
|
155
|
+
client_email: demo_key['client_email']
|
|
156
|
+
)
|
|
157
|
+
else
|
|
158
|
+
credential = Legate::Auth::Credential.new(
|
|
159
|
+
auth_type: :google_service_account,
|
|
160
|
+
service_account_key: ENV['SERVICE_ACCOUNT_KEY'] || File.read(ENV['SERVICE_ACCOUNT_KEY_FILE'])
|
|
161
|
+
)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
[scheme, credential]
|
|
165
|
+
|
|
166
|
+
else
|
|
167
|
+
raise ArgumentError, "Unsupported scheme: #{scheme_type}"
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# Helper method to create a demo token for testing
|
|
172
|
+
def create_demo_token(scheme_type)
|
|
173
|
+
case scheme_type
|
|
174
|
+
when 'oauth2'
|
|
175
|
+
Legate::Auth::ExchangedCredential.new(
|
|
176
|
+
auth_type: :oauth2,
|
|
177
|
+
access_token: 'demo_access_token_' + SecureRandom.hex(8),
|
|
178
|
+
refresh_token: 'demo_refresh_token_' + SecureRandom.hex(8),
|
|
179
|
+
token_type: 'Bearer',
|
|
180
|
+
expires_at: Time.now + 30, # Expires in 30 seconds for demo
|
|
181
|
+
scope: 'email profile'
|
|
182
|
+
)
|
|
183
|
+
when 'service_account'
|
|
184
|
+
Legate::Auth::ExchangedCredential.new(
|
|
185
|
+
auth_type: :google_service_account,
|
|
186
|
+
access_token: 'demo_sa_token_' + SecureRandom.hex(8),
|
|
187
|
+
token_type: 'Bearer',
|
|
188
|
+
expires_at: Time.now + 45, # Expires in 45 seconds for demo
|
|
189
|
+
scope: 'https://www.googleapis.com/auth/cloud-platform'
|
|
190
|
+
)
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# Create authentication components
|
|
195
|
+
begin
|
|
196
|
+
scheme, credential = create_auth_components(options[:scheme], demo_mode: options[:demo_mode])
|
|
197
|
+
puts '✓ Authentication scheme and credential created'
|
|
198
|
+
rescue StandardError => e
|
|
199
|
+
puts "❌ Failed to create authentication components: #{e.message}"
|
|
200
|
+
puts "\nTip: Use --demo-mode to run with simulated credentials" unless options[:demo_mode]
|
|
201
|
+
exit 1
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
# Token lifecycle demonstration
|
|
205
|
+
puts "\n=== Token Lifecycle Demonstration ==="
|
|
206
|
+
|
|
207
|
+
token_key = "#{options[:scheme]}_demo_token"
|
|
208
|
+
|
|
209
|
+
# 1. Initial token acquisition
|
|
210
|
+
puts "\n1. Initial Token Acquisition"
|
|
211
|
+
puts '─' * 40
|
|
212
|
+
|
|
213
|
+
if options[:demo_mode]
|
|
214
|
+
# In demo mode, simulate getting a token
|
|
215
|
+
demo_token = create_demo_token(options[:scheme])
|
|
216
|
+
token_store.store(token_key, demo_token)
|
|
217
|
+
current_token = demo_token
|
|
218
|
+
puts '✓ Demo token created and stored'
|
|
219
|
+
else
|
|
220
|
+
# In real mode, attempt to get a token through the token manager
|
|
221
|
+
puts 'Attempting to acquire token through token manager...'
|
|
222
|
+
current_token = token_manager.get_token(scheme, credential)
|
|
223
|
+
|
|
224
|
+
if current_token
|
|
225
|
+
puts '✓ Token acquired successfully'
|
|
226
|
+
else
|
|
227
|
+
puts '⚠️ Token acquisition failed (this is expected for interactive flows in CLI)'
|
|
228
|
+
puts 'Creating a demo token for lifecycle demonstration...'
|
|
229
|
+
current_token = create_demo_token(options[:scheme])
|
|
230
|
+
token_store.store(token_key, current_token)
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# Display token information
|
|
235
|
+
if current_token
|
|
236
|
+
puts "\nToken Information:"
|
|
237
|
+
puts " Type: #{current_token.token_type}"
|
|
238
|
+
puts " Access Token: #{current_token.access_token[0..15]}..."
|
|
239
|
+
puts " Expires At: #{current_token.expires_at}"
|
|
240
|
+
puts " Expires In: #{(current_token.expires_at - Time.now).to_i} seconds"
|
|
241
|
+
puts " Scope: #{current_token[:scope]}" if current_token[:scope]
|
|
242
|
+
puts " Has Refresh Token: #{current_token.refresh_token ? 'Yes' : 'No'}"
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
# 2. Token retrieval from storage
|
|
246
|
+
puts "\n2. Token Retrieval from Storage"
|
|
247
|
+
puts '─' * 40
|
|
248
|
+
|
|
249
|
+
retrieved_token = token_store.get(token_key)
|
|
250
|
+
if retrieved_token
|
|
251
|
+
puts '✓ Token successfully retrieved from storage'
|
|
252
|
+
puts " Retrieved token matches stored token: #{current_token.access_token == retrieved_token.access_token}"
|
|
253
|
+
else
|
|
254
|
+
puts '❌ Failed to retrieve token from storage'
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
# 3. Token expiration checking
|
|
258
|
+
puts "\n3. Token Expiration Checking"
|
|
259
|
+
puts '─' * 40
|
|
260
|
+
|
|
261
|
+
expires_in_seconds = (current_token.expires_at - Time.now).to_i
|
|
262
|
+
|
|
263
|
+
puts "Current time: #{Time.now}"
|
|
264
|
+
puts "Token expires at: #{current_token.expires_at}"
|
|
265
|
+
puts "Token expired?: #{current_token.expired?}"
|
|
266
|
+
puts "Token expires in: #{expires_in_seconds} seconds"
|
|
267
|
+
|
|
268
|
+
if expires_in_seconds > 0
|
|
269
|
+
puts 'Token is currently valid'
|
|
270
|
+
else
|
|
271
|
+
puts 'Token has already expired'
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# 4. Automatic token refresh demonstration
|
|
275
|
+
puts "\n4. Automatic Token Refresh"
|
|
276
|
+
puts '─' * 40
|
|
277
|
+
|
|
278
|
+
if current_token.refresh_token && !options[:demo_mode]
|
|
279
|
+
puts 'Token has refresh token - attempting refresh...'
|
|
280
|
+
|
|
281
|
+
begin
|
|
282
|
+
refreshed_token = token_manager.refresh_token(scheme, credential, current_token)
|
|
283
|
+
if refreshed_token
|
|
284
|
+
puts '✓ Token refreshed successfully'
|
|
285
|
+
puts " New access token: #{refreshed_token.access_token[0..15]}..."
|
|
286
|
+
puts " New expiry: #{refreshed_token.expires_at}"
|
|
287
|
+
current_token = refreshed_token
|
|
288
|
+
else
|
|
289
|
+
puts '⚠️ Token refresh returned nil'
|
|
290
|
+
end
|
|
291
|
+
rescue StandardError => e
|
|
292
|
+
puts "❌ Token refresh failed: #{e.message}"
|
|
293
|
+
end
|
|
294
|
+
else
|
|
295
|
+
puts 'Token refresh not available (no refresh token or demo mode)'
|
|
296
|
+
|
|
297
|
+
if options[:demo_mode]
|
|
298
|
+
puts 'Simulating token refresh in demo mode...'
|
|
299
|
+
refreshed_demo = create_demo_token(options[:scheme])
|
|
300
|
+
token_store.store(token_key, refreshed_demo)
|
|
301
|
+
puts "✓ Demo token 'refreshed' (new token created)"
|
|
302
|
+
current_token = refreshed_demo
|
|
303
|
+
end
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
# 5. Waiting for expiration (demo)
|
|
307
|
+
current_expires_in = (current_token.expires_at - Time.now).to_i
|
|
308
|
+
if options[:demo_mode] && current_expires_in > 0 && current_expires_in < 60
|
|
309
|
+
puts "\n5. Waiting for Token Expiration (Demo)"
|
|
310
|
+
puts '─' * 40
|
|
311
|
+
|
|
312
|
+
puts "Token expires in #{current_expires_in} seconds"
|
|
313
|
+
puts 'Waiting for expiration... (press Ctrl+C to skip)'
|
|
314
|
+
|
|
315
|
+
begin
|
|
316
|
+
sleep_time = [current_expires_in + 1, 5].min # Max 5 seconds wait
|
|
317
|
+
sleep(sleep_time)
|
|
318
|
+
|
|
319
|
+
puts 'Checking token status after wait...'
|
|
320
|
+
puts "Token expired?: #{current_token.expired?}"
|
|
321
|
+
|
|
322
|
+
# Demonstrate automatic refresh on next access
|
|
323
|
+
puts 'Attempting to get token (should trigger refresh if expired)...'
|
|
324
|
+
fresh_token = token_manager.get_token(scheme, credential, force_refresh: current_token.expired?)
|
|
325
|
+
|
|
326
|
+
puts '✓ Automatic refresh triggered on expired token access' if fresh_token && fresh_token.access_token != current_token.access_token
|
|
327
|
+
rescue Interrupt
|
|
328
|
+
puts "\n⏭️ Skipped expiration wait"
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
# 6. Manual token operations
|
|
333
|
+
puts "\n6. Manual Token Operations"
|
|
334
|
+
puts '─' * 40
|
|
335
|
+
|
|
336
|
+
# Force refresh
|
|
337
|
+
puts 'Force refreshing token...'
|
|
338
|
+
if options[:demo_mode]
|
|
339
|
+
new_demo_token = create_demo_token(options[:scheme])
|
|
340
|
+
token_store.store(token_key, new_demo_token)
|
|
341
|
+
puts '✓ Demo token force refreshed'
|
|
342
|
+
else
|
|
343
|
+
force_refreshed = token_manager.get_token(scheme, credential, force_refresh: true)
|
|
344
|
+
if force_refreshed
|
|
345
|
+
puts '✓ Token force refreshed'
|
|
346
|
+
else
|
|
347
|
+
puts '⚠️ Force refresh failed'
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
# Check for multiple tokens
|
|
352
|
+
puts "\nChecking all stored tokens..."
|
|
353
|
+
all_tokens = get_auth_keys(session_service)
|
|
354
|
+
puts "Found #{all_tokens.length} authentication-related keys in storage:"
|
|
355
|
+
all_tokens.each { |key| puts " - #{key}" }
|
|
356
|
+
|
|
357
|
+
# 7. Token invalidation
|
|
358
|
+
puts "\n7. Token Invalidation"
|
|
359
|
+
puts '─' * 40
|
|
360
|
+
|
|
361
|
+
puts 'Invalidating token...'
|
|
362
|
+
# Generate the proper cache key for the token manager
|
|
363
|
+
require_relative '../../../lib/legate/auth/tool_integration'
|
|
364
|
+
cache_key = Legate::Auth::ToolIntegration.generate_cache_key(scheme, credential)
|
|
365
|
+
token_manager.invalidate_token(cache_key)
|
|
366
|
+
|
|
367
|
+
# Verify invalidation
|
|
368
|
+
invalidated_token = token_store.get(token_key)
|
|
369
|
+
if invalidated_token.nil?
|
|
370
|
+
puts '✓ Token successfully invalidated and removed from storage'
|
|
371
|
+
else
|
|
372
|
+
puts '⚠️ Token still exists in storage after invalidation'
|
|
373
|
+
end
|
|
374
|
+
|
|
375
|
+
# 8. Error handling demonstration
|
|
376
|
+
puts "\n8. Error Handling"
|
|
377
|
+
puts '─' * 40
|
|
378
|
+
|
|
379
|
+
puts 'Attempting to get invalidated token...'
|
|
380
|
+
result = token_manager.get_token(scheme, credential)
|
|
381
|
+
if result.nil?
|
|
382
|
+
puts '✓ Correctly returned nil for invalidated token'
|
|
383
|
+
else
|
|
384
|
+
puts "⚠️ Unexpectedly returned a token: #{result.access_token[0..15]}..."
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
# Try token operations on non-existent token
|
|
388
|
+
puts 'Attempting to refresh non-existent token...'
|
|
389
|
+
begin
|
|
390
|
+
fake_token = create_demo_token(options[:scheme])
|
|
391
|
+
fake_token.instance_variable_set(:@access_token, 'invalid_token')
|
|
392
|
+
refresh_result = token_manager.refresh_token(scheme, credential, fake_token)
|
|
393
|
+
if refresh_result
|
|
394
|
+
puts '⚠️ Unexpectedly succeeded refreshing invalid token'
|
|
395
|
+
else
|
|
396
|
+
puts '✓ Correctly failed to refresh invalid token'
|
|
397
|
+
end
|
|
398
|
+
rescue StandardError => e
|
|
399
|
+
puts "✓ Correctly raised error for invalid token refresh: #{e.class}"
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
# 9. Cleanup demonstration
|
|
403
|
+
puts "\n9. Cleanup"
|
|
404
|
+
puts '─' * 40
|
|
405
|
+
|
|
406
|
+
puts 'Clearing all tokens...'
|
|
407
|
+
token_store.clear_all
|
|
408
|
+
remaining_tokens = get_auth_keys(session_service)
|
|
409
|
+
puts "Remaining auth tokens after cleanup: #{remaining_tokens.length}"
|
|
410
|
+
|
|
411
|
+
if remaining_tokens.empty?
|
|
412
|
+
puts '✓ All tokens successfully cleared'
|
|
413
|
+
else
|
|
414
|
+
puts "⚠️ Some tokens remain: #{remaining_tokens}"
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
puts "\n=== Token Lifecycle Demonstration Complete ==="
|
|
418
|
+
puts "\nKey concepts demonstrated:"
|
|
419
|
+
puts '• Token acquisition and storage'
|
|
420
|
+
puts '• Automatic expiration detection'
|
|
421
|
+
puts '• Token refresh mechanisms'
|
|
422
|
+
puts '• Manual token operations'
|
|
423
|
+
puts '• Error handling and recovery'
|
|
424
|
+
puts '• Token invalidation and cleanup'
|
|
425
|
+
puts '• Event-based lifecycle callbacks'
|
|
426
|
+
puts "\nThis example shows how the Legate authentication system handles"
|
|
427
|
+
puts 'the complete token lifecycle automatically, with manual override'
|
|
428
|
+
puts 'capabilities when needed.'
|