IAMRequest

Struct IAMRequest 

Source
pub struct IAMRequest {
    pub principal: Principal,
    pub action: String,
    pub resource: Arn,
    pub context: Context,
}
Expand description

Core IAM request containing principal, action, and resource

§Understanding the PARC model

The PARC model represents the request context based on the four JSON elements in the policy language:

  • Principal – The entity making the request. A principal represents a human user or programmatic workload that can be authenticated and then authorized to perform actions in AWS accounts.
  • Action – The operation being performed. Often the action will map to an API action.
  • Resource – The AWS resource on which the action is being performed.
  • Condition – Additional constraints that must be met for the request to be allowed.

The following shows an example of how the PARC model might represent a request context:

Principal: AIDA123456789EXAMPLE
Action: s3:CreateBucket
Resource: arn:aws:s3:::amzn-s3-demo-bucket1
Context:
- aws:UserId=AIDA123456789EXAMPLE:BobsSession
- aws:PrincipalAccount=123456789012
- aws:PrincipalOrgId=o-example
- aws:PrincipalARN=arn:aws:iam::AIDA123456789EXAMPLE:role/HR
- aws:MultiFactorAuthPresent=true
- aws:CurrentTime=...
- aws:EpochTime=...
- aws:SourceIp=...
- aws:PrincipalTag/dept=123
- aws:PrincipalTag/project=blue
- aws:RequestTag/dept=123

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_evaluation-logic_policy-eval-reqcontext.html

Fields§

§principal: Principal

The principal making the request (e.g., AROA123456789EXAMPLE)

§action: String

The action being requested (e.g., iam:DeactivateMFADevice)

§resource: Arn

The resource being accessed (e.g., arn:aws:iam::user/martha)

§context: Context

Additional context for condition evaluation

Implementations§

Source§

impl IAMRequest

Source

pub fn new<S: Into<String>>( principal: Principal, action: S, resource: Arn, ) -> Self

Creates a new request

Examples found in repository?
examples/evaluation_demo.rs (lines 21-27)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8    println!("=== IAM Policy Evaluation Engine Demo ===\n");
9
10    // Example 1: Simple Allow Policy
11    println!("1. Simple Allow Policy:");
12    let allow_policy = IAMPolicy::new()
13        .with_id("550e8400-e29b-41d4-a716-446655440000")
14        .add_statement(
15            IAMStatement::new(IAMEffect::Allow)
16                .with_sid("AllowS3Read")
17                .with_action(IAMAction::Single("s3:GetObject".to_string()))
18                .with_resource(IAMResource::Single("arn:aws:s3:::my-bucket/*".to_string())),
19        );
20
21    let request = IAMRequest::new(
22        Principal::Aws(PrincipalId::String(
23            "arn:aws:iam::123456789012:user/alice".to_string(),
24        )),
25        "s3:GetObject",
26        Arn::parse("arn:aws:s3:::my-bucket/file.txt").unwrap(),
27    );
28
29    match evaluate_policy(&allow_policy, &request)? {
30        Decision::Allow => println!("✓ Access ALLOWED"),
31        Decision::Deny => println!("✗ Access DENIED"),
32        Decision::NotApplicable => println!("? No applicable policy (implicit deny)"),
33    }
34    println!();
35
36    // Example 2: Simple Deny Policy
37    println!("2. Simple Deny Policy:");
38    let deny_policy = IAMPolicy::new()
39        .with_id("550e8400-e29b-41d4-a716-446655440001")
40        .add_statement(
41            IAMStatement::new(IAMEffect::Deny)
42                .with_sid("DenyS3Delete")
43                .with_action(IAMAction::Single("s3:DeleteObject".to_string()))
44                .with_resource(IAMResource::Single(
45                    "arn:aws:s3:::protected-bucket/*".to_string(),
46                )),
47        );
48
49    let delete_request = IAMRequest::new(
50        Principal::Aws(PrincipalId::String(
51            "arn:aws:iam::123456789012:user/alice".to_string(),
52        )),
53        "s3:DeleteObject",
54        Arn::parse("arn:aws:s3:::protected-bucket/important.txt").unwrap(),
55    );
56
57    match evaluate_policy(&deny_policy, &delete_request)? {
58        Decision::Allow => println!("✓ Access ALLOWED"),
59        Decision::Deny => println!("✗ Access DENIED"),
60        Decision::NotApplicable => println!("? No applicable policy (implicit deny)"),
61    }
62    println!();
63
64    // Example 3: Wildcard Action Matching
65    println!("3. Wildcard Action Matching:");
66    let wildcard_policy = IAMPolicy::new()
67        .with_id("550e8400-e29b-41d4-a716-446655440002")
68        .add_statement(
69            IAMStatement::new(IAMEffect::Allow)
70                .with_sid("AllowAllS3")
71                .with_action(IAMAction::Single("s3:*".to_string()))
72                .with_resource(IAMResource::Single("arn:aws:s3:::my-bucket/*".to_string())),
73        );
74
75    let wildcard_request = IAMRequest::new(
76        Principal::Aws(PrincipalId::String(
77            "arn:aws:iam::123456789012:user/alice".to_string(),
78        )),
79        "s3:PutObject",
80        Arn::parse("arn:aws:s3:::my-bucket/new-file.txt").unwrap(),
81    );
82
83    match evaluate_policy(&wildcard_policy, &wildcard_request)? {
84        Decision::Allow => println!("✓ Wildcard action matched - Access ALLOWED"),
85        Decision::Deny => println!("✗ Access DENIED"),
86        Decision::NotApplicable => println!("? No applicable policy"),
87    }
88    println!();
89
90    // Example 4: Condition-Based Policy
91    println!("4. Condition-Based Policy:");
92    let mut context = Context::new();
93    context.insert(
94        "aws:userid".to_string(),
95        ContextValue::String("alice".to_string()),
96    );
97    context.insert(
98        "aws:CurrentTime".to_string(),
99        ContextValue::String("2024-01-15T10:00:00Z".to_string()),
100    );
101
102    let condition_policy = IAMPolicy::new()
103        .with_id("550e8400-e29b-41d4-a716-446655440003")
104        .add_statement(
105            IAMStatement::new(IAMEffect::Allow)
106                .with_sid("AllowWithCondition")
107                .with_action(IAMAction::Single("s3:GetObject".to_string()))
108                .with_resource(IAMResource::Single(
109                    "arn:aws:s3:::private-bucket/*".to_string(),
110                ))
111                .with_condition(
112                    IAMOperator::StringEquals,
113                    "aws:userid".to_string(),
114                    ConditionValue::String("alice".to_string()),
115                ),
116        );
117
118    let condition_request = IAMRequest::new_with_context(
119        Principal::Aws(PrincipalId::String(
120            "arn:aws:iam::123456789012:user/alice".to_string(),
121        )),
122        "s3:GetObject",
123        Arn::parse("arn:aws:s3:::private-bucket/personal.txt").unwrap(),
124        context,
125    );
126
127    match evaluate_policy(&condition_policy, &condition_request)? {
128        Decision::Allow => println!("✓ Condition satisfied - Access ALLOWED"),
129        Decision::Deny => println!("✗ Access DENIED"),
130        Decision::NotApplicable => println!("? Condition not satisfied"),
131    }
132    println!();
133
134    // Example 5: Failed Condition
135    println!("5. Failed Condition:");
136    let mut wrong_context = Context::new();
137    wrong_context.insert(
138        "aws:userid".to_string(),
139        ContextValue::String("bob".to_string()),
140    );
141
142    let failed_condition_request = IAMRequest::new_with_context(
143        Principal::Aws(PrincipalId::String(
144            "arn:aws:iam::123456789012:user/bob".to_string(),
145        )),
146        "s3:GetObject",
147        Arn::parse("arn:aws:s3:::private-bucket/personal.txt").unwrap(),
148        wrong_context,
149    );
150
151    match evaluate_policy(&condition_policy, &failed_condition_request)? {
152        Decision::Allow => println!("✓ Access ALLOWED"),
153        Decision::Deny => println!("✗ Access DENIED"),
154        Decision::NotApplicable => println!("? Condition failed - No applicable policy"),
155    }
156    println!();
157
158    // Example 6: Explicit Deny Overrides Allow
159    println!("6. Explicit Deny Overrides Allow:");
160    let combined_policies = vec![
161        IAMPolicy::new()
162            .with_id("550e8400-e29b-41d4-a716-446655440004")
163            .add_statement(
164                IAMStatement::new(IAMEffect::Allow)
165                    .with_sid("AllowAll")
166                    .with_action(IAMAction::Single("s3:*".to_string()))
167                    .with_resource(IAMResource::Single("*".to_string())),
168            ),
169        IAMPolicy::new()
170            .with_id("550e8400-e29b-41d4-a716-446655440005")
171            .add_statement(
172                IAMStatement::new(IAMEffect::Deny)
173                    .with_sid("DenyProtected")
174                    .with_action(IAMAction::Single("s3:DeleteObject".to_string()))
175                    .with_resource(IAMResource::Single(
176                        "arn:aws:s3:::protected-bucket/*".to_string(),
177                    )),
178            ),
179    ];
180
181    let evaluator = PolicyEvaluator::with_policies(combined_policies);
182    let protected_request = IAMRequest::new(
183        Principal::Aws(PrincipalId::String(
184            "arn:aws:iam::123456789012:user/alice".to_string(),
185        )),
186        "s3:DeleteObject",
187        Arn::parse("arn:aws:s3:::protected-bucket/critical.txt").unwrap(),
188    );
189
190    match evaluator.evaluate(&protected_request)?.decision {
191        Decision::Allow => println!("✓ Access ALLOWED"),
192        Decision::Deny => println!("✗ Explicit DENY overrides Allow"),
193        Decision::NotApplicable => println!("? No applicable policy"),
194    }
195    println!();
196
197    // Example 7: Numeric Condition
198    println!("7. Numeric Condition:");
199    let mut numeric_context = Context::new();
200    numeric_context.insert("aws:RequestCount".to_string(), ContextValue::Number(5.0));
201
202    let numeric_policy = IAMPolicy::new()
203        .with_id("550e8400-e29b-41d4-a716-446655440006")
204        .add_statement(
205            IAMStatement::new(IAMEffect::Allow)
206                .with_sid("AllowLimitedRequests")
207                .with_action(IAMAction::Single("s3:GetObject".to_string()))
208                .with_resource(IAMResource::Single("*".to_string()))
209                .with_condition(
210                    IAMOperator::NumericLessThan,
211                    "aws:RequestCount".to_string(),
212                    ConditionValue::Number(10),
213                ),
214        );
215
216    let numeric_request = IAMRequest::new_with_context(
217        Principal::Aws(PrincipalId::String(
218            "arn:aws:iam::123456789012:user/alice".to_string(),
219        )),
220        "s3:GetObject",
221        Arn::parse("arn:aws:s3:::any-bucket/file.txt").unwrap(),
222        numeric_context,
223    );
224
225    match evaluate_policy(&numeric_policy, &numeric_request)? {
226        Decision::Allow => println!("✓ Numeric condition satisfied - Access ALLOWED"),
227        Decision::Deny => println!("✗ Access DENIED"),
228        Decision::NotApplicable => println!("? Numeric condition failed"),
229    }
230    println!();
231
232    // Example 8: Detailed Evaluation with Options
233    println!("8. Detailed Evaluation with Options:");
234    let detailed_evaluator = PolicyEvaluator::with_policies(vec![allow_policy.clone()])
235        .with_options(EvaluationOptions {
236            collect_match_details: true,
237            stop_on_explicit_deny: false,
238            max_statements: 100,
239            ignore_resource_constraints: false,
240        });
241
242    let detailed_result = detailed_evaluator.evaluate(&request)?;
243    println!("Decision: {:?}", detailed_result.decision);
244    println!("Matched Statements:");
245    for (i, statement_match) in detailed_result.matched_statements.iter().enumerate() {
246        println!(
247            "  {}. SID: {:?}, Effect: {:?}, Satisfied: {}, Reason: {}",
248            i + 1,
249            statement_match.sid,
250            statement_match.effect,
251            statement_match.conditions_satisfied,
252            statement_match.reason
253        );
254    }
255    println!();
256
257    // Example 9: No Applicable Policy (Implicit Deny)
258    println!("9. No Applicable Policy (Implicit Deny):");
259    let unrelated_request = IAMRequest::new(
260        Principal::Aws(PrincipalId::String(
261            "arn:aws:iam::123456789012:user/alice".to_string(),
262        )),
263        "ec2:DescribeInstances",
264        Arn::parse("arn:aws:ec2:us-east-1:123456789012:instance/*").unwrap(),
265    );
266
267    match evaluate_policy(&allow_policy, &unrelated_request)? {
268        Decision::Allow => println!("✓ Access ALLOWED"),
269        Decision::Deny => println!("✗ Access DENIED"),
270        Decision::NotApplicable => println!("? No applicable policy - Implicit DENY"),
271    }
272    println!();
273
274    // Example 10: Resource Pattern Matching
275    println!("10. Resource Pattern Matching:");
276    let pattern_policy = IAMPolicy::new()
277        .with_id("550e8400-e29b-41d4-a716-446655440007")
278        .add_statement(
279            IAMStatement::new(IAMEffect::Allow)
280                .with_sid("AllowBucketAccess")
281                .with_action(IAMAction::Multiple(vec![
282                    "s3:GetObject".to_string(),
283                    "s3:PutObject".to_string(),
284                ]))
285                .with_resource(IAMResource::Single(
286                    "arn:aws:s3:::user-data-*/*".to_string(),
287                )),
288        );
289
290    let pattern_request = IAMRequest::new(
291        Principal::Aws(PrincipalId::String(
292            "arn:aws:iam::123456789012:user/alice".to_string(),
293        )),
294        "s3:GetObject",
295        Arn::parse("arn:aws:s3:::user-data-alice/profile.json").unwrap(),
296    );
297
298    match evaluate_policy(&pattern_policy, &pattern_request)? {
299        Decision::Allow => println!("✓ Resource pattern matched - Access ALLOWED"),
300        Decision::Deny => println!("✗ Access DENIED"),
301        Decision::NotApplicable => println!("? Resource pattern didn't match"),
302    }
303
304    println!("\n=== Policy Evaluation Demo Complete ===");
305    println!("\nThe Policy Evaluation Engine successfully:");
306    println!("• ✅ Evaluates Allow/Deny effects");
307    println!("• ✅ Handles wildcard actions and resources");
308    println!("• ✅ Processes condition blocks with various operators");
309    println!("• ✅ Implements proper IAM logic (explicit deny overrides)");
310    println!("• ✅ Supports detailed evaluation with match information");
311    println!("• ✅ Handles multiple policies with complex interactions");
312    println!("• ✅ Provides clear Allow/Deny/NotApplicable decisions");
313
314    Ok(())
315}
Source

pub fn new_with_context<S: Into<String>>( principal: Principal, action: S, resource: Arn, context: Context, ) -> Self

Creates a request with context

Examples found in repository?
examples/evaluation_demo.rs (lines 118-125)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8    println!("=== IAM Policy Evaluation Engine Demo ===\n");
9
10    // Example 1: Simple Allow Policy
11    println!("1. Simple Allow Policy:");
12    let allow_policy = IAMPolicy::new()
13        .with_id("550e8400-e29b-41d4-a716-446655440000")
14        .add_statement(
15            IAMStatement::new(IAMEffect::Allow)
16                .with_sid("AllowS3Read")
17                .with_action(IAMAction::Single("s3:GetObject".to_string()))
18                .with_resource(IAMResource::Single("arn:aws:s3:::my-bucket/*".to_string())),
19        );
20
21    let request = IAMRequest::new(
22        Principal::Aws(PrincipalId::String(
23            "arn:aws:iam::123456789012:user/alice".to_string(),
24        )),
25        "s3:GetObject",
26        Arn::parse("arn:aws:s3:::my-bucket/file.txt").unwrap(),
27    );
28
29    match evaluate_policy(&allow_policy, &request)? {
30        Decision::Allow => println!("✓ Access ALLOWED"),
31        Decision::Deny => println!("✗ Access DENIED"),
32        Decision::NotApplicable => println!("? No applicable policy (implicit deny)"),
33    }
34    println!();
35
36    // Example 2: Simple Deny Policy
37    println!("2. Simple Deny Policy:");
38    let deny_policy = IAMPolicy::new()
39        .with_id("550e8400-e29b-41d4-a716-446655440001")
40        .add_statement(
41            IAMStatement::new(IAMEffect::Deny)
42                .with_sid("DenyS3Delete")
43                .with_action(IAMAction::Single("s3:DeleteObject".to_string()))
44                .with_resource(IAMResource::Single(
45                    "arn:aws:s3:::protected-bucket/*".to_string(),
46                )),
47        );
48
49    let delete_request = IAMRequest::new(
50        Principal::Aws(PrincipalId::String(
51            "arn:aws:iam::123456789012:user/alice".to_string(),
52        )),
53        "s3:DeleteObject",
54        Arn::parse("arn:aws:s3:::protected-bucket/important.txt").unwrap(),
55    );
56
57    match evaluate_policy(&deny_policy, &delete_request)? {
58        Decision::Allow => println!("✓ Access ALLOWED"),
59        Decision::Deny => println!("✗ Access DENIED"),
60        Decision::NotApplicable => println!("? No applicable policy (implicit deny)"),
61    }
62    println!();
63
64    // Example 3: Wildcard Action Matching
65    println!("3. Wildcard Action Matching:");
66    let wildcard_policy = IAMPolicy::new()
67        .with_id("550e8400-e29b-41d4-a716-446655440002")
68        .add_statement(
69            IAMStatement::new(IAMEffect::Allow)
70                .with_sid("AllowAllS3")
71                .with_action(IAMAction::Single("s3:*".to_string()))
72                .with_resource(IAMResource::Single("arn:aws:s3:::my-bucket/*".to_string())),
73        );
74
75    let wildcard_request = IAMRequest::new(
76        Principal::Aws(PrincipalId::String(
77            "arn:aws:iam::123456789012:user/alice".to_string(),
78        )),
79        "s3:PutObject",
80        Arn::parse("arn:aws:s3:::my-bucket/new-file.txt").unwrap(),
81    );
82
83    match evaluate_policy(&wildcard_policy, &wildcard_request)? {
84        Decision::Allow => println!("✓ Wildcard action matched - Access ALLOWED"),
85        Decision::Deny => println!("✗ Access DENIED"),
86        Decision::NotApplicable => println!("? No applicable policy"),
87    }
88    println!();
89
90    // Example 4: Condition-Based Policy
91    println!("4. Condition-Based Policy:");
92    let mut context = Context::new();
93    context.insert(
94        "aws:userid".to_string(),
95        ContextValue::String("alice".to_string()),
96    );
97    context.insert(
98        "aws:CurrentTime".to_string(),
99        ContextValue::String("2024-01-15T10:00:00Z".to_string()),
100    );
101
102    let condition_policy = IAMPolicy::new()
103        .with_id("550e8400-e29b-41d4-a716-446655440003")
104        .add_statement(
105            IAMStatement::new(IAMEffect::Allow)
106                .with_sid("AllowWithCondition")
107                .with_action(IAMAction::Single("s3:GetObject".to_string()))
108                .with_resource(IAMResource::Single(
109                    "arn:aws:s3:::private-bucket/*".to_string(),
110                ))
111                .with_condition(
112                    IAMOperator::StringEquals,
113                    "aws:userid".to_string(),
114                    ConditionValue::String("alice".to_string()),
115                ),
116        );
117
118    let condition_request = IAMRequest::new_with_context(
119        Principal::Aws(PrincipalId::String(
120            "arn:aws:iam::123456789012:user/alice".to_string(),
121        )),
122        "s3:GetObject",
123        Arn::parse("arn:aws:s3:::private-bucket/personal.txt").unwrap(),
124        context,
125    );
126
127    match evaluate_policy(&condition_policy, &condition_request)? {
128        Decision::Allow => println!("✓ Condition satisfied - Access ALLOWED"),
129        Decision::Deny => println!("✗ Access DENIED"),
130        Decision::NotApplicable => println!("? Condition not satisfied"),
131    }
132    println!();
133
134    // Example 5: Failed Condition
135    println!("5. Failed Condition:");
136    let mut wrong_context = Context::new();
137    wrong_context.insert(
138        "aws:userid".to_string(),
139        ContextValue::String("bob".to_string()),
140    );
141
142    let failed_condition_request = IAMRequest::new_with_context(
143        Principal::Aws(PrincipalId::String(
144            "arn:aws:iam::123456789012:user/bob".to_string(),
145        )),
146        "s3:GetObject",
147        Arn::parse("arn:aws:s3:::private-bucket/personal.txt").unwrap(),
148        wrong_context,
149    );
150
151    match evaluate_policy(&condition_policy, &failed_condition_request)? {
152        Decision::Allow => println!("✓ Access ALLOWED"),
153        Decision::Deny => println!("✗ Access DENIED"),
154        Decision::NotApplicable => println!("? Condition failed - No applicable policy"),
155    }
156    println!();
157
158    // Example 6: Explicit Deny Overrides Allow
159    println!("6. Explicit Deny Overrides Allow:");
160    let combined_policies = vec![
161        IAMPolicy::new()
162            .with_id("550e8400-e29b-41d4-a716-446655440004")
163            .add_statement(
164                IAMStatement::new(IAMEffect::Allow)
165                    .with_sid("AllowAll")
166                    .with_action(IAMAction::Single("s3:*".to_string()))
167                    .with_resource(IAMResource::Single("*".to_string())),
168            ),
169        IAMPolicy::new()
170            .with_id("550e8400-e29b-41d4-a716-446655440005")
171            .add_statement(
172                IAMStatement::new(IAMEffect::Deny)
173                    .with_sid("DenyProtected")
174                    .with_action(IAMAction::Single("s3:DeleteObject".to_string()))
175                    .with_resource(IAMResource::Single(
176                        "arn:aws:s3:::protected-bucket/*".to_string(),
177                    )),
178            ),
179    ];
180
181    let evaluator = PolicyEvaluator::with_policies(combined_policies);
182    let protected_request = IAMRequest::new(
183        Principal::Aws(PrincipalId::String(
184            "arn:aws:iam::123456789012:user/alice".to_string(),
185        )),
186        "s3:DeleteObject",
187        Arn::parse("arn:aws:s3:::protected-bucket/critical.txt").unwrap(),
188    );
189
190    match evaluator.evaluate(&protected_request)?.decision {
191        Decision::Allow => println!("✓ Access ALLOWED"),
192        Decision::Deny => println!("✗ Explicit DENY overrides Allow"),
193        Decision::NotApplicable => println!("? No applicable policy"),
194    }
195    println!();
196
197    // Example 7: Numeric Condition
198    println!("7. Numeric Condition:");
199    let mut numeric_context = Context::new();
200    numeric_context.insert("aws:RequestCount".to_string(), ContextValue::Number(5.0));
201
202    let numeric_policy = IAMPolicy::new()
203        .with_id("550e8400-e29b-41d4-a716-446655440006")
204        .add_statement(
205            IAMStatement::new(IAMEffect::Allow)
206                .with_sid("AllowLimitedRequests")
207                .with_action(IAMAction::Single("s3:GetObject".to_string()))
208                .with_resource(IAMResource::Single("*".to_string()))
209                .with_condition(
210                    IAMOperator::NumericLessThan,
211                    "aws:RequestCount".to_string(),
212                    ConditionValue::Number(10),
213                ),
214        );
215
216    let numeric_request = IAMRequest::new_with_context(
217        Principal::Aws(PrincipalId::String(
218            "arn:aws:iam::123456789012:user/alice".to_string(),
219        )),
220        "s3:GetObject",
221        Arn::parse("arn:aws:s3:::any-bucket/file.txt").unwrap(),
222        numeric_context,
223    );
224
225    match evaluate_policy(&numeric_policy, &numeric_request)? {
226        Decision::Allow => println!("✓ Numeric condition satisfied - Access ALLOWED"),
227        Decision::Deny => println!("✗ Access DENIED"),
228        Decision::NotApplicable => println!("? Numeric condition failed"),
229    }
230    println!();
231
232    // Example 8: Detailed Evaluation with Options
233    println!("8. Detailed Evaluation with Options:");
234    let detailed_evaluator = PolicyEvaluator::with_policies(vec![allow_policy.clone()])
235        .with_options(EvaluationOptions {
236            collect_match_details: true,
237            stop_on_explicit_deny: false,
238            max_statements: 100,
239            ignore_resource_constraints: false,
240        });
241
242    let detailed_result = detailed_evaluator.evaluate(&request)?;
243    println!("Decision: {:?}", detailed_result.decision);
244    println!("Matched Statements:");
245    for (i, statement_match) in detailed_result.matched_statements.iter().enumerate() {
246        println!(
247            "  {}. SID: {:?}, Effect: {:?}, Satisfied: {}, Reason: {}",
248            i + 1,
249            statement_match.sid,
250            statement_match.effect,
251            statement_match.conditions_satisfied,
252            statement_match.reason
253        );
254    }
255    println!();
256
257    // Example 9: No Applicable Policy (Implicit Deny)
258    println!("9. No Applicable Policy (Implicit Deny):");
259    let unrelated_request = IAMRequest::new(
260        Principal::Aws(PrincipalId::String(
261            "arn:aws:iam::123456789012:user/alice".to_string(),
262        )),
263        "ec2:DescribeInstances",
264        Arn::parse("arn:aws:ec2:us-east-1:123456789012:instance/*").unwrap(),
265    );
266
267    match evaluate_policy(&allow_policy, &unrelated_request)? {
268        Decision::Allow => println!("✓ Access ALLOWED"),
269        Decision::Deny => println!("✗ Access DENIED"),
270        Decision::NotApplicable => println!("? No applicable policy - Implicit DENY"),
271    }
272    println!();
273
274    // Example 10: Resource Pattern Matching
275    println!("10. Resource Pattern Matching:");
276    let pattern_policy = IAMPolicy::new()
277        .with_id("550e8400-e29b-41d4-a716-446655440007")
278        .add_statement(
279            IAMStatement::new(IAMEffect::Allow)
280                .with_sid("AllowBucketAccess")
281                .with_action(IAMAction::Multiple(vec![
282                    "s3:GetObject".to_string(),
283                    "s3:PutObject".to_string(),
284                ]))
285                .with_resource(IAMResource::Single(
286                    "arn:aws:s3:::user-data-*/*".to_string(),
287                )),
288        );
289
290    let pattern_request = IAMRequest::new(
291        Principal::Aws(PrincipalId::String(
292            "arn:aws:iam::123456789012:user/alice".to_string(),
293        )),
294        "s3:GetObject",
295        Arn::parse("arn:aws:s3:::user-data-alice/profile.json").unwrap(),
296    );
297
298    match evaluate_policy(&pattern_policy, &pattern_request)? {
299        Decision::Allow => println!("✓ Resource pattern matched - Access ALLOWED"),
300        Decision::Deny => println!("✗ Access DENIED"),
301        Decision::NotApplicable => println!("? Resource pattern didn't match"),
302    }
303
304    println!("\n=== Policy Evaluation Demo Complete ===");
305    println!("\nThe Policy Evaluation Engine successfully:");
306    println!("• ✅ Evaluates Allow/Deny effects");
307    println!("• ✅ Handles wildcard actions and resources");
308    println!("• ✅ Processes condition blocks with various operators");
309    println!("• ✅ Implements proper IAM logic (explicit deny overrides)");
310    println!("• ✅ Supports detailed evaluation with match information");
311    println!("• ✅ Handles multiple policies with complex interactions");
312    println!("• ✅ Provides clear Allow/Deny/NotApplicable decisions");
313
314    Ok(())
315}

Trait Implementations§

Source§

impl Clone for IAMRequest

Source§

fn clone(&self) -> IAMRequest

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for IAMRequest

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<'de> Deserialize<'de> for IAMRequest

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl PartialEq for IAMRequest

Source§

fn eq(&self, other: &IAMRequest) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Serialize for IAMRequest

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for IAMRequest

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,