forked from mirrors/kingfisher
7 KiB
7 KiB
Multi-Step Revocation Implementation
Overview
This document describes the implementation of 2-step revocation support in Kingfisher. Some services require a two-step revocation process:
- Step 1 (Lookup): Query the API to retrieve an internal ID, token identifier, or other metadata
- Step 2 (Delete): Use the extracted value(s) to perform the actual revocation/deletion
Architecture
New Types
HttpMultiStepRevocation
pub struct HttpMultiStepRevocation {
/// Sequential steps to execute (minimum 1, maximum 2).
pub steps: Vec<RevocationStep>,
}
RevocationStep
pub struct RevocationStep {
/// Human-readable name for this step (e.g., "lookup_id", "delete").
pub name: Option<String>,
/// HTTP request configuration for this step.
pub request: HttpRequest,
/// Optional multipart configuration for this step.
pub multipart: Option<MultipartConfig>,
/// Variables to extract from the response for use in subsequent steps.
pub extract: Option<BTreeMap<String, ResponseExtractor>>,
}
ResponseExtractor
pub enum ResponseExtractor {
/// Extract from JSON response using JSONPath syntax
JsonPath { path: String },
/// Extract using regex with a capture group
Regex { pattern: String },
/// Extract an HTTP response header value
Header { name: String },
/// Use the entire response body as-is
Body,
/// Extract the HTTP status code as a string
StatusCode,
}
Revocation Enum
The Revocation enum has been extended with:
pub enum Revocation {
AWS,
GCP,
Http(HttpValidation),
HttpMultiStep(HttpMultiStepRevocation), // New variant
}
Implementation Details
Execution Flow
- Validation: Checks that 1-2 steps are defined
- Sequential Execution: Each step executes in order
- Variable Extraction: After each step completes, extract variables from response
- Variable Injection: Extracted variables are available as Liquid templates in subsequent steps
- Response Validation: Final step's
response_matcherdetermines success/failure
Key Functions
extract_value_from_response()
Extracts a value from an HTTP response based on the specified extractor type.
Supported Extractors:
- JsonPath: Basic JSONPath implementation supporting:
- Nested fields:
$.data.user.id - Array indexing:
$.items[0].id - Combined:
$.data.sessions[0].session_id
- Nested fields:
- Regex: Uses first capture group from pattern match
- Header: Extracts value from response header by name
- Body: Returns entire response body
- StatusCode: Returns HTTP status code as string
execute_revocation_step()
Executes a single revocation step:
- Renders URL and request templates with current variables
- Builds and sends HTTP request
- Extracts variables from response if configured
- Adds extracted variables to globals for next step
execute_multi_step_revocation()
Orchestrates the multi-step revocation process:
- Validates step count (1-2 steps)
- Iterates through steps sequentially
- Tracks intermediate results
- Returns final result from last step
Backwards Compatibility
All existing single-step revocations continue to work unchanged:
Revocation::AWSRevocation::GCPRevocation::Http(_)
Usage Examples
Basic 2-Step Revocation
revocation:
type: HttpMultiStep
content:
steps:
# Step 1: Get the token ID
- name: lookup_token_id
request:
method: GET
url: https://api.example.com/v1/tokens/current
headers:
Authorization: "Bearer {{ TOKEN }}"
response_matcher:
- type: StatusMatch
status: [200]
extract:
TOKEN_ID:
type: JsonPath
path: "$.data.token_id"
# Step 2: Delete the token
- name: delete_token
request:
method: DELETE
url: https://api.example.com/v1/tokens/{{ TOKEN_ID }}
headers:
Authorization: "Bearer {{ TOKEN }}"
response_matcher:
- type: StatusMatch
status: [204]
Multiple Extractions
revocation:
type: HttpMultiStep
content:
steps:
- name: get_metadata
request:
method: GET
url: https://api.service.com/tokens/info
headers:
Authorization: "Bearer {{ TOKEN }}"
response_matcher:
- type: StatusMatch
status: [200]
extract:
TOKEN_ID:
type: JsonPath
path: "$.id"
ACCOUNT_ID:
type: Header
name: X-Account-ID
TOKEN_TYPE:
type: Regex
pattern: '"type":\s*"([^"]+)"'
- name: revoke_token
request:
method: POST
url: https://api.service.com/accounts/{{ ACCOUNT_ID }}/tokens/{{ TOKEN_ID }}/revoke
headers:
Authorization: "Bearer {{ TOKEN }}"
Content-Type: application/json
body: '{"token_type":"{{ TOKEN_TYPE }}"}'
response_matcher:
- type: StatusMatch
status: [200, 204]
Testing
Test your multi-step revocation using:
# Revoke a token using multi-step revocation
kingfisher revoke --rule <rule_id> <token>
# With additional variables if needed
kingfisher revoke --rule <rule_id> --var EXTRA_VAR=value <token>
Files Modified
Core Implementation
crates/kingfisher-rules/src/rule.rs: Added new types and enum variantscrates/kingfisher-rules/src/lib.rs: Exported new typessrc/direct_revoke.rs: Added multi-step execution logic
Documentation
docs/RULES.md: Added comprehensive multi-step revocation documentationdocs/MULTI_STEP_REVOCATION.md: This file
Examples
crates/kingfisher-rules/data/rules/example_multistep.yml: Example rules demonstrating multi-step revocation
Supporting Changes
src/reporter.rs: Added pattern match forHttpMultiStepvariant
Constraints
- Maximum 2 steps: The implementation supports 1-2 steps only
- Sequential execution: Steps execute in order; no parallel execution
- Final step validation: The last step must include
response_matcher - Variable naming: Extracted variable names should be uppercase (convention)
- JSONPath limitations: Basic implementation supporting common patterns only
Error Handling
The implementation provides clear error messages for:
- Empty steps array
- More than 2 steps
- Missing response_matcher on final step
- Failed variable extraction
- Invalid JSONPath syntax
- Missing required headers or fields
- HTTP request failures
All errors are propagated with context about which step failed and why.
Debug Logging
Enable debug logging to see multi-step execution details:
RUST_LOG=debug kingfisher revoke --rule <rule_id> <token>
Debug logs include:
- Step execution start/completion
- URLs being called
- Variables extracted and their values
- Response status codes
- Intermediate step results