399 lines
11 KiB
Markdown
399 lines
11 KiB
Markdown
|
|
# Authorization Rules API Specification
|
||
|
|
|
||
|
|
This document defines the standardized API that all authorization rules must implement to ensure consistency, performance, and maintainability across the zanzibar-graph system.
|
||
|
|
|
||
|
|
## Overview
|
||
|
|
|
||
|
|
All authorization rules must extend the `BaseRule` class and implement the required abstract methods. This ensures:
|
||
|
|
|
||
|
|
- **Consistent Interface**: All rules have the same public API
|
||
|
|
- **Performance Tracking**: Built-in performance monitoring
|
||
|
|
- **Error Handling**: Standardized error responses
|
||
|
|
- **Batch Processing**: Optional but encouraged for performance
|
||
|
|
- **Early Exit**: Threshold-based optimization support
|
||
|
|
- **Input Validation**: Automatic parameter validation
|
||
|
|
|
||
|
|
## Core Interface
|
||
|
|
|
||
|
|
### Constructor
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
constructor(arbiter)
|
||
|
|
```
|
||
|
|
|
||
|
|
**Parameters:**
|
||
|
|
- `arbiter` (Arbiter): The main Arbiter instance
|
||
|
|
|
||
|
|
**Requirements:**
|
||
|
|
- Must call `super(arbiter)` first
|
||
|
|
- Should initialize any rule-specific state
|
||
|
|
- Must not throw exceptions
|
||
|
|
|
||
|
|
### Primary Evaluation Method
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
evaluate(userId, userKey, objectId, objectKey, rule, visited, currentRelation, options = {})
|
||
|
|
```
|
||
|
|
|
||
|
|
**Parameters:**
|
||
|
|
- `userId` (number): Internal user node ID
|
||
|
|
- `userKey` (string): User key (e.g., "user:alice")
|
||
|
|
- `objectId` (number): Internal object node ID
|
||
|
|
- `objectKey` (string): Object key (e.g., "doc:secret")
|
||
|
|
- `rule` (Object): Rule configuration object
|
||
|
|
- `visited` (Set): Set of visited nodes for cycle detection
|
||
|
|
- `currentRelation` (string): Current relation being evaluated
|
||
|
|
- `options` (Object): Evaluation options
|
||
|
|
|
||
|
|
**Returns:** `RuleEvaluationResult` object
|
||
|
|
|
||
|
|
**Standard Options:**
|
||
|
|
```javascript
|
||
|
|
{
|
||
|
|
// Performance options
|
||
|
|
fastPath: false, // Enable early termination
|
||
|
|
minAllowPossibility: null, // Threshold for allow early exit (0-1)
|
||
|
|
maxDenyPossibility: null, // Threshold for deny early exit (0-1)
|
||
|
|
|
||
|
|
// Inference options
|
||
|
|
noInfer: false, // Disable inference
|
||
|
|
allowInference: true, // Allow inference (opposite of noInfer)
|
||
|
|
|
||
|
|
// Binary mode
|
||
|
|
binary: false, // Return binary allow/deny decisions
|
||
|
|
|
||
|
|
// Evaluation tracking
|
||
|
|
trackEvaluation: true, // Include evaluation metadata
|
||
|
|
|
||
|
|
// Rule-specific options (passed through)
|
||
|
|
// ... additional options specific to rule type
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Batch Evaluation Method (Optional)
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
batchEvaluate(queries, batchOptions = {})
|
||
|
|
```
|
||
|
|
|
||
|
|
**Parameters:**
|
||
|
|
- `queries` (Array): Array of query objects with same structure as `evaluate` parameters
|
||
|
|
- `batchOptions` (Object): Batch-specific options
|
||
|
|
|
||
|
|
**Returns:** Array of `RuleEvaluationResult` objects
|
||
|
|
|
||
|
|
**Query Object Structure:**
|
||
|
|
```javascript
|
||
|
|
{
|
||
|
|
userId: number,
|
||
|
|
userKey: string,
|
||
|
|
objectId: number,
|
||
|
|
objectKey: string,
|
||
|
|
rule: Object,
|
||
|
|
visited: Set,
|
||
|
|
currentRelation: string,
|
||
|
|
options: Object
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Batch Support Check
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
canBatchProcess()
|
||
|
|
```
|
||
|
|
|
||
|
|
**Returns:** `boolean` - Whether this rule supports efficient batch processing
|
||
|
|
|
||
|
|
## Standard Result Structure
|
||
|
|
|
||
|
|
All evaluation methods must return a `RuleEvaluationResult` object:
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
{
|
||
|
|
// Core evaluation results (required)
|
||
|
|
possibility_allow: number, // 0-1, possibility of allowing access
|
||
|
|
possibility_deny: number, // 0-1, possibility of denying access
|
||
|
|
reliability: number, // 0-1, reliability of the evaluation
|
||
|
|
|
||
|
|
// Metadata (required, can be null)
|
||
|
|
meta_allow: Object | null, // Metadata for allow decision
|
||
|
|
meta_deny: Object | null, // Metadata for deny decision
|
||
|
|
|
||
|
|
// Optional fields
|
||
|
|
reason: string, // Reason for the result
|
||
|
|
error: boolean, // Whether this is an error result
|
||
|
|
details: Object, // Additional details
|
||
|
|
evaluation: Object // Evaluation tracking data
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Standard Metadata Structure
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// meta_allow / meta_deny structure
|
||
|
|
{
|
||
|
|
ruleType: string, // Type of rule (e.g., 'direct', 'tuple_to_userset')
|
||
|
|
reason: string, // Reason for decision
|
||
|
|
rule: Object, // Original rule configuration
|
||
|
|
|
||
|
|
// Performance metadata
|
||
|
|
earlyExit: boolean, // Whether early exit was used
|
||
|
|
earlyExitReason: string, // Reason for early exit
|
||
|
|
|
||
|
|
// Rule-specific metadata
|
||
|
|
// ... additional fields specific to rule type
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Implementation Requirements
|
||
|
|
|
||
|
|
### Abstract Methods (Must Implement)
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// Core evaluation logic
|
||
|
|
_evaluateRule(userId, userKey, objectId, objectKey, rule, visited, currentRelation, options)
|
||
|
|
|
||
|
|
// Batch evaluation logic (optional, only if canBatchProcess() returns true)
|
||
|
|
_batchEvaluateRule(queries, batchOptions)
|
||
|
|
```
|
||
|
|
|
||
|
|
### Performance Tracking
|
||
|
|
|
||
|
|
All rules automatically track:
|
||
|
|
- Individual evaluation count and timing
|
||
|
|
- Batch evaluation count and timing
|
||
|
|
- Average evaluation times
|
||
|
|
|
||
|
|
Access via:
|
||
|
|
```javascript
|
||
|
|
rule.getPerformanceStats()
|
||
|
|
rule.resetPerformanceStats()
|
||
|
|
```
|
||
|
|
|
||
|
|
### Error Handling
|
||
|
|
|
||
|
|
Rules should handle errors gracefully:
|
||
|
|
- Input validation is automatic
|
||
|
|
- Exceptions are caught and converted to error results
|
||
|
|
- Batch operations fall back to individual evaluations on error
|
||
|
|
|
||
|
|
## Rule-Specific Configurations
|
||
|
|
|
||
|
|
### Common Rule Properties
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
{
|
||
|
|
type: string, // Rule type identifier
|
||
|
|
ruleType: string, // 'defeasible', 'defeater', 'strict'
|
||
|
|
priority: number, // Rule priority (higher = more important)
|
||
|
|
weight: number, // Rule weight for aggregation
|
||
|
|
|
||
|
|
// Performance options
|
||
|
|
no_infer: boolean, // Disable inference for this rule
|
||
|
|
allowInference: boolean, // Allow inference
|
||
|
|
|
||
|
|
// Aggregation options
|
||
|
|
owaWeights: Array<number>, // OWA aggregation weights
|
||
|
|
aggregator: string, // Aggregation method ('max', 'min', 'avg', etc.)
|
||
|
|
|
||
|
|
// Rule-specific properties
|
||
|
|
// ... varies by rule type
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### DirectRule Configuration
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
{
|
||
|
|
type: 'direct',
|
||
|
|
relation: string, // Relation to check (optional, uses currentRelation)
|
||
|
|
reverse: boolean // Check in reverse direction
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### TupleToUsersetRule Configuration
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
{
|
||
|
|
type: 'tuple_to_userset',
|
||
|
|
tuplesetRelation: string, // Relation from object to intermediate
|
||
|
|
computedRelation: string, // Relation from user to intermediate
|
||
|
|
reverse: boolean // Check in reverse direction
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### ParentRule Configuration
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
{
|
||
|
|
type: 'parent',
|
||
|
|
parentRelation: string, // Relation defining parent-child
|
||
|
|
relation: string, // Relation to check on parent
|
||
|
|
reverse: boolean // Check in reverse direction
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### SimilarityRule Configuration
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
{
|
||
|
|
type: 'similar_to',
|
||
|
|
relation: string, // Relation to find similarities for
|
||
|
|
k: number, // Number of similar entities to consider
|
||
|
|
similarityThreshold: number, // Minimum similarity threshold (0-1)
|
||
|
|
reverse: boolean, // Check in reverse direction
|
||
|
|
fallbackToBasicSimilarity: boolean // Use basic similarity when embeddings unavailable
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### MultiHopRule Configuration
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
{
|
||
|
|
type: 'multi_hop',
|
||
|
|
relation: string, // Relation to traverse
|
||
|
|
maxDepth: number, // Maximum path depth
|
||
|
|
minReliability: number, // Minimum path reliability
|
||
|
|
decayFactor: number, // Reliability decay per hop
|
||
|
|
pathAggregation: string, // How to aggregate multiple paths ('max', 'sum', 'owa')
|
||
|
|
reverse: boolean, // Search in reverse direction
|
||
|
|
allowInference: boolean, // Allow inference for missing edges
|
||
|
|
fallbackToBasicPaths: boolean // Use basic path finding as fallback
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### ComputedRule Configuration
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
{
|
||
|
|
type: 'computed',
|
||
|
|
relation: string // Relation to recursively evaluate
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Logical Operators
|
||
|
|
|
||
|
|
### Union (OR) Configuration
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
{
|
||
|
|
union: Array<RuleConfig>, // Array of rules to OR together
|
||
|
|
aggregator: string, // Aggregation method
|
||
|
|
owaWeights: Array<number>, // OWA weights for fusion
|
||
|
|
reliabilityWeighting: boolean // Weight by reliability
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Intersection (AND) Configuration
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
{
|
||
|
|
intersection: Array<RuleConfig>, // Array of rules to AND together
|
||
|
|
aggregator: string, // Aggregation method (defaults to 'min')
|
||
|
|
owaWeights: Array<number> // OWA weights for fusion
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Exclusion (A AND NOT B) Configuration
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
{
|
||
|
|
exclusion: [RuleConfig, RuleConfig] // [base rule, exclusion rule]
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
## Performance Optimization Guidelines
|
||
|
|
|
||
|
|
### Early Exit Support
|
||
|
|
|
||
|
|
Rules should support early termination when:
|
||
|
|
- `options.fastPath` is true
|
||
|
|
- `options.minAllowPossibility` threshold is met
|
||
|
|
- `options.maxDenyPossibility` threshold is met
|
||
|
|
|
||
|
|
### Batch Processing
|
||
|
|
|
||
|
|
Rules that can benefit from batch processing should:
|
||
|
|
- Override `canBatchProcess()` to return `true`
|
||
|
|
- Implement `_batchEvaluateRule()` method
|
||
|
|
- Group similar operations for efficiency
|
||
|
|
- Use indexed lookups instead of linear scans
|
||
|
|
|
||
|
|
### Caching
|
||
|
|
|
||
|
|
Rules should leverage:
|
||
|
|
- Arbiter's built-in caching mechanisms
|
||
|
|
- Batch caches for intermediate results
|
||
|
|
- Embedding caches for similarity calculations
|
||
|
|
|
||
|
|
## Testing Requirements
|
||
|
|
|
||
|
|
All rules must include:
|
||
|
|
- Unit tests for individual evaluation
|
||
|
|
- Batch evaluation tests (if supported)
|
||
|
|
- Performance benchmarks
|
||
|
|
- Error handling tests
|
||
|
|
- Edge case coverage
|
||
|
|
|
||
|
|
## Migration Guide
|
||
|
|
|
||
|
|
To migrate existing rules to the new API:
|
||
|
|
|
||
|
|
1. **Extend BaseRule**: Change `export class MyRule` to `export class MyRule extends BaseRule`
|
||
|
|
2. **Rename evaluate**: Rename `evaluate()` to `_evaluateRule()`
|
||
|
|
3. **Update constructor**: Call `super(arbiter)` first
|
||
|
|
4. **Handle options**: Use normalized options parameter
|
||
|
|
5. **Update tests**: Test against new interface
|
||
|
|
|
||
|
|
## Example Implementation
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
import { BaseRule } from './BaseRule.js';
|
||
|
|
|
||
|
|
export class ExampleRule extends BaseRule {
|
||
|
|
constructor(arbiter) {
|
||
|
|
super(arbiter);
|
||
|
|
// Rule-specific initialization
|
||
|
|
}
|
||
|
|
|
||
|
|
canBatchProcess() {
|
||
|
|
return true; // This rule supports batching
|
||
|
|
}
|
||
|
|
|
||
|
|
_evaluateRule(userId, userKey, objectId, objectKey, rule, visited, currentRelation, options) {
|
||
|
|
// Implement rule-specific logic
|
||
|
|
const result = {
|
||
|
|
possibility_allow: 0.8,
|
||
|
|
possibility_deny: 0.1,
|
||
|
|
reliability: 0.9,
|
||
|
|
meta_allow: {
|
||
|
|
ruleType: 'example',
|
||
|
|
reason: 'example_evaluation',
|
||
|
|
rule
|
||
|
|
},
|
||
|
|
meta_deny: null,
|
||
|
|
reason: 'example_result'
|
||
|
|
};
|
||
|
|
|
||
|
|
return result;
|
||
|
|
}
|
||
|
|
|
||
|
|
_batchEvaluateRule(queries, batchOptions) {
|
||
|
|
// Implement efficient batch processing
|
||
|
|
return queries.map(query =>
|
||
|
|
this._evaluateRule(
|
||
|
|
query.userId,
|
||
|
|
query.userKey,
|
||
|
|
query.objectId,
|
||
|
|
query.objectKey,
|
||
|
|
query.rule,
|
||
|
|
query.visited,
|
||
|
|
query.currentRelation,
|
||
|
|
query.options
|
||
|
|
)
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
This standardized API ensures all rules work consistently while allowing for rule-specific optimizations and features.
|