Class: A2A::Client::Auth::Interceptor
- Inherits:
-
Object
- Object
- A2A::Client::Auth::Interceptor
- Defined in:
- lib/a2a/client/auth/interceptor.rb
Instance Attribute Summary collapse
-
#auto_retry ⇒ Object
readonly
Returns the value of attribute auto_retry.
-
#strategy ⇒ Object
readonly
Returns the value of attribute strategy.
Class Method Summary collapse
-
.from_config(config) ⇒ Interceptor
Create interceptor from configuration.
-
.from_security_scheme(scheme, credentials) ⇒ Interceptor
Create interceptor from security scheme.
Instance Method Summary collapse
-
#apply_authentication(request) ⇒ Object
Apply authentication to a request.
-
#apply_config_authentication(request, config) ⇒ Object
private
Apply configuration-based authentication.
-
#authentication_error?(response) ⇒ Boolean
private
Check if response indicates authentication error.
-
#call(request, context, next_middleware) ⇒ Object
Middleware call method for Faraday.
-
#handle_auth_error_retry(request, context, next_middleware) ⇒ Object
private
Handle authentication error with retry.
-
#initialize(strategy, auto_retry: true) ⇒ Interceptor
constructor
Initialize authentication interceptor.
-
#refresh! ⇒ Boolean
Refresh authentication credentials.
-
#status ⇒ Hash
Get current authentication status.
-
#strategy_expires_at ⇒ Time?
private
Get strategy expiration time.
-
#strategy_valid? ⇒ Boolean
private
Check if the current strategy is valid.
-
#supports_refresh? ⇒ Boolean
Check if the strategy supports token refresh.
Constructor Details
#initialize(strategy, auto_retry: true) ⇒ Interceptor
Initialize authentication interceptor
25 26 27 28 29 |
# File 'lib/a2a/client/auth/interceptor.rb', line 25 def initialize(strategy, auto_retry: true) @strategy = strategy @auto_retry = auto_retry @retry_mutex = Mutex.new end |
Instance Attribute Details
#auto_retry ⇒ Object (readonly)
Returns the value of attribute auto_retry.
18 19 20 |
# File 'lib/a2a/client/auth/interceptor.rb', line 18 def auto_retry @auto_retry end |
#strategy ⇒ Object (readonly)
Returns the value of attribute strategy.
18 19 20 |
# File 'lib/a2a/client/auth/interceptor.rb', line 18 def strategy @strategy end |
Class Method Details
.from_config(config) ⇒ Interceptor
Create interceptor from configuration
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/a2a/client/auth/interceptor.rb', line 80 def self.from_config(config) strategy = case config["type"] || config[:type] when "oauth2" OAuth2.new( client_id: config["client_id"] || config[:client_id], client_secret: config["client_secret"] || config[:client_secret], token_url: config["token_url"] || config[:token_url], scope: config["scope"] || config[:scope] ) when "jwt" JWT.new( token: config["token"] || config[:token], secret: config["secret"] || config[:secret], algorithm: config["algorithm"] || config[:algorithm] || "HS256", payload: config["payload"] || config[:payload], headers: config["headers"] || config[:headers], expires_in: config["expires_in"] || config[:expires_in] ) when "api_key" ApiKey.new( key: config["key"] || config[:key], name: config["name"] || config[:name] || "X-API-Key", location: config["location"] || config[:location] || "header" ) else raise ArgumentError, "Unknown authentication type: #{config['type'] || config[:type]}" end new(strategy, auto_retry: config["auto_retry"] || config[:auto_retry] || true) end |
.from_security_scheme(scheme, credentials) ⇒ Interceptor
Create interceptor from security scheme
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
# File 'lib/a2a/client/auth/interceptor.rb', line 117 def self.from_security_scheme(scheme, credentials) strategy = case scheme["type"] when "oauth2" OAuth2.new( client_id: credentials["client_id"], client_secret: credentials["client_secret"], token_url: scheme["tokenUrl"], scope: credentials["scope"] ) when "http" case scheme["scheme"] when "bearer" JWT.new(token: credentials["token"]) when "basic" # Basic auth would be handled differently raise ArgumentError, "Basic auth not yet implemented" else raise ArgumentError, "Unsupported HTTP scheme: #{scheme['scheme']}" end when "apiKey" ApiKey.from_security_scheme(scheme, credentials["key"]) else raise ArgumentError, "Unsupported security scheme type: #{scheme['type']}" end new(strategy) end |
Instance Method Details
#apply_authentication(request) ⇒ Object
Apply authentication to a request
63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/a2a/client/auth/interceptor.rb', line 63 def apply_authentication(request) case @strategy when OAuth2, JWT, ApiKey @strategy.apply_to_request(request) when Hash # Handle configuration-based authentication apply_config_authentication(request, @strategy) else raise ArgumentError, "Unsupported authentication strategy: #{@strategy.class}" end end |
#apply_config_authentication(request, config) ⇒ Object (private)
Apply configuration-based authentication
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/a2a/client/auth/interceptor.rb', line 192 def apply_config_authentication(request, config) case config["type"] || config[:type] when "bearer" request.headers["Authorization"] = "Bearer #{config['token'] || config[:token]}" when "basic" require "base64" username = config["username"] || config[:username] password = config["password"] || config[:password] credentials = Base64.strict_encode64("#{username}:#{password}") request.headers["Authorization"] = "Basic #{credentials}" when "api_key" name = config["name"] || config[:name] || "X-API-Key" key = config["key"] || config[:key] location = config["location"] || config[:location] || "header" case location when "header" request.headers[name] = key when "query" request.params[name] = key end end end |
#authentication_error?(response) ⇒ Boolean (private)
Check if response indicates authentication error
221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/a2a/client/auth/interceptor.rb', line 221 def authentication_error?(response) # This would depend on the response format # For HTTP responses, check status codes return [401, 403].include?(response.status) if response.respond_to?(:status) # For JSON-RPC responses, check error codes if response.respond_to?(:[]) && response["error"] error_code = response["error"]["code"] return [A2A::Protocol::JsonRpc::AUTHENTICATION_REQUIRED, A2A::Protocol::JsonRpc::AUTHORIZATION_FAILED].include?(error_code) end false end |
#call(request, context, next_middleware) ⇒ Object
Middleware call method for Faraday
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/a2a/client/auth/interceptor.rb', line 38 def call(request, context, next_middleware) # Apply authentication to the request apply_authentication(request) # Execute the request begin response = next_middleware.call(request, context) # Check for authentication errors and retry if configured if authentication_error?(response) && @auto_retry handle_auth_error_retry(request, context, next_middleware) else response end rescue A2A::Errors::AuthenticationError, A2A::Errors::AuthorizationFailed => e raise e unless @auto_retry handle_auth_error_retry(request, context, next_middleware) end end |
#handle_auth_error_retry(request, context, next_middleware) ⇒ Object (private)
Handle authentication error with retry
242 243 244 245 246 247 248 249 250 251 252 253 254 |
# File 'lib/a2a/client/auth/interceptor.rb', line 242 def handle_auth_error_retry(request, context, next_middleware) @retry_mutex.synchronize do # Try to refresh credentials if refresh! # Reapply authentication and retry apply_authentication(request) return next_middleware.call(request, context) end end # If refresh failed, raise the original error raise A2A::Errors::AuthenticationError, "Authentication failed and refresh unsuccessful" end |
#refresh! ⇒ Boolean
Refresh authentication credentials
157 158 159 160 161 162 163 164 165 166 167 168 169 170 |
# File 'lib/a2a/client/auth/interceptor.rb', line 157 def refresh! return false unless supports_refresh? begin if @strategy.respond_to?(:refresh_token!) @strategy.refresh_token! elsif @strategy.respond_to?(:regenerate_token!) @strategy.regenerate_token! end true rescue StandardError false end end |
#status ⇒ Hash
Get current authentication status
176 177 178 179 180 181 182 183 |
# File 'lib/a2a/client/auth/interceptor.rb', line 176 def status { strategy: @strategy.class.name, valid: strategy_valid?, supports_refresh: supports_refresh?, expires_at: strategy_expires_at } end |
#strategy_expires_at ⇒ Time? (private)
Get strategy expiration time
277 278 279 280 281 282 283 284 |
# File 'lib/a2a/client/auth/interceptor.rb', line 277 def strategy_expires_at case @strategy when OAuth2 @strategy.expires_at when JWT @strategy.expires_at end end |
#strategy_valid? ⇒ Boolean (private)
Check if the current strategy is valid
260 261 262 263 264 265 266 267 268 269 270 271 |
# File 'lib/a2a/client/auth/interceptor.rb', line 260 def strategy_valid? case @strategy when OAuth2 @strategy.token_valid? when JWT !@strategy.token_expired? when ApiKey @strategy.valid? else true # Assume valid for unknown strategies end end |
#supports_refresh? ⇒ Boolean
Check if the strategy supports token refresh
149 150 151 |
# File 'lib/a2a/client/auth/interceptor.rb', line 149 def supports_refresh? @strategy.respond_to?(:refresh_token!) || @strategy.respond_to?(:regenerate_token!) end |