Struct IAMStatement

Source
pub struct IAMStatement {
    pub sid: Option<String>,
    pub effect: Effect,
    pub principal: Option<Principal>,
    pub not_principal: Option<Principal>,
    pub action: Option<Action>,
    pub not_action: Option<Action>,
    pub resource: Option<Resource>,
    pub not_resource: Option<Resource>,
    pub condition: Option<ConditionBlock>,
}
Expand description

Fields§

§sid: Option<String>

Optional statement ID

You can provide a Sid (statement ID) as an optional identifier for the policy statement. You can assign a Sid value to each statement in a statement array. You can use the Sid value as a description for the policy statement.

In services that let you specify an ID element, such as AWS SQS and AWS SNS, the Sid value is just a sub-ID of the policy document ID. In IAM, the Sid value must be unique within a JSON policy.

The Sid element supports ASCII uppercase letters (A-Z), lowercase letters (a-z), and numbers (0-9).

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_sid.html

§effect: Effect

The effect of the statement (Allow or Deny)

The Effect element is required and specifies whether the statement results in an allow or an explicit deny. Valid values for Effect are Allow and Deny. The Effect value is case sensitive.

By default, access to resources is denied. To allow access to a resource, you must set the Effect element to Allow. To override an allow (for example, to override an allow that is otherwise in force), you set the Effect element to Deny.

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_effect.html

§principal: Option<Principal>

Optional principal(s) - who the statement applies to

Use the Principal element in a resource-based JSON policy to specify the principal that is allowed or denied access to a resource.

You must use the Principal element in resource-based policies. You cannot use the Principal element in an identity-based policy.

Identity-based policies are permissions policies that you attach to IAM identities (users, groups, or roles). In those cases, the principal is implicitly the identity where the policy is attached.

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_principal.html

§not_principal: Option<Principal>

Optional not principal(s) - who the statement does not apply to

The NotPrincipal element uses “Effect”:“Deny” to deny access to all principals except the principal specified in the NotPrincipal element. A principal can usually be a user, federated user, role, assumed role, account, service, or other principal type.

NotPrincipal must be used with "Effect":"Deny". Using it with "Effect":"Allow" is not supported.

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notprincipal.html

§action: Option<Action>

Optional action(s) - what actions are allowed/denied

The Action element describes the specific action or actions that will be allowed or denied. Statements must include either an Action or NotAction element. Each service has its own set of actions that describe tasks that you can perform with that service.

For example:

  • the list of actions for Amazon S3 can be found at Specifying Permissions in a Policy in the Amazon Simple Storage Service User Guide
  • the list of actions for Amazon EC2 can be found in the Amazon EC2 API Reference
  • the list of actions for AWS Identity and Access Management can be found in the IAM API Reference

To find the list of actions for other AWS services, consult the API reference documentation for the service. For non-AWS services, consult the service documentation for the actions that are supported by that service.

You specify a value using a service namespace as an action prefix (iam, ec2, sqs, sns, s3, etc.) followed by the name of the action to allow or deny. The name must match an action that is supported by the service. The prefix and the action name are case insensitive. For example, iam:ListAccessKeys is the same as IAM:listaccesskeys.

The following examples show Action elements for different services:

  • Action: "sqs:SendMessage" - allows the SendMessage action on SQS.
  • Action: "ec2:StartInstances" - allows the StartInstances action on EC2.
  • Action: "iam:ChangePassword" - allows the ChangePassword action on IAM.
  • Action: "s3:GetObject" - allows the GetObject action on S3.

You can specify multiple values for the Action element:

  • Action: [ "sqs:SendMessage", "sqs:ReceiveMessage", "ec2:StartInstances", "iam:ChangePassword", "s3:GetObject" ]

You can use wildcards to match multiple actions:

  • Action: "s3:*" - allows all actions on S3.

You can also use wildcards (* or ?) as part of the action name. For example, the following Action element applies to all IAM actions that include the string AccessKey, including CreateAccessKey, DeleteAccessKey, ListAccessKeys, and UpdateAccessKey:

"Action": "iam:*AccessKey*"

Some services let you limit the actions that are available. For example, Amazon SQS lets you make available just a subset of all the possible Amazon SQS actions. In that case, the * wildcard doesn’t allow complete control of the queue; it allows only the subset of actions that you’ve shared.

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_action.html

§not_action: Option<Action>

Optional not action(s) - what actions are not covered

NotAction is an advanced policy element that explicitly matches everything except the specified list of actions. Using NotAction can result in a shorter policy by listing only a few actions that should not match, rather than including a long list of actions that will match.

Actions specified in NotAction are not impacted by the Allow or Deny effect in a policy statement. This, in turn, means that all of the applicable actions or services that are not listed are allowed if you use the Allow effect. In addition, such unlisted actions or services are denied if you use the Deny effect.

When you use NotAction with the Resource element, you provide scope for the policy. This is how AWS determines which actions or services are applicable.

For more information, see the following example policy.

§NotAction with Allow

You can use the NotAction element in a statement with "Effect": "Allow" to provide access to all of the actions in an AWS service, except for the actions specified in NotAction. You can use it with the Resource element to provide scope for the policy, limiting the allowed actions to the actions that can be performed on the specified resource.

Example: Allow all S3 actions except deleting a bucket:

"Effect": "Allow",
"NotAction": "s3:DeleteBucket",
"Resource": "arn:aws:s3:::*"

Example: Allow all actions except IAM:

"Effect": "Allow",
"NotAction": "iam:*",
"Resource": "*"

Be careful using NotAction with "Effect": "Allow" as it could grant more permissions than intended.

§NotAction with Deny

You can use the NotAction element in a statement with "Effect": "Deny" to deny access to all of the listed resources except for the actions specified in NotAction. This combination does not allow the listed items, but instead explicitly denies the actions not listed.

Example: Deny all actions except IAM actions if not using MFA:

{
    "Sid": "DenyAllUsersNotUsingMFA",
    "Effect": "Deny",
    "NotAction": "iam:*",
    "Resource": "*",
    "Condition": {"BoolIfExists": {"aws:MultiFactorAuthPresent": "false"}}
}

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notaction.html

§resource: Option<Resource>

Optional resource(s) - what resources the statement applies to

The Resource element specifies the object(s) that the statement applies to.

You must include either a Resource or a NotResource element in a statement.

You specify a resource using an Amazon Resource Name (ARN). The ARN format depends on the AWS service and the specific resource. For more information about ARNs, see: https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_identifiers.html#identifiers-arns

Some AWS services do not support resource-level permissions. In those cases, use the wildcard character (*) in the Resource element.

Examples:

  • Specific SQS queue: "Resource": "arn:aws:sqs:us-east-2:account-ID-without-hyphens:queue1"
  • Specific IAM user (user name is case sensitive): "Resource": "arn:aws:iam::account-ID-without-hyphens:user/Bob"

§Using wildcards in resource ARNs

You can use wildcard characters (* and ?) within the individual segments of an ARN (the parts separated by colons) to represent:

  • Any combination of characters (*)
  • Any single character (?)

You can use multiple * or ? characters in each segment. If the * wildcard is the last character of a resource ARN segment, it can expand to match beyond the colon boundaries. It is recommended to use wildcards within ARN segments separated by a colon.

Note: You can’t use a wildcard in the service segment that identifies the AWS product.

§Examples

All IAM users whose path is /accounting:

"Resource": "arn:aws:iam::account-ID-without-hyphens:user/accounting/*"

All items within a specific Amazon S3 bucket:

"Resource": "arn:aws:s3:::amzn-s3-demo-bucket/*"

Wildcards can match across slashes and other characters:

"Resource": "arn:aws:s3:::amzn-s3-demo-bucket/*/test/*"

This matches:

  • amzn-s3-demo-bucket/1/test/object.jpg
  • amzn-s3-demo-bucket/1/2/test/object.jpg
  • amzn-s3-demo-bucket/1/2/test/3/object.jpg
  • amzn-s3-demo-bucket/1/2/3/test/4/object.jpg
  • amzn-s3-demo-bucket/1///test///object.jpg
  • amzn-s3-demo-bucket/1/test/.jpg
  • amzn-s3-demo-bucket//test/object.jpg
  • amzn-s3-demo-bucket/1/test/

But does not match:

  • amzn-s3-demo-bucket/1-test/object.jpg
  • amzn-s3-demo-bucket/test/object.jpg
  • amzn-s3-demo-bucket/1/2/test.jpg

§Specifying multiple resources

You can specify multiple resources in the Resource element by using an array of ARNs:

"Resource": [
    "arn:aws:dynamodb:us-east-2:account-ID-without-hyphens:table/books_table",
    "arn:aws:dynamodb:us-east-2:account-ID-without-hyphens:table/magazines_table"
]

§Using policy variables in resource ARNs

You can use JSON policy variables in the part of the ARN that identifies the specific resource. For example:

"Resource": "arn:aws:dynamodb:us-east-2:account-id:table/${aws:username}"

This allows access to a DynamoDB table that matches the current user’s name.

For more information about JSON policy variables, see IAM policy elements: Variables and tags.

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_resource.html

§not_resource: Option<Resource>

Optional not resource(s) - what resources are not covered

NotResource is an advanced policy element that explicitly matches every resource except those specified. Using NotResource can result in a shorter policy by listing only a few resources that should not match, rather than including a long list of resources that will match. This is particularly useful for policies that apply within a single AWS service.

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_notresource.html

§condition: Option<ConditionBlock>

Optional conditions for the statement

The Condition element (or Condition block) lets you specify conditions for when a policy is in effect. The Condition element is optional.

In the Condition element, you build expressions in which you use condition operators (equal, less than, and others) to match the context keys and values in the policy against keys and values in the request context. To learn more about the request context, see Components of a request.

"Condition" : { "{condition-operator}" : { "{condition-key}" : "{condition-value}" }}

The context key that you specify in a policy condition can be a global condition context key or a service-specific context key.

  • Global condition context keys have the aws: prefix.

  • Service-specific context keys have the service’s prefix.

    For example, Amazon EC2 lets you write a condition using the ec2:InstanceType context key, which is unique to that service.

Context key names are not case-sensitive. For example, including the aws:SourceIP context key is equivalent to testing for AWS:SourceIp. Case-sensitivity of context key values depends on the condition operator that you use. For example, the following condition includes the StringEquals operator to make sure that only requests made by john match. Users named John are denied access.

"Condition" : { "StringEquals" : { "aws:username" : "john" }}

The following condition uses the StringEqualsIgnoreCase operator to match users named john or John.

"Condition" : { "StringEqualsIgnoreCase" : { "aws:username" : "john" }}

https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_elements_condition.html

Implementations§

Source§

impl IAMStatement

Source

pub fn new(effect: Effect) -> Self

Creates a new IAM statement with the specified effect

Examples found in repository?
examples/arn_demo.rs (line 84)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("=== IAM ARN Validator Demo ===\n");
5
6    // Example 1: Parse and validate ARNs
7    println!("1. Parsing and validating ARNs:");
8
9    let valid_arns = vec![
10        "arn:aws:s3:::my-bucket/folder/file.txt",
11        "arn:aws:iam::123456789012:user/alice",
12        "arn:aws:ec2:us-east-1:123456789012:instance/i-1234567890abcdef0",
13        "arn:aws:lambda:us-east-1:123456789012:function:MyFunction",
14        "arn:aws:dynamodb:us-east-1:123456789012:table/MyTable",
15        "arn:aws-eu-gov:dynamodb:us-east-1:123456789012:table/MyTable",
16    ];
17
18    for arn_str in &valid_arns {
19        match Arn::parse(arn_str) {
20            Ok(arn) => {
21                println!("✓ Valid ARN: {}", arn);
22                println!("  - Service: {}", arn.service);
23                println!(
24                    "  - Region: {}",
25                    if arn.region.is_empty() {
26                        "global"
27                    } else {
28                        &arn.region
29                    }
30                );
31                println!(
32                    "  - Account: {}",
33                    if arn.account_id.is_empty() {
34                        "none"
35                    } else {
36                        &arn.account_id
37                    }
38                );
39                if let Some(resource_type) = arn.resource_type() {
40                    println!("  - Resource Type: {}", resource_type);
41                }
42                if let Some(resource_id) = arn.resource_id() {
43                    println!("  - Resource ID: {}", resource_id);
44                }
45                println!();
46            }
47            Err(e) => println!("✗ Invalid ARN {}: {}", arn_str, e),
48        }
49    }
50
51    // Example 2: Wildcard matching
52    println!("2. Wildcard pattern matching:");
53
54    let resource_arn = Arn::parse("arn:aws:s3:::my-bucket/uploads/user123/document.pdf")?;
55    println!("Resource ARN: {}", resource_arn);
56
57    let patterns = vec![
58        "arn:aws:s3:::my-bucket/*",
59        "arn:aws:s3:::my-bucket/uploads/*",
60        "arn:aws:s3:::my-bucket/uploads/user123/*",
61        "arn:aws:s3:::*/uploads/user123/document.pdf",
62        "arn:aws:s3:::my-bucket/uploads/*/document.pdf",
63        "arn:aws:s3:::my-bucket/uploads/user???/document.pdf",
64        "arn:aws:s3:::other-bucket/*",
65        "arn:aws:ec2:*:*:instance/*",
66    ];
67
68    for pattern in &patterns {
69        match resource_arn.matches(pattern) {
70            Ok(matches) => {
71                let status = if matches { "✓ MATCH" } else { "✗ NO MATCH" };
72                println!("  {} Pattern: {}", status, pattern);
73            }
74            Err(e) => println!("  ✗ ERROR Pattern: {} ({})", pattern, e),
75        }
76    }
77
78    // Example 3: Integration with IAM policies
79    println!("\n3. Using ARNs in IAM policies:");
80
81    let policy = IAMPolicy::new()
82        .with_id("s3-access-policy")
83        .add_statement(
84            IAMStatement::new(Effect::Allow)
85                .with_sid("AllowS3Read")
86                .with_action(Action::Multiple(vec![
87                    "s3:GetObject".to_string(),
88                    "s3:ListBucket".to_string(),
89                ]))
90                .with_resource(Resource::Multiple(vec![
91                    "arn:aws:s3:::my-bucket".to_string(),
92                    "arn:aws:s3:::my-bucket/*".to_string(),
93                ])),
94        )
95        .add_statement(
96            IAMStatement::new(Effect::Allow)
97                .with_sid("AllowS3Write")
98                .with_action(Action::Single("s3:PutObject".to_string()))
99                .with_resource(Resource::Single(
100                    "arn:aws:s3:::my-bucket/uploads/*".to_string(),
101                )),
102        );
103
104    let policy_json = policy.to_json()?;
105    println!("Generated IAM Policy:");
106    println!("{}", policy_json);
107
108    // Example 4: Validate all ARNs in the policy
109    println!("\n4. Validating ARNs in policy:");
110
111    for (i, statement) in policy.statement.iter().enumerate() {
112        println!(
113            "Statement {}: {}",
114            i + 1,
115            statement.sid.as_ref().unwrap_or(&"(no sid)".to_string())
116        );
117
118        let resources = match &statement.resource {
119            Some(Resource::Single(arn)) => vec![arn.clone()],
120            Some(Resource::Multiple(arns)) => arns.clone(),
121            None => vec![],
122        };
123
124        for resource in resources {
125            match Arn::parse(&resource) {
126                Ok(arn) => {
127                    let validity = if arn.is_valid() {
128                        "✓ Valid"
129                    } else {
130                        "⚠ Invalid"
131                    };
132                    println!("  {} Resource: {}", validity, resource);
133                }
134                Err(e) => println!("  ✗ Parse Error: {} ({})", resource, e),
135            }
136        }
137    }
138
139    Ok(())
140}
More examples
Hide additional examples
examples/validation_demo.rs (line 15)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8    println!("=== IAM Policy Validation Demo ===\n");
9
10    // Example 1: Valid Policy
11    println!("1. Valid Policy Validation:");
12    let valid_policy = IAMPolicy::new()
13        .with_id("550e8400-e29b-41d4-a716-446655440000")
14        .add_statement(
15            IAMStatement::new(Effect::Allow)
16                .with_sid("AllowS3Read")
17                .with_action(Action::Single("s3:GetObject".to_string()))
18                .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string()))
19                .with_condition(
20                    Operator::StringEquals,
21                    "aws:PrincipalTag/department".to_string(),
22                    json!("engineering"),
23                ),
24        );
25
26    if valid_policy.is_valid() {
27        println!("✓ Policy is valid!");
28    } else {
29        println!("✗ Policy is invalid");
30    }
31
32    match valid_policy.validate_result() {
33        Ok(()) => println!("✓ Policy passes validation"),
34        Err(e) => println!("✗ Policy fails validation: {}", e),
35    }
36
37    println!();
38
39    // Example 2: Invalid Policy - Missing Required Fields
40    println!("2. Invalid Policy - Missing Required Fields:");
41    let invalid_policy = IAMPolicy::new().add_statement(IAMStatement::new(Effect::Allow)); // Missing action and resource
42
43    if !invalid_policy.is_valid() {
44        println!("✗ Policy is invalid (as expected)");
45        match invalid_policy.validate_result() {
46            Err(e) => println!("   Validation errors: {}", e),
47            Ok(()) => println!("   Unexpected: validation passed"),
48        }
49    }
50
51    println!();
52
53    // Example 3: Policy with Multiple Validation Errors
54    println!("3. Policy with Multiple Validation Errors:");
55    let multi_error_policy = IAMPolicy::new()
56        .with_id("") // Empty ID
57        .add_statement(
58            IAMStatement::new(Effect::Allow)
59                .with_action(Action::Single("invalid-action".to_string())) // Invalid action format
60                .with_resource(Resource::Single("invalid-resource".to_string())), // Invalid resource
61        )
62        .add_statement(
63            IAMStatement::new(Effect::Allow)
64                .with_sid("DuplicateId")
65                .with_action(Action::Single("s3:GetObject".to_string()))
66                .with_resource(Resource::Single("*".to_string())),
67        )
68        .add_statement(
69            IAMStatement::new(Effect::Deny)
70                .with_sid("DuplicateId") // Duplicate SID
71                .with_action(Action::Single("s3:DeleteObject".to_string()))
72                .with_resource(Resource::Single("*".to_string())),
73        );
74
75    match multi_error_policy.validate_result() {
76        Err(ValidationError::Multiple(errors)) => {
77            println!("✗ Found {} validation errors:", errors.len());
78            for (i, error) in errors.iter().enumerate() {
79                println!("   {}. {}", i + 1, error);
80            }
81        }
82        Err(e) => {
83            println!("✗ Single validation error: {}", e);
84        }
85        Ok(()) => {
86            println!("✓ Unexpected: validation passed");
87        }
88    }
89
90    println!();
91
92    // Example 4: Comprehensive Validation
93    println!("4. Comprehensive Validation:");
94    let comprehensive_policy = IAMPolicy::new()
95        .with_id("short") // Short ID - will fail validation
96        .add_statement(
97            IAMStatement::new(Effect::Allow)
98                .with_action(Action::Single("s3:GetObject".to_string()))
99                .with_resource(Resource::Single("*".to_string()))
100                .with_condition(
101                    Operator::NumericEquals,
102                    "aws:RequestedRegion".to_string(),
103                    json!("not-a-number"), // Numeric operator with string value - will fail
104                ),
105        );
106
107    match comprehensive_policy.validate_result() {
108        Ok(()) => println!("✓ Policy passes validation"),
109        Err(e) => println!("✗ Policy fails validation: {}", e),
110    }
111
112    println!();
113
114    // Example 5: Logical Policy Errors
115    println!("5. Logical Policy Errors:");
116
117    // NotPrincipal with Allow effect (invalid)
118    let mut logical_error_policy = IAMStatement::new(Effect::Allow);
119    logical_error_policy.action = Some(Action::Single("s3:GetObject".to_string()));
120    logical_error_policy.resource = Some(Resource::Single("*".to_string()));
121    let mut principal_map = std::collections::HashMap::new();
122    principal_map.insert(
123        PrincipalType::Aws,
124        serde_json::json!("arn:aws:iam::123456789012:user/test"),
125    );
126    logical_error_policy.not_principal = Some(Principal::Mapped(principal_map));
127
128    match logical_error_policy.validate_result() {
129        Err(e) => println!("✗ Logical error detected: {}", e),
130        Ok(()) => println!("✓ Unexpected: validation passed"),
131    }
132
133    // Both Action and NotAction (invalid)
134    let mut conflicting_statement = IAMStatement::new(Effect::Allow);
135    conflicting_statement.action = Some(Action::Single("s3:GetObject".to_string()));
136    conflicting_statement.not_action = Some(Action::Single("s3:PutObject".to_string()));
137    conflicting_statement.resource = Some(Resource::Single("*".to_string()));
138
139    match conflicting_statement.validate_result() {
140        Err(e) => println!("✗ Logical error detected: {}", e),
141        Ok(()) => println!("✓ Unexpected: validation passed"),
142    }
143
144    println!();
145
146    // Example 6: Component Validation
147    println!("6. Individual Component Validation:");
148
149    // Invalid action
150    let invalid_action = Action::Single("invalid-action".to_string());
151    match invalid_action.validate_result() {
152        Err(e) => println!("✗ Invalid action: {}", e),
153        Ok(()) => println!("✓ Action is valid"),
154    }
155
156    // Invalid principal
157    let mut invalid_map = std::collections::HashMap::new();
158    invalid_map.insert(PrincipalType::Aws, serde_json::json!("invalid-principal"));
159    let invalid_principal = Principal::Mapped(invalid_map);
160    match invalid_principal.validate_result() {
161        Err(e) => println!("✗ Invalid principal: {}", e),
162        Ok(()) => println!("✓ Principal is valid"),
163    }
164
165    // Valid service principal
166    let service_principal = Principal::Mapped(
167        [(PrincipalType::Service, json!("lambda.amazonaws.com"))]
168            .iter()
169            .cloned()
170            .collect(),
171    );
172    if service_principal.is_valid() {
173        println!("✓ Service principal is valid");
174    } else {
175        println!("✗ Service principal is invalid");
176    }
177
178    println!("\n=== Validation Demo Complete ===");
179
180    Ok(())
181}
examples/evaluation_demo.rs (line 15)
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(Effect::Allow)
16                .with_sid("AllowS3Read")
17                .with_action(Action::Single("s3:GetObject".to_string()))
18                .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string())),
19        );
20
21    let request = IAMRequest::new(
22        "arn:aws:iam::123456789012:user/alice",
23        "s3:GetObject",
24        "arn:aws:s3:::my-bucket/file.txt",
25    );
26
27    match evaluate_policy(&allow_policy, &request)? {
28        Decision::Allow => println!("✓ Access ALLOWED"),
29        Decision::Deny => println!("✗ Access DENIED"),
30        Decision::NotApplicable => println!("? No applicable policy (implicit deny)"),
31    }
32    println!();
33
34    // Example 2: Simple Deny Policy
35    println!("2. Simple Deny Policy:");
36    let deny_policy = IAMPolicy::new()
37        .with_id("550e8400-e29b-41d4-a716-446655440001")
38        .add_statement(
39            IAMStatement::new(Effect::Deny)
40                .with_sid("DenyS3Delete")
41                .with_action(Action::Single("s3:DeleteObject".to_string()))
42                .with_resource(Resource::Single(
43                    "arn:aws:s3:::protected-bucket/*".to_string(),
44                )),
45        );
46
47    let delete_request = IAMRequest::new(
48        "arn:aws:iam::123456789012:user/alice",
49        "s3:DeleteObject",
50        "arn:aws:s3:::protected-bucket/important.txt",
51    );
52
53    match evaluate_policy(&deny_policy, &delete_request)? {
54        Decision::Allow => println!("✓ Access ALLOWED"),
55        Decision::Deny => println!("✗ Access DENIED"),
56        Decision::NotApplicable => println!("? No applicable policy (implicit deny)"),
57    }
58    println!();
59
60    // Example 3: Wildcard Action Matching
61    println!("3. Wildcard Action Matching:");
62    let wildcard_policy = IAMPolicy::new()
63        .with_id("550e8400-e29b-41d4-a716-446655440002")
64        .add_statement(
65            IAMStatement::new(Effect::Allow)
66                .with_sid("AllowAllS3")
67                .with_action(Action::Single("s3:*".to_string()))
68                .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string())),
69        );
70
71    let wildcard_request = IAMRequest::new(
72        "arn:aws:iam::123456789012:user/alice",
73        "s3:PutObject",
74        "arn:aws:s3:::my-bucket/new-file.txt",
75    );
76
77    match evaluate_policy(&wildcard_policy, &wildcard_request)? {
78        Decision::Allow => println!("✓ Wildcard action matched - Access ALLOWED"),
79        Decision::Deny => println!("✗ Access DENIED"),
80        Decision::NotApplicable => println!("? No applicable policy"),
81    }
82    println!();
83
84    // Example 4: Condition-Based Policy
85    println!("4. Condition-Based Policy:");
86    let mut context = Context::new();
87    context.insert(
88        "aws:userid".to_string(),
89        ContextValue::String("alice".to_string()),
90    );
91    context.insert(
92        "aws:CurrentTime".to_string(),
93        ContextValue::String("2024-01-15T10:00:00Z".to_string()),
94    );
95
96    let condition_policy = IAMPolicy::new()
97        .with_id("550e8400-e29b-41d4-a716-446655440003")
98        .add_statement(
99            IAMStatement::new(Effect::Allow)
100                .with_sid("AllowWithCondition")
101                .with_action(Action::Single("s3:GetObject".to_string()))
102                .with_resource(Resource::Single(
103                    "arn:aws:s3:::private-bucket/*".to_string(),
104                ))
105                .with_condition(
106                    Operator::StringEquals,
107                    "aws:userid".to_string(),
108                    json!("alice"),
109                ),
110        );
111
112    let condition_request = IAMRequest::new_with_context(
113        "arn:aws:iam::123456789012:user/alice",
114        "s3:GetObject",
115        "arn:aws:s3:::private-bucket/personal.txt",
116        context,
117    );
118
119    match evaluate_policy(&condition_policy, &condition_request)? {
120        Decision::Allow => println!("✓ Condition satisfied - Access ALLOWED"),
121        Decision::Deny => println!("✗ Access DENIED"),
122        Decision::NotApplicable => println!("? Condition not satisfied"),
123    }
124    println!();
125
126    // Example 5: Failed Condition
127    println!("5. Failed Condition:");
128    let mut wrong_context = Context::new();
129    wrong_context.insert(
130        "aws:userid".to_string(),
131        ContextValue::String("bob".to_string()),
132    );
133
134    let failed_condition_request = IAMRequest::new_with_context(
135        "arn:aws:iam::123456789012:user/bob",
136        "s3:GetObject",
137        "arn:aws:s3:::private-bucket/personal.txt",
138        wrong_context,
139    );
140
141    match evaluate_policy(&condition_policy, &failed_condition_request)? {
142        Decision::Allow => println!("✓ Access ALLOWED"),
143        Decision::Deny => println!("✗ Access DENIED"),
144        Decision::NotApplicable => println!("? Condition failed - No applicable policy"),
145    }
146    println!();
147
148    // Example 6: Explicit Deny Overrides Allow
149    println!("6. Explicit Deny Overrides Allow:");
150    let combined_policies = vec![
151        IAMPolicy::new()
152            .with_id("550e8400-e29b-41d4-a716-446655440004")
153            .add_statement(
154                IAMStatement::new(Effect::Allow)
155                    .with_sid("AllowAll")
156                    .with_action(Action::Single("s3:*".to_string()))
157                    .with_resource(Resource::Single("*".to_string())),
158            ),
159        IAMPolicy::new()
160            .with_id("550e8400-e29b-41d4-a716-446655440005")
161            .add_statement(
162                IAMStatement::new(Effect::Deny)
163                    .with_sid("DenyProtected")
164                    .with_action(Action::Single("s3:DeleteObject".to_string()))
165                    .with_resource(Resource::Single(
166                        "arn:aws:s3:::protected-bucket/*".to_string(),
167                    )),
168            ),
169    ];
170
171    let evaluator = PolicyEvaluator::with_policies(combined_policies);
172    let protected_request = IAMRequest::new(
173        "arn:aws:iam::123456789012:user/alice",
174        "s3:DeleteObject",
175        "arn:aws:s3:::protected-bucket/critical.txt",
176    );
177
178    match evaluator.evaluate(&protected_request)?.decision {
179        Decision::Allow => println!("✓ Access ALLOWED"),
180        Decision::Deny => println!("✗ Explicit DENY overrides Allow"),
181        Decision::NotApplicable => println!("? No applicable policy"),
182    }
183    println!();
184
185    // Example 7: Numeric Condition
186    println!("7. Numeric Condition:");
187    let mut numeric_context = Context::new();
188    numeric_context.insert("aws:RequestCount".to_string(), ContextValue::Number(5.0));
189
190    let numeric_policy = IAMPolicy::new()
191        .with_id("550e8400-e29b-41d4-a716-446655440006")
192        .add_statement(
193            IAMStatement::new(Effect::Allow)
194                .with_sid("AllowLimitedRequests")
195                .with_action(Action::Single("s3:GetObject".to_string()))
196                .with_resource(Resource::Single("*".to_string()))
197                .with_condition(
198                    Operator::NumericLessThan,
199                    "aws:RequestCount".to_string(),
200                    json!(10),
201                ),
202        );
203
204    let numeric_request = IAMRequest::new_with_context(
205        "arn:aws:iam::123456789012:user/alice",
206        "s3:GetObject",
207        "arn:aws:s3:::any-bucket/file.txt",
208        numeric_context,
209    );
210
211    match evaluate_policy(&numeric_policy, &numeric_request)? {
212        Decision::Allow => println!("✓ Numeric condition satisfied - Access ALLOWED"),
213        Decision::Deny => println!("✗ Access DENIED"),
214        Decision::NotApplicable => println!("? Numeric condition failed"),
215    }
216    println!();
217
218    // Example 8: Detailed Evaluation with Options
219    println!("8. Detailed Evaluation with Options:");
220    let detailed_evaluator = PolicyEvaluator::with_policies(vec![allow_policy.clone()])
221        .with_options(EvaluationOptions {
222            collect_match_details: true,
223            stop_on_explicit_deny: false,
224            max_statements: 100,
225        });
226
227    let detailed_result = detailed_evaluator.evaluate(&request)?;
228    println!("Decision: {:?}", detailed_result.decision);
229    println!("Matched Statements:");
230    for (i, statement_match) in detailed_result.matched_statements.iter().enumerate() {
231        println!(
232            "  {}. SID: {:?}, Effect: {:?}, Satisfied: {}, Reason: {}",
233            i + 1,
234            statement_match.sid,
235            statement_match.effect,
236            statement_match.conditions_satisfied,
237            statement_match.reason
238        );
239    }
240    println!();
241
242    // Example 9: No Applicable Policy (Implicit Deny)
243    println!("9. No Applicable Policy (Implicit Deny):");
244    let unrelated_request = IAMRequest::new(
245        "arn:aws:iam::123456789012:user/alice",
246        "ec2:DescribeInstances",
247        "arn:aws:ec2:us-east-1:123456789012:instance/*",
248    );
249
250    match evaluate_policy(&allow_policy, &unrelated_request)? {
251        Decision::Allow => println!("✓ Access ALLOWED"),
252        Decision::Deny => println!("✗ Access DENIED"),
253        Decision::NotApplicable => println!("? No applicable policy - Implicit DENY"),
254    }
255    println!();
256
257    // Example 10: Resource Pattern Matching
258    println!("10. Resource Pattern Matching:");
259    let pattern_policy = IAMPolicy::new()
260        .with_id("550e8400-e29b-41d4-a716-446655440007")
261        .add_statement(
262            IAMStatement::new(Effect::Allow)
263                .with_sid("AllowBucketAccess")
264                .with_action(Action::Multiple(vec![
265                    "s3:GetObject".to_string(),
266                    "s3:PutObject".to_string(),
267                ]))
268                .with_resource(Resource::Single("arn:aws:s3:::user-data-*/*".to_string())),
269        );
270
271    let pattern_request = IAMRequest::new(
272        "arn:aws:iam::123456789012:user/alice",
273        "s3:GetObject",
274        "arn:aws:s3:::user-data-alice/profile.json",
275    );
276
277    match evaluate_policy(&pattern_policy, &pattern_request)? {
278        Decision::Allow => println!("✓ Resource pattern matched - Access ALLOWED"),
279        Decision::Deny => println!("✗ Access DENIED"),
280        Decision::NotApplicable => println!("? Resource pattern didn't match"),
281    }
282
283    println!("\n=== Policy Evaluation Demo Complete ===");
284    println!("\nThe Policy Evaluation Engine successfully:");
285    println!("• ✅ Evaluates Allow/Deny effects");
286    println!("• ✅ Handles wildcard actions and resources");
287    println!("• ✅ Processes condition blocks with various operators");
288    println!("• ✅ Implements proper IAM logic (explicit deny overrides)");
289    println!("• ✅ Supports detailed evaluation with match information");
290    println!("• ✅ Handles multiple policies with complex interactions");
291    println!("• ✅ Provides clear Allow/Deny/NotApplicable decisions");
292
293    Ok(())
294}
Source

pub fn with_sid<S: Into<String>>(self, sid: S) -> Self

Sets the statement ID

Examples found in repository?
examples/arn_demo.rs (line 85)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("=== IAM ARN Validator Demo ===\n");
5
6    // Example 1: Parse and validate ARNs
7    println!("1. Parsing and validating ARNs:");
8
9    let valid_arns = vec![
10        "arn:aws:s3:::my-bucket/folder/file.txt",
11        "arn:aws:iam::123456789012:user/alice",
12        "arn:aws:ec2:us-east-1:123456789012:instance/i-1234567890abcdef0",
13        "arn:aws:lambda:us-east-1:123456789012:function:MyFunction",
14        "arn:aws:dynamodb:us-east-1:123456789012:table/MyTable",
15        "arn:aws-eu-gov:dynamodb:us-east-1:123456789012:table/MyTable",
16    ];
17
18    for arn_str in &valid_arns {
19        match Arn::parse(arn_str) {
20            Ok(arn) => {
21                println!("✓ Valid ARN: {}", arn);
22                println!("  - Service: {}", arn.service);
23                println!(
24                    "  - Region: {}",
25                    if arn.region.is_empty() {
26                        "global"
27                    } else {
28                        &arn.region
29                    }
30                );
31                println!(
32                    "  - Account: {}",
33                    if arn.account_id.is_empty() {
34                        "none"
35                    } else {
36                        &arn.account_id
37                    }
38                );
39                if let Some(resource_type) = arn.resource_type() {
40                    println!("  - Resource Type: {}", resource_type);
41                }
42                if let Some(resource_id) = arn.resource_id() {
43                    println!("  - Resource ID: {}", resource_id);
44                }
45                println!();
46            }
47            Err(e) => println!("✗ Invalid ARN {}: {}", arn_str, e),
48        }
49    }
50
51    // Example 2: Wildcard matching
52    println!("2. Wildcard pattern matching:");
53
54    let resource_arn = Arn::parse("arn:aws:s3:::my-bucket/uploads/user123/document.pdf")?;
55    println!("Resource ARN: {}", resource_arn);
56
57    let patterns = vec![
58        "arn:aws:s3:::my-bucket/*",
59        "arn:aws:s3:::my-bucket/uploads/*",
60        "arn:aws:s3:::my-bucket/uploads/user123/*",
61        "arn:aws:s3:::*/uploads/user123/document.pdf",
62        "arn:aws:s3:::my-bucket/uploads/*/document.pdf",
63        "arn:aws:s3:::my-bucket/uploads/user???/document.pdf",
64        "arn:aws:s3:::other-bucket/*",
65        "arn:aws:ec2:*:*:instance/*",
66    ];
67
68    for pattern in &patterns {
69        match resource_arn.matches(pattern) {
70            Ok(matches) => {
71                let status = if matches { "✓ MATCH" } else { "✗ NO MATCH" };
72                println!("  {} Pattern: {}", status, pattern);
73            }
74            Err(e) => println!("  ✗ ERROR Pattern: {} ({})", pattern, e),
75        }
76    }
77
78    // Example 3: Integration with IAM policies
79    println!("\n3. Using ARNs in IAM policies:");
80
81    let policy = IAMPolicy::new()
82        .with_id("s3-access-policy")
83        .add_statement(
84            IAMStatement::new(Effect::Allow)
85                .with_sid("AllowS3Read")
86                .with_action(Action::Multiple(vec![
87                    "s3:GetObject".to_string(),
88                    "s3:ListBucket".to_string(),
89                ]))
90                .with_resource(Resource::Multiple(vec![
91                    "arn:aws:s3:::my-bucket".to_string(),
92                    "arn:aws:s3:::my-bucket/*".to_string(),
93                ])),
94        )
95        .add_statement(
96            IAMStatement::new(Effect::Allow)
97                .with_sid("AllowS3Write")
98                .with_action(Action::Single("s3:PutObject".to_string()))
99                .with_resource(Resource::Single(
100                    "arn:aws:s3:::my-bucket/uploads/*".to_string(),
101                )),
102        );
103
104    let policy_json = policy.to_json()?;
105    println!("Generated IAM Policy:");
106    println!("{}", policy_json);
107
108    // Example 4: Validate all ARNs in the policy
109    println!("\n4. Validating ARNs in policy:");
110
111    for (i, statement) in policy.statement.iter().enumerate() {
112        println!(
113            "Statement {}: {}",
114            i + 1,
115            statement.sid.as_ref().unwrap_or(&"(no sid)".to_string())
116        );
117
118        let resources = match &statement.resource {
119            Some(Resource::Single(arn)) => vec![arn.clone()],
120            Some(Resource::Multiple(arns)) => arns.clone(),
121            None => vec![],
122        };
123
124        for resource in resources {
125            match Arn::parse(&resource) {
126                Ok(arn) => {
127                    let validity = if arn.is_valid() {
128                        "✓ Valid"
129                    } else {
130                        "⚠ Invalid"
131                    };
132                    println!("  {} Resource: {}", validity, resource);
133                }
134                Err(e) => println!("  ✗ Parse Error: {} ({})", resource, e),
135            }
136        }
137    }
138
139    Ok(())
140}
More examples
Hide additional examples
examples/validation_demo.rs (line 16)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8    println!("=== IAM Policy Validation Demo ===\n");
9
10    // Example 1: Valid Policy
11    println!("1. Valid Policy Validation:");
12    let valid_policy = IAMPolicy::new()
13        .with_id("550e8400-e29b-41d4-a716-446655440000")
14        .add_statement(
15            IAMStatement::new(Effect::Allow)
16                .with_sid("AllowS3Read")
17                .with_action(Action::Single("s3:GetObject".to_string()))
18                .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string()))
19                .with_condition(
20                    Operator::StringEquals,
21                    "aws:PrincipalTag/department".to_string(),
22                    json!("engineering"),
23                ),
24        );
25
26    if valid_policy.is_valid() {
27        println!("✓ Policy is valid!");
28    } else {
29        println!("✗ Policy is invalid");
30    }
31
32    match valid_policy.validate_result() {
33        Ok(()) => println!("✓ Policy passes validation"),
34        Err(e) => println!("✗ Policy fails validation: {}", e),
35    }
36
37    println!();
38
39    // Example 2: Invalid Policy - Missing Required Fields
40    println!("2. Invalid Policy - Missing Required Fields:");
41    let invalid_policy = IAMPolicy::new().add_statement(IAMStatement::new(Effect::Allow)); // Missing action and resource
42
43    if !invalid_policy.is_valid() {
44        println!("✗ Policy is invalid (as expected)");
45        match invalid_policy.validate_result() {
46            Err(e) => println!("   Validation errors: {}", e),
47            Ok(()) => println!("   Unexpected: validation passed"),
48        }
49    }
50
51    println!();
52
53    // Example 3: Policy with Multiple Validation Errors
54    println!("3. Policy with Multiple Validation Errors:");
55    let multi_error_policy = IAMPolicy::new()
56        .with_id("") // Empty ID
57        .add_statement(
58            IAMStatement::new(Effect::Allow)
59                .with_action(Action::Single("invalid-action".to_string())) // Invalid action format
60                .with_resource(Resource::Single("invalid-resource".to_string())), // Invalid resource
61        )
62        .add_statement(
63            IAMStatement::new(Effect::Allow)
64                .with_sid("DuplicateId")
65                .with_action(Action::Single("s3:GetObject".to_string()))
66                .with_resource(Resource::Single("*".to_string())),
67        )
68        .add_statement(
69            IAMStatement::new(Effect::Deny)
70                .with_sid("DuplicateId") // Duplicate SID
71                .with_action(Action::Single("s3:DeleteObject".to_string()))
72                .with_resource(Resource::Single("*".to_string())),
73        );
74
75    match multi_error_policy.validate_result() {
76        Err(ValidationError::Multiple(errors)) => {
77            println!("✗ Found {} validation errors:", errors.len());
78            for (i, error) in errors.iter().enumerate() {
79                println!("   {}. {}", i + 1, error);
80            }
81        }
82        Err(e) => {
83            println!("✗ Single validation error: {}", e);
84        }
85        Ok(()) => {
86            println!("✓ Unexpected: validation passed");
87        }
88    }
89
90    println!();
91
92    // Example 4: Comprehensive Validation
93    println!("4. Comprehensive Validation:");
94    let comprehensive_policy = IAMPolicy::new()
95        .with_id("short") // Short ID - will fail validation
96        .add_statement(
97            IAMStatement::new(Effect::Allow)
98                .with_action(Action::Single("s3:GetObject".to_string()))
99                .with_resource(Resource::Single("*".to_string()))
100                .with_condition(
101                    Operator::NumericEquals,
102                    "aws:RequestedRegion".to_string(),
103                    json!("not-a-number"), // Numeric operator with string value - will fail
104                ),
105        );
106
107    match comprehensive_policy.validate_result() {
108        Ok(()) => println!("✓ Policy passes validation"),
109        Err(e) => println!("✗ Policy fails validation: {}", e),
110    }
111
112    println!();
113
114    // Example 5: Logical Policy Errors
115    println!("5. Logical Policy Errors:");
116
117    // NotPrincipal with Allow effect (invalid)
118    let mut logical_error_policy = IAMStatement::new(Effect::Allow);
119    logical_error_policy.action = Some(Action::Single("s3:GetObject".to_string()));
120    logical_error_policy.resource = Some(Resource::Single("*".to_string()));
121    let mut principal_map = std::collections::HashMap::new();
122    principal_map.insert(
123        PrincipalType::Aws,
124        serde_json::json!("arn:aws:iam::123456789012:user/test"),
125    );
126    logical_error_policy.not_principal = Some(Principal::Mapped(principal_map));
127
128    match logical_error_policy.validate_result() {
129        Err(e) => println!("✗ Logical error detected: {}", e),
130        Ok(()) => println!("✓ Unexpected: validation passed"),
131    }
132
133    // Both Action and NotAction (invalid)
134    let mut conflicting_statement = IAMStatement::new(Effect::Allow);
135    conflicting_statement.action = Some(Action::Single("s3:GetObject".to_string()));
136    conflicting_statement.not_action = Some(Action::Single("s3:PutObject".to_string()));
137    conflicting_statement.resource = Some(Resource::Single("*".to_string()));
138
139    match conflicting_statement.validate_result() {
140        Err(e) => println!("✗ Logical error detected: {}", e),
141        Ok(()) => println!("✓ Unexpected: validation passed"),
142    }
143
144    println!();
145
146    // Example 6: Component Validation
147    println!("6. Individual Component Validation:");
148
149    // Invalid action
150    let invalid_action = Action::Single("invalid-action".to_string());
151    match invalid_action.validate_result() {
152        Err(e) => println!("✗ Invalid action: {}", e),
153        Ok(()) => println!("✓ Action is valid"),
154    }
155
156    // Invalid principal
157    let mut invalid_map = std::collections::HashMap::new();
158    invalid_map.insert(PrincipalType::Aws, serde_json::json!("invalid-principal"));
159    let invalid_principal = Principal::Mapped(invalid_map);
160    match invalid_principal.validate_result() {
161        Err(e) => println!("✗ Invalid principal: {}", e),
162        Ok(()) => println!("✓ Principal is valid"),
163    }
164
165    // Valid service principal
166    let service_principal = Principal::Mapped(
167        [(PrincipalType::Service, json!("lambda.amazonaws.com"))]
168            .iter()
169            .cloned()
170            .collect(),
171    );
172    if service_principal.is_valid() {
173        println!("✓ Service principal is valid");
174    } else {
175        println!("✗ Service principal is invalid");
176    }
177
178    println!("\n=== Validation Demo Complete ===");
179
180    Ok(())
181}
examples/evaluation_demo.rs (line 16)
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(Effect::Allow)
16                .with_sid("AllowS3Read")
17                .with_action(Action::Single("s3:GetObject".to_string()))
18                .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string())),
19        );
20
21    let request = IAMRequest::new(
22        "arn:aws:iam::123456789012:user/alice",
23        "s3:GetObject",
24        "arn:aws:s3:::my-bucket/file.txt",
25    );
26
27    match evaluate_policy(&allow_policy, &request)? {
28        Decision::Allow => println!("✓ Access ALLOWED"),
29        Decision::Deny => println!("✗ Access DENIED"),
30        Decision::NotApplicable => println!("? No applicable policy (implicit deny)"),
31    }
32    println!();
33
34    // Example 2: Simple Deny Policy
35    println!("2. Simple Deny Policy:");
36    let deny_policy = IAMPolicy::new()
37        .with_id("550e8400-e29b-41d4-a716-446655440001")
38        .add_statement(
39            IAMStatement::new(Effect::Deny)
40                .with_sid("DenyS3Delete")
41                .with_action(Action::Single("s3:DeleteObject".to_string()))
42                .with_resource(Resource::Single(
43                    "arn:aws:s3:::protected-bucket/*".to_string(),
44                )),
45        );
46
47    let delete_request = IAMRequest::new(
48        "arn:aws:iam::123456789012:user/alice",
49        "s3:DeleteObject",
50        "arn:aws:s3:::protected-bucket/important.txt",
51    );
52
53    match evaluate_policy(&deny_policy, &delete_request)? {
54        Decision::Allow => println!("✓ Access ALLOWED"),
55        Decision::Deny => println!("✗ Access DENIED"),
56        Decision::NotApplicable => println!("? No applicable policy (implicit deny)"),
57    }
58    println!();
59
60    // Example 3: Wildcard Action Matching
61    println!("3. Wildcard Action Matching:");
62    let wildcard_policy = IAMPolicy::new()
63        .with_id("550e8400-e29b-41d4-a716-446655440002")
64        .add_statement(
65            IAMStatement::new(Effect::Allow)
66                .with_sid("AllowAllS3")
67                .with_action(Action::Single("s3:*".to_string()))
68                .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string())),
69        );
70
71    let wildcard_request = IAMRequest::new(
72        "arn:aws:iam::123456789012:user/alice",
73        "s3:PutObject",
74        "arn:aws:s3:::my-bucket/new-file.txt",
75    );
76
77    match evaluate_policy(&wildcard_policy, &wildcard_request)? {
78        Decision::Allow => println!("✓ Wildcard action matched - Access ALLOWED"),
79        Decision::Deny => println!("✗ Access DENIED"),
80        Decision::NotApplicable => println!("? No applicable policy"),
81    }
82    println!();
83
84    // Example 4: Condition-Based Policy
85    println!("4. Condition-Based Policy:");
86    let mut context = Context::new();
87    context.insert(
88        "aws:userid".to_string(),
89        ContextValue::String("alice".to_string()),
90    );
91    context.insert(
92        "aws:CurrentTime".to_string(),
93        ContextValue::String("2024-01-15T10:00:00Z".to_string()),
94    );
95
96    let condition_policy = IAMPolicy::new()
97        .with_id("550e8400-e29b-41d4-a716-446655440003")
98        .add_statement(
99            IAMStatement::new(Effect::Allow)
100                .with_sid("AllowWithCondition")
101                .with_action(Action::Single("s3:GetObject".to_string()))
102                .with_resource(Resource::Single(
103                    "arn:aws:s3:::private-bucket/*".to_string(),
104                ))
105                .with_condition(
106                    Operator::StringEquals,
107                    "aws:userid".to_string(),
108                    json!("alice"),
109                ),
110        );
111
112    let condition_request = IAMRequest::new_with_context(
113        "arn:aws:iam::123456789012:user/alice",
114        "s3:GetObject",
115        "arn:aws:s3:::private-bucket/personal.txt",
116        context,
117    );
118
119    match evaluate_policy(&condition_policy, &condition_request)? {
120        Decision::Allow => println!("✓ Condition satisfied - Access ALLOWED"),
121        Decision::Deny => println!("✗ Access DENIED"),
122        Decision::NotApplicable => println!("? Condition not satisfied"),
123    }
124    println!();
125
126    // Example 5: Failed Condition
127    println!("5. Failed Condition:");
128    let mut wrong_context = Context::new();
129    wrong_context.insert(
130        "aws:userid".to_string(),
131        ContextValue::String("bob".to_string()),
132    );
133
134    let failed_condition_request = IAMRequest::new_with_context(
135        "arn:aws:iam::123456789012:user/bob",
136        "s3:GetObject",
137        "arn:aws:s3:::private-bucket/personal.txt",
138        wrong_context,
139    );
140
141    match evaluate_policy(&condition_policy, &failed_condition_request)? {
142        Decision::Allow => println!("✓ Access ALLOWED"),
143        Decision::Deny => println!("✗ Access DENIED"),
144        Decision::NotApplicable => println!("? Condition failed - No applicable policy"),
145    }
146    println!();
147
148    // Example 6: Explicit Deny Overrides Allow
149    println!("6. Explicit Deny Overrides Allow:");
150    let combined_policies = vec![
151        IAMPolicy::new()
152            .with_id("550e8400-e29b-41d4-a716-446655440004")
153            .add_statement(
154                IAMStatement::new(Effect::Allow)
155                    .with_sid("AllowAll")
156                    .with_action(Action::Single("s3:*".to_string()))
157                    .with_resource(Resource::Single("*".to_string())),
158            ),
159        IAMPolicy::new()
160            .with_id("550e8400-e29b-41d4-a716-446655440005")
161            .add_statement(
162                IAMStatement::new(Effect::Deny)
163                    .with_sid("DenyProtected")
164                    .with_action(Action::Single("s3:DeleteObject".to_string()))
165                    .with_resource(Resource::Single(
166                        "arn:aws:s3:::protected-bucket/*".to_string(),
167                    )),
168            ),
169    ];
170
171    let evaluator = PolicyEvaluator::with_policies(combined_policies);
172    let protected_request = IAMRequest::new(
173        "arn:aws:iam::123456789012:user/alice",
174        "s3:DeleteObject",
175        "arn:aws:s3:::protected-bucket/critical.txt",
176    );
177
178    match evaluator.evaluate(&protected_request)?.decision {
179        Decision::Allow => println!("✓ Access ALLOWED"),
180        Decision::Deny => println!("✗ Explicit DENY overrides Allow"),
181        Decision::NotApplicable => println!("? No applicable policy"),
182    }
183    println!();
184
185    // Example 7: Numeric Condition
186    println!("7. Numeric Condition:");
187    let mut numeric_context = Context::new();
188    numeric_context.insert("aws:RequestCount".to_string(), ContextValue::Number(5.0));
189
190    let numeric_policy = IAMPolicy::new()
191        .with_id("550e8400-e29b-41d4-a716-446655440006")
192        .add_statement(
193            IAMStatement::new(Effect::Allow)
194                .with_sid("AllowLimitedRequests")
195                .with_action(Action::Single("s3:GetObject".to_string()))
196                .with_resource(Resource::Single("*".to_string()))
197                .with_condition(
198                    Operator::NumericLessThan,
199                    "aws:RequestCount".to_string(),
200                    json!(10),
201                ),
202        );
203
204    let numeric_request = IAMRequest::new_with_context(
205        "arn:aws:iam::123456789012:user/alice",
206        "s3:GetObject",
207        "arn:aws:s3:::any-bucket/file.txt",
208        numeric_context,
209    );
210
211    match evaluate_policy(&numeric_policy, &numeric_request)? {
212        Decision::Allow => println!("✓ Numeric condition satisfied - Access ALLOWED"),
213        Decision::Deny => println!("✗ Access DENIED"),
214        Decision::NotApplicable => println!("? Numeric condition failed"),
215    }
216    println!();
217
218    // Example 8: Detailed Evaluation with Options
219    println!("8. Detailed Evaluation with Options:");
220    let detailed_evaluator = PolicyEvaluator::with_policies(vec![allow_policy.clone()])
221        .with_options(EvaluationOptions {
222            collect_match_details: true,
223            stop_on_explicit_deny: false,
224            max_statements: 100,
225        });
226
227    let detailed_result = detailed_evaluator.evaluate(&request)?;
228    println!("Decision: {:?}", detailed_result.decision);
229    println!("Matched Statements:");
230    for (i, statement_match) in detailed_result.matched_statements.iter().enumerate() {
231        println!(
232            "  {}. SID: {:?}, Effect: {:?}, Satisfied: {}, Reason: {}",
233            i + 1,
234            statement_match.sid,
235            statement_match.effect,
236            statement_match.conditions_satisfied,
237            statement_match.reason
238        );
239    }
240    println!();
241
242    // Example 9: No Applicable Policy (Implicit Deny)
243    println!("9. No Applicable Policy (Implicit Deny):");
244    let unrelated_request = IAMRequest::new(
245        "arn:aws:iam::123456789012:user/alice",
246        "ec2:DescribeInstances",
247        "arn:aws:ec2:us-east-1:123456789012:instance/*",
248    );
249
250    match evaluate_policy(&allow_policy, &unrelated_request)? {
251        Decision::Allow => println!("✓ Access ALLOWED"),
252        Decision::Deny => println!("✗ Access DENIED"),
253        Decision::NotApplicable => println!("? No applicable policy - Implicit DENY"),
254    }
255    println!();
256
257    // Example 10: Resource Pattern Matching
258    println!("10. Resource Pattern Matching:");
259    let pattern_policy = IAMPolicy::new()
260        .with_id("550e8400-e29b-41d4-a716-446655440007")
261        .add_statement(
262            IAMStatement::new(Effect::Allow)
263                .with_sid("AllowBucketAccess")
264                .with_action(Action::Multiple(vec![
265                    "s3:GetObject".to_string(),
266                    "s3:PutObject".to_string(),
267                ]))
268                .with_resource(Resource::Single("arn:aws:s3:::user-data-*/*".to_string())),
269        );
270
271    let pattern_request = IAMRequest::new(
272        "arn:aws:iam::123456789012:user/alice",
273        "s3:GetObject",
274        "arn:aws:s3:::user-data-alice/profile.json",
275    );
276
277    match evaluate_policy(&pattern_policy, &pattern_request)? {
278        Decision::Allow => println!("✓ Resource pattern matched - Access ALLOWED"),
279        Decision::Deny => println!("✗ Access DENIED"),
280        Decision::NotApplicable => println!("? Resource pattern didn't match"),
281    }
282
283    println!("\n=== Policy Evaluation Demo Complete ===");
284    println!("\nThe Policy Evaluation Engine successfully:");
285    println!("• ✅ Evaluates Allow/Deny effects");
286    println!("• ✅ Handles wildcard actions and resources");
287    println!("• ✅ Processes condition blocks with various operators");
288    println!("• ✅ Implements proper IAM logic (explicit deny overrides)");
289    println!("• ✅ Supports detailed evaluation with match information");
290    println!("• ✅ Handles multiple policies with complex interactions");
291    println!("• ✅ Provides clear Allow/Deny/NotApplicable decisions");
292
293    Ok(())
294}
Source

pub fn with_principal(self, principal: Principal) -> Self

Sets the principal

Source

pub fn with_action(self, action: Action) -> Self

Sets the action

Examples found in repository?
examples/arn_demo.rs (lines 86-89)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("=== IAM ARN Validator Demo ===\n");
5
6    // Example 1: Parse and validate ARNs
7    println!("1. Parsing and validating ARNs:");
8
9    let valid_arns = vec![
10        "arn:aws:s3:::my-bucket/folder/file.txt",
11        "arn:aws:iam::123456789012:user/alice",
12        "arn:aws:ec2:us-east-1:123456789012:instance/i-1234567890abcdef0",
13        "arn:aws:lambda:us-east-1:123456789012:function:MyFunction",
14        "arn:aws:dynamodb:us-east-1:123456789012:table/MyTable",
15        "arn:aws-eu-gov:dynamodb:us-east-1:123456789012:table/MyTable",
16    ];
17
18    for arn_str in &valid_arns {
19        match Arn::parse(arn_str) {
20            Ok(arn) => {
21                println!("✓ Valid ARN: {}", arn);
22                println!("  - Service: {}", arn.service);
23                println!(
24                    "  - Region: {}",
25                    if arn.region.is_empty() {
26                        "global"
27                    } else {
28                        &arn.region
29                    }
30                );
31                println!(
32                    "  - Account: {}",
33                    if arn.account_id.is_empty() {
34                        "none"
35                    } else {
36                        &arn.account_id
37                    }
38                );
39                if let Some(resource_type) = arn.resource_type() {
40                    println!("  - Resource Type: {}", resource_type);
41                }
42                if let Some(resource_id) = arn.resource_id() {
43                    println!("  - Resource ID: {}", resource_id);
44                }
45                println!();
46            }
47            Err(e) => println!("✗ Invalid ARN {}: {}", arn_str, e),
48        }
49    }
50
51    // Example 2: Wildcard matching
52    println!("2. Wildcard pattern matching:");
53
54    let resource_arn = Arn::parse("arn:aws:s3:::my-bucket/uploads/user123/document.pdf")?;
55    println!("Resource ARN: {}", resource_arn);
56
57    let patterns = vec![
58        "arn:aws:s3:::my-bucket/*",
59        "arn:aws:s3:::my-bucket/uploads/*",
60        "arn:aws:s3:::my-bucket/uploads/user123/*",
61        "arn:aws:s3:::*/uploads/user123/document.pdf",
62        "arn:aws:s3:::my-bucket/uploads/*/document.pdf",
63        "arn:aws:s3:::my-bucket/uploads/user???/document.pdf",
64        "arn:aws:s3:::other-bucket/*",
65        "arn:aws:ec2:*:*:instance/*",
66    ];
67
68    for pattern in &patterns {
69        match resource_arn.matches(pattern) {
70            Ok(matches) => {
71                let status = if matches { "✓ MATCH" } else { "✗ NO MATCH" };
72                println!("  {} Pattern: {}", status, pattern);
73            }
74            Err(e) => println!("  ✗ ERROR Pattern: {} ({})", pattern, e),
75        }
76    }
77
78    // Example 3: Integration with IAM policies
79    println!("\n3. Using ARNs in IAM policies:");
80
81    let policy = IAMPolicy::new()
82        .with_id("s3-access-policy")
83        .add_statement(
84            IAMStatement::new(Effect::Allow)
85                .with_sid("AllowS3Read")
86                .with_action(Action::Multiple(vec![
87                    "s3:GetObject".to_string(),
88                    "s3:ListBucket".to_string(),
89                ]))
90                .with_resource(Resource::Multiple(vec![
91                    "arn:aws:s3:::my-bucket".to_string(),
92                    "arn:aws:s3:::my-bucket/*".to_string(),
93                ])),
94        )
95        .add_statement(
96            IAMStatement::new(Effect::Allow)
97                .with_sid("AllowS3Write")
98                .with_action(Action::Single("s3:PutObject".to_string()))
99                .with_resource(Resource::Single(
100                    "arn:aws:s3:::my-bucket/uploads/*".to_string(),
101                )),
102        );
103
104    let policy_json = policy.to_json()?;
105    println!("Generated IAM Policy:");
106    println!("{}", policy_json);
107
108    // Example 4: Validate all ARNs in the policy
109    println!("\n4. Validating ARNs in policy:");
110
111    for (i, statement) in policy.statement.iter().enumerate() {
112        println!(
113            "Statement {}: {}",
114            i + 1,
115            statement.sid.as_ref().unwrap_or(&"(no sid)".to_string())
116        );
117
118        let resources = match &statement.resource {
119            Some(Resource::Single(arn)) => vec![arn.clone()],
120            Some(Resource::Multiple(arns)) => arns.clone(),
121            None => vec![],
122        };
123
124        for resource in resources {
125            match Arn::parse(&resource) {
126                Ok(arn) => {
127                    let validity = if arn.is_valid() {
128                        "✓ Valid"
129                    } else {
130                        "⚠ Invalid"
131                    };
132                    println!("  {} Resource: {}", validity, resource);
133                }
134                Err(e) => println!("  ✗ Parse Error: {} ({})", resource, e),
135            }
136        }
137    }
138
139    Ok(())
140}
More examples
Hide additional examples
examples/validation_demo.rs (line 17)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8    println!("=== IAM Policy Validation Demo ===\n");
9
10    // Example 1: Valid Policy
11    println!("1. Valid Policy Validation:");
12    let valid_policy = IAMPolicy::new()
13        .with_id("550e8400-e29b-41d4-a716-446655440000")
14        .add_statement(
15            IAMStatement::new(Effect::Allow)
16                .with_sid("AllowS3Read")
17                .with_action(Action::Single("s3:GetObject".to_string()))
18                .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string()))
19                .with_condition(
20                    Operator::StringEquals,
21                    "aws:PrincipalTag/department".to_string(),
22                    json!("engineering"),
23                ),
24        );
25
26    if valid_policy.is_valid() {
27        println!("✓ Policy is valid!");
28    } else {
29        println!("✗ Policy is invalid");
30    }
31
32    match valid_policy.validate_result() {
33        Ok(()) => println!("✓ Policy passes validation"),
34        Err(e) => println!("✗ Policy fails validation: {}", e),
35    }
36
37    println!();
38
39    // Example 2: Invalid Policy - Missing Required Fields
40    println!("2. Invalid Policy - Missing Required Fields:");
41    let invalid_policy = IAMPolicy::new().add_statement(IAMStatement::new(Effect::Allow)); // Missing action and resource
42
43    if !invalid_policy.is_valid() {
44        println!("✗ Policy is invalid (as expected)");
45        match invalid_policy.validate_result() {
46            Err(e) => println!("   Validation errors: {}", e),
47            Ok(()) => println!("   Unexpected: validation passed"),
48        }
49    }
50
51    println!();
52
53    // Example 3: Policy with Multiple Validation Errors
54    println!("3. Policy with Multiple Validation Errors:");
55    let multi_error_policy = IAMPolicy::new()
56        .with_id("") // Empty ID
57        .add_statement(
58            IAMStatement::new(Effect::Allow)
59                .with_action(Action::Single("invalid-action".to_string())) // Invalid action format
60                .with_resource(Resource::Single("invalid-resource".to_string())), // Invalid resource
61        )
62        .add_statement(
63            IAMStatement::new(Effect::Allow)
64                .with_sid("DuplicateId")
65                .with_action(Action::Single("s3:GetObject".to_string()))
66                .with_resource(Resource::Single("*".to_string())),
67        )
68        .add_statement(
69            IAMStatement::new(Effect::Deny)
70                .with_sid("DuplicateId") // Duplicate SID
71                .with_action(Action::Single("s3:DeleteObject".to_string()))
72                .with_resource(Resource::Single("*".to_string())),
73        );
74
75    match multi_error_policy.validate_result() {
76        Err(ValidationError::Multiple(errors)) => {
77            println!("✗ Found {} validation errors:", errors.len());
78            for (i, error) in errors.iter().enumerate() {
79                println!("   {}. {}", i + 1, error);
80            }
81        }
82        Err(e) => {
83            println!("✗ Single validation error: {}", e);
84        }
85        Ok(()) => {
86            println!("✓ Unexpected: validation passed");
87        }
88    }
89
90    println!();
91
92    // Example 4: Comprehensive Validation
93    println!("4. Comprehensive Validation:");
94    let comprehensive_policy = IAMPolicy::new()
95        .with_id("short") // Short ID - will fail validation
96        .add_statement(
97            IAMStatement::new(Effect::Allow)
98                .with_action(Action::Single("s3:GetObject".to_string()))
99                .with_resource(Resource::Single("*".to_string()))
100                .with_condition(
101                    Operator::NumericEquals,
102                    "aws:RequestedRegion".to_string(),
103                    json!("not-a-number"), // Numeric operator with string value - will fail
104                ),
105        );
106
107    match comprehensive_policy.validate_result() {
108        Ok(()) => println!("✓ Policy passes validation"),
109        Err(e) => println!("✗ Policy fails validation: {}", e),
110    }
111
112    println!();
113
114    // Example 5: Logical Policy Errors
115    println!("5. Logical Policy Errors:");
116
117    // NotPrincipal with Allow effect (invalid)
118    let mut logical_error_policy = IAMStatement::new(Effect::Allow);
119    logical_error_policy.action = Some(Action::Single("s3:GetObject".to_string()));
120    logical_error_policy.resource = Some(Resource::Single("*".to_string()));
121    let mut principal_map = std::collections::HashMap::new();
122    principal_map.insert(
123        PrincipalType::Aws,
124        serde_json::json!("arn:aws:iam::123456789012:user/test"),
125    );
126    logical_error_policy.not_principal = Some(Principal::Mapped(principal_map));
127
128    match logical_error_policy.validate_result() {
129        Err(e) => println!("✗ Logical error detected: {}", e),
130        Ok(()) => println!("✓ Unexpected: validation passed"),
131    }
132
133    // Both Action and NotAction (invalid)
134    let mut conflicting_statement = IAMStatement::new(Effect::Allow);
135    conflicting_statement.action = Some(Action::Single("s3:GetObject".to_string()));
136    conflicting_statement.not_action = Some(Action::Single("s3:PutObject".to_string()));
137    conflicting_statement.resource = Some(Resource::Single("*".to_string()));
138
139    match conflicting_statement.validate_result() {
140        Err(e) => println!("✗ Logical error detected: {}", e),
141        Ok(()) => println!("✓ Unexpected: validation passed"),
142    }
143
144    println!();
145
146    // Example 6: Component Validation
147    println!("6. Individual Component Validation:");
148
149    // Invalid action
150    let invalid_action = Action::Single("invalid-action".to_string());
151    match invalid_action.validate_result() {
152        Err(e) => println!("✗ Invalid action: {}", e),
153        Ok(()) => println!("✓ Action is valid"),
154    }
155
156    // Invalid principal
157    let mut invalid_map = std::collections::HashMap::new();
158    invalid_map.insert(PrincipalType::Aws, serde_json::json!("invalid-principal"));
159    let invalid_principal = Principal::Mapped(invalid_map);
160    match invalid_principal.validate_result() {
161        Err(e) => println!("✗ Invalid principal: {}", e),
162        Ok(()) => println!("✓ Principal is valid"),
163    }
164
165    // Valid service principal
166    let service_principal = Principal::Mapped(
167        [(PrincipalType::Service, json!("lambda.amazonaws.com"))]
168            .iter()
169            .cloned()
170            .collect(),
171    );
172    if service_principal.is_valid() {
173        println!("✓ Service principal is valid");
174    } else {
175        println!("✗ Service principal is invalid");
176    }
177
178    println!("\n=== Validation Demo Complete ===");
179
180    Ok(())
181}
examples/evaluation_demo.rs (line 17)
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(Effect::Allow)
16                .with_sid("AllowS3Read")
17                .with_action(Action::Single("s3:GetObject".to_string()))
18                .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string())),
19        );
20
21    let request = IAMRequest::new(
22        "arn:aws:iam::123456789012:user/alice",
23        "s3:GetObject",
24        "arn:aws:s3:::my-bucket/file.txt",
25    );
26
27    match evaluate_policy(&allow_policy, &request)? {
28        Decision::Allow => println!("✓ Access ALLOWED"),
29        Decision::Deny => println!("✗ Access DENIED"),
30        Decision::NotApplicable => println!("? No applicable policy (implicit deny)"),
31    }
32    println!();
33
34    // Example 2: Simple Deny Policy
35    println!("2. Simple Deny Policy:");
36    let deny_policy = IAMPolicy::new()
37        .with_id("550e8400-e29b-41d4-a716-446655440001")
38        .add_statement(
39            IAMStatement::new(Effect::Deny)
40                .with_sid("DenyS3Delete")
41                .with_action(Action::Single("s3:DeleteObject".to_string()))
42                .with_resource(Resource::Single(
43                    "arn:aws:s3:::protected-bucket/*".to_string(),
44                )),
45        );
46
47    let delete_request = IAMRequest::new(
48        "arn:aws:iam::123456789012:user/alice",
49        "s3:DeleteObject",
50        "arn:aws:s3:::protected-bucket/important.txt",
51    );
52
53    match evaluate_policy(&deny_policy, &delete_request)? {
54        Decision::Allow => println!("✓ Access ALLOWED"),
55        Decision::Deny => println!("✗ Access DENIED"),
56        Decision::NotApplicable => println!("? No applicable policy (implicit deny)"),
57    }
58    println!();
59
60    // Example 3: Wildcard Action Matching
61    println!("3. Wildcard Action Matching:");
62    let wildcard_policy = IAMPolicy::new()
63        .with_id("550e8400-e29b-41d4-a716-446655440002")
64        .add_statement(
65            IAMStatement::new(Effect::Allow)
66                .with_sid("AllowAllS3")
67                .with_action(Action::Single("s3:*".to_string()))
68                .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string())),
69        );
70
71    let wildcard_request = IAMRequest::new(
72        "arn:aws:iam::123456789012:user/alice",
73        "s3:PutObject",
74        "arn:aws:s3:::my-bucket/new-file.txt",
75    );
76
77    match evaluate_policy(&wildcard_policy, &wildcard_request)? {
78        Decision::Allow => println!("✓ Wildcard action matched - Access ALLOWED"),
79        Decision::Deny => println!("✗ Access DENIED"),
80        Decision::NotApplicable => println!("? No applicable policy"),
81    }
82    println!();
83
84    // Example 4: Condition-Based Policy
85    println!("4. Condition-Based Policy:");
86    let mut context = Context::new();
87    context.insert(
88        "aws:userid".to_string(),
89        ContextValue::String("alice".to_string()),
90    );
91    context.insert(
92        "aws:CurrentTime".to_string(),
93        ContextValue::String("2024-01-15T10:00:00Z".to_string()),
94    );
95
96    let condition_policy = IAMPolicy::new()
97        .with_id("550e8400-e29b-41d4-a716-446655440003")
98        .add_statement(
99            IAMStatement::new(Effect::Allow)
100                .with_sid("AllowWithCondition")
101                .with_action(Action::Single("s3:GetObject".to_string()))
102                .with_resource(Resource::Single(
103                    "arn:aws:s3:::private-bucket/*".to_string(),
104                ))
105                .with_condition(
106                    Operator::StringEquals,
107                    "aws:userid".to_string(),
108                    json!("alice"),
109                ),
110        );
111
112    let condition_request = IAMRequest::new_with_context(
113        "arn:aws:iam::123456789012:user/alice",
114        "s3:GetObject",
115        "arn:aws:s3:::private-bucket/personal.txt",
116        context,
117    );
118
119    match evaluate_policy(&condition_policy, &condition_request)? {
120        Decision::Allow => println!("✓ Condition satisfied - Access ALLOWED"),
121        Decision::Deny => println!("✗ Access DENIED"),
122        Decision::NotApplicable => println!("? Condition not satisfied"),
123    }
124    println!();
125
126    // Example 5: Failed Condition
127    println!("5. Failed Condition:");
128    let mut wrong_context = Context::new();
129    wrong_context.insert(
130        "aws:userid".to_string(),
131        ContextValue::String("bob".to_string()),
132    );
133
134    let failed_condition_request = IAMRequest::new_with_context(
135        "arn:aws:iam::123456789012:user/bob",
136        "s3:GetObject",
137        "arn:aws:s3:::private-bucket/personal.txt",
138        wrong_context,
139    );
140
141    match evaluate_policy(&condition_policy, &failed_condition_request)? {
142        Decision::Allow => println!("✓ Access ALLOWED"),
143        Decision::Deny => println!("✗ Access DENIED"),
144        Decision::NotApplicable => println!("? Condition failed - No applicable policy"),
145    }
146    println!();
147
148    // Example 6: Explicit Deny Overrides Allow
149    println!("6. Explicit Deny Overrides Allow:");
150    let combined_policies = vec![
151        IAMPolicy::new()
152            .with_id("550e8400-e29b-41d4-a716-446655440004")
153            .add_statement(
154                IAMStatement::new(Effect::Allow)
155                    .with_sid("AllowAll")
156                    .with_action(Action::Single("s3:*".to_string()))
157                    .with_resource(Resource::Single("*".to_string())),
158            ),
159        IAMPolicy::new()
160            .with_id("550e8400-e29b-41d4-a716-446655440005")
161            .add_statement(
162                IAMStatement::new(Effect::Deny)
163                    .with_sid("DenyProtected")
164                    .with_action(Action::Single("s3:DeleteObject".to_string()))
165                    .with_resource(Resource::Single(
166                        "arn:aws:s3:::protected-bucket/*".to_string(),
167                    )),
168            ),
169    ];
170
171    let evaluator = PolicyEvaluator::with_policies(combined_policies);
172    let protected_request = IAMRequest::new(
173        "arn:aws:iam::123456789012:user/alice",
174        "s3:DeleteObject",
175        "arn:aws:s3:::protected-bucket/critical.txt",
176    );
177
178    match evaluator.evaluate(&protected_request)?.decision {
179        Decision::Allow => println!("✓ Access ALLOWED"),
180        Decision::Deny => println!("✗ Explicit DENY overrides Allow"),
181        Decision::NotApplicable => println!("? No applicable policy"),
182    }
183    println!();
184
185    // Example 7: Numeric Condition
186    println!("7. Numeric Condition:");
187    let mut numeric_context = Context::new();
188    numeric_context.insert("aws:RequestCount".to_string(), ContextValue::Number(5.0));
189
190    let numeric_policy = IAMPolicy::new()
191        .with_id("550e8400-e29b-41d4-a716-446655440006")
192        .add_statement(
193            IAMStatement::new(Effect::Allow)
194                .with_sid("AllowLimitedRequests")
195                .with_action(Action::Single("s3:GetObject".to_string()))
196                .with_resource(Resource::Single("*".to_string()))
197                .with_condition(
198                    Operator::NumericLessThan,
199                    "aws:RequestCount".to_string(),
200                    json!(10),
201                ),
202        );
203
204    let numeric_request = IAMRequest::new_with_context(
205        "arn:aws:iam::123456789012:user/alice",
206        "s3:GetObject",
207        "arn:aws:s3:::any-bucket/file.txt",
208        numeric_context,
209    );
210
211    match evaluate_policy(&numeric_policy, &numeric_request)? {
212        Decision::Allow => println!("✓ Numeric condition satisfied - Access ALLOWED"),
213        Decision::Deny => println!("✗ Access DENIED"),
214        Decision::NotApplicable => println!("? Numeric condition failed"),
215    }
216    println!();
217
218    // Example 8: Detailed Evaluation with Options
219    println!("8. Detailed Evaluation with Options:");
220    let detailed_evaluator = PolicyEvaluator::with_policies(vec![allow_policy.clone()])
221        .with_options(EvaluationOptions {
222            collect_match_details: true,
223            stop_on_explicit_deny: false,
224            max_statements: 100,
225        });
226
227    let detailed_result = detailed_evaluator.evaluate(&request)?;
228    println!("Decision: {:?}", detailed_result.decision);
229    println!("Matched Statements:");
230    for (i, statement_match) in detailed_result.matched_statements.iter().enumerate() {
231        println!(
232            "  {}. SID: {:?}, Effect: {:?}, Satisfied: {}, Reason: {}",
233            i + 1,
234            statement_match.sid,
235            statement_match.effect,
236            statement_match.conditions_satisfied,
237            statement_match.reason
238        );
239    }
240    println!();
241
242    // Example 9: No Applicable Policy (Implicit Deny)
243    println!("9. No Applicable Policy (Implicit Deny):");
244    let unrelated_request = IAMRequest::new(
245        "arn:aws:iam::123456789012:user/alice",
246        "ec2:DescribeInstances",
247        "arn:aws:ec2:us-east-1:123456789012:instance/*",
248    );
249
250    match evaluate_policy(&allow_policy, &unrelated_request)? {
251        Decision::Allow => println!("✓ Access ALLOWED"),
252        Decision::Deny => println!("✗ Access DENIED"),
253        Decision::NotApplicable => println!("? No applicable policy - Implicit DENY"),
254    }
255    println!();
256
257    // Example 10: Resource Pattern Matching
258    println!("10. Resource Pattern Matching:");
259    let pattern_policy = IAMPolicy::new()
260        .with_id("550e8400-e29b-41d4-a716-446655440007")
261        .add_statement(
262            IAMStatement::new(Effect::Allow)
263                .with_sid("AllowBucketAccess")
264                .with_action(Action::Multiple(vec![
265                    "s3:GetObject".to_string(),
266                    "s3:PutObject".to_string(),
267                ]))
268                .with_resource(Resource::Single("arn:aws:s3:::user-data-*/*".to_string())),
269        );
270
271    let pattern_request = IAMRequest::new(
272        "arn:aws:iam::123456789012:user/alice",
273        "s3:GetObject",
274        "arn:aws:s3:::user-data-alice/profile.json",
275    );
276
277    match evaluate_policy(&pattern_policy, &pattern_request)? {
278        Decision::Allow => println!("✓ Resource pattern matched - Access ALLOWED"),
279        Decision::Deny => println!("✗ Access DENIED"),
280        Decision::NotApplicable => println!("? Resource pattern didn't match"),
281    }
282
283    println!("\n=== Policy Evaluation Demo Complete ===");
284    println!("\nThe Policy Evaluation Engine successfully:");
285    println!("• ✅ Evaluates Allow/Deny effects");
286    println!("• ✅ Handles wildcard actions and resources");
287    println!("• ✅ Processes condition blocks with various operators");
288    println!("• ✅ Implements proper IAM logic (explicit deny overrides)");
289    println!("• ✅ Supports detailed evaluation with match information");
290    println!("• ✅ Handles multiple policies with complex interactions");
291    println!("• ✅ Provides clear Allow/Deny/NotApplicable decisions");
292
293    Ok(())
294}
Source

pub fn with_resource(self, resource: Resource) -> Self

Sets the resource

Examples found in repository?
examples/arn_demo.rs (lines 90-93)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("=== IAM ARN Validator Demo ===\n");
5
6    // Example 1: Parse and validate ARNs
7    println!("1. Parsing and validating ARNs:");
8
9    let valid_arns = vec![
10        "arn:aws:s3:::my-bucket/folder/file.txt",
11        "arn:aws:iam::123456789012:user/alice",
12        "arn:aws:ec2:us-east-1:123456789012:instance/i-1234567890abcdef0",
13        "arn:aws:lambda:us-east-1:123456789012:function:MyFunction",
14        "arn:aws:dynamodb:us-east-1:123456789012:table/MyTable",
15        "arn:aws-eu-gov:dynamodb:us-east-1:123456789012:table/MyTable",
16    ];
17
18    for arn_str in &valid_arns {
19        match Arn::parse(arn_str) {
20            Ok(arn) => {
21                println!("✓ Valid ARN: {}", arn);
22                println!("  - Service: {}", arn.service);
23                println!(
24                    "  - Region: {}",
25                    if arn.region.is_empty() {
26                        "global"
27                    } else {
28                        &arn.region
29                    }
30                );
31                println!(
32                    "  - Account: {}",
33                    if arn.account_id.is_empty() {
34                        "none"
35                    } else {
36                        &arn.account_id
37                    }
38                );
39                if let Some(resource_type) = arn.resource_type() {
40                    println!("  - Resource Type: {}", resource_type);
41                }
42                if let Some(resource_id) = arn.resource_id() {
43                    println!("  - Resource ID: {}", resource_id);
44                }
45                println!();
46            }
47            Err(e) => println!("✗ Invalid ARN {}: {}", arn_str, e),
48        }
49    }
50
51    // Example 2: Wildcard matching
52    println!("2. Wildcard pattern matching:");
53
54    let resource_arn = Arn::parse("arn:aws:s3:::my-bucket/uploads/user123/document.pdf")?;
55    println!("Resource ARN: {}", resource_arn);
56
57    let patterns = vec![
58        "arn:aws:s3:::my-bucket/*",
59        "arn:aws:s3:::my-bucket/uploads/*",
60        "arn:aws:s3:::my-bucket/uploads/user123/*",
61        "arn:aws:s3:::*/uploads/user123/document.pdf",
62        "arn:aws:s3:::my-bucket/uploads/*/document.pdf",
63        "arn:aws:s3:::my-bucket/uploads/user???/document.pdf",
64        "arn:aws:s3:::other-bucket/*",
65        "arn:aws:ec2:*:*:instance/*",
66    ];
67
68    for pattern in &patterns {
69        match resource_arn.matches(pattern) {
70            Ok(matches) => {
71                let status = if matches { "✓ MATCH" } else { "✗ NO MATCH" };
72                println!("  {} Pattern: {}", status, pattern);
73            }
74            Err(e) => println!("  ✗ ERROR Pattern: {} ({})", pattern, e),
75        }
76    }
77
78    // Example 3: Integration with IAM policies
79    println!("\n3. Using ARNs in IAM policies:");
80
81    let policy = IAMPolicy::new()
82        .with_id("s3-access-policy")
83        .add_statement(
84            IAMStatement::new(Effect::Allow)
85                .with_sid("AllowS3Read")
86                .with_action(Action::Multiple(vec![
87                    "s3:GetObject".to_string(),
88                    "s3:ListBucket".to_string(),
89                ]))
90                .with_resource(Resource::Multiple(vec![
91                    "arn:aws:s3:::my-bucket".to_string(),
92                    "arn:aws:s3:::my-bucket/*".to_string(),
93                ])),
94        )
95        .add_statement(
96            IAMStatement::new(Effect::Allow)
97                .with_sid("AllowS3Write")
98                .with_action(Action::Single("s3:PutObject".to_string()))
99                .with_resource(Resource::Single(
100                    "arn:aws:s3:::my-bucket/uploads/*".to_string(),
101                )),
102        );
103
104    let policy_json = policy.to_json()?;
105    println!("Generated IAM Policy:");
106    println!("{}", policy_json);
107
108    // Example 4: Validate all ARNs in the policy
109    println!("\n4. Validating ARNs in policy:");
110
111    for (i, statement) in policy.statement.iter().enumerate() {
112        println!(
113            "Statement {}: {}",
114            i + 1,
115            statement.sid.as_ref().unwrap_or(&"(no sid)".to_string())
116        );
117
118        let resources = match &statement.resource {
119            Some(Resource::Single(arn)) => vec![arn.clone()],
120            Some(Resource::Multiple(arns)) => arns.clone(),
121            None => vec![],
122        };
123
124        for resource in resources {
125            match Arn::parse(&resource) {
126                Ok(arn) => {
127                    let validity = if arn.is_valid() {
128                        "✓ Valid"
129                    } else {
130                        "⚠ Invalid"
131                    };
132                    println!("  {} Resource: {}", validity, resource);
133                }
134                Err(e) => println!("  ✗ Parse Error: {} ({})", resource, e),
135            }
136        }
137    }
138
139    Ok(())
140}
More examples
Hide additional examples
examples/validation_demo.rs (line 18)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8    println!("=== IAM Policy Validation Demo ===\n");
9
10    // Example 1: Valid Policy
11    println!("1. Valid Policy Validation:");
12    let valid_policy = IAMPolicy::new()
13        .with_id("550e8400-e29b-41d4-a716-446655440000")
14        .add_statement(
15            IAMStatement::new(Effect::Allow)
16                .with_sid("AllowS3Read")
17                .with_action(Action::Single("s3:GetObject".to_string()))
18                .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string()))
19                .with_condition(
20                    Operator::StringEquals,
21                    "aws:PrincipalTag/department".to_string(),
22                    json!("engineering"),
23                ),
24        );
25
26    if valid_policy.is_valid() {
27        println!("✓ Policy is valid!");
28    } else {
29        println!("✗ Policy is invalid");
30    }
31
32    match valid_policy.validate_result() {
33        Ok(()) => println!("✓ Policy passes validation"),
34        Err(e) => println!("✗ Policy fails validation: {}", e),
35    }
36
37    println!();
38
39    // Example 2: Invalid Policy - Missing Required Fields
40    println!("2. Invalid Policy - Missing Required Fields:");
41    let invalid_policy = IAMPolicy::new().add_statement(IAMStatement::new(Effect::Allow)); // Missing action and resource
42
43    if !invalid_policy.is_valid() {
44        println!("✗ Policy is invalid (as expected)");
45        match invalid_policy.validate_result() {
46            Err(e) => println!("   Validation errors: {}", e),
47            Ok(()) => println!("   Unexpected: validation passed"),
48        }
49    }
50
51    println!();
52
53    // Example 3: Policy with Multiple Validation Errors
54    println!("3. Policy with Multiple Validation Errors:");
55    let multi_error_policy = IAMPolicy::new()
56        .with_id("") // Empty ID
57        .add_statement(
58            IAMStatement::new(Effect::Allow)
59                .with_action(Action::Single("invalid-action".to_string())) // Invalid action format
60                .with_resource(Resource::Single("invalid-resource".to_string())), // Invalid resource
61        )
62        .add_statement(
63            IAMStatement::new(Effect::Allow)
64                .with_sid("DuplicateId")
65                .with_action(Action::Single("s3:GetObject".to_string()))
66                .with_resource(Resource::Single("*".to_string())),
67        )
68        .add_statement(
69            IAMStatement::new(Effect::Deny)
70                .with_sid("DuplicateId") // Duplicate SID
71                .with_action(Action::Single("s3:DeleteObject".to_string()))
72                .with_resource(Resource::Single("*".to_string())),
73        );
74
75    match multi_error_policy.validate_result() {
76        Err(ValidationError::Multiple(errors)) => {
77            println!("✗ Found {} validation errors:", errors.len());
78            for (i, error) in errors.iter().enumerate() {
79                println!("   {}. {}", i + 1, error);
80            }
81        }
82        Err(e) => {
83            println!("✗ Single validation error: {}", e);
84        }
85        Ok(()) => {
86            println!("✓ Unexpected: validation passed");
87        }
88    }
89
90    println!();
91
92    // Example 4: Comprehensive Validation
93    println!("4. Comprehensive Validation:");
94    let comprehensive_policy = IAMPolicy::new()
95        .with_id("short") // Short ID - will fail validation
96        .add_statement(
97            IAMStatement::new(Effect::Allow)
98                .with_action(Action::Single("s3:GetObject".to_string()))
99                .with_resource(Resource::Single("*".to_string()))
100                .with_condition(
101                    Operator::NumericEquals,
102                    "aws:RequestedRegion".to_string(),
103                    json!("not-a-number"), // Numeric operator with string value - will fail
104                ),
105        );
106
107    match comprehensive_policy.validate_result() {
108        Ok(()) => println!("✓ Policy passes validation"),
109        Err(e) => println!("✗ Policy fails validation: {}", e),
110    }
111
112    println!();
113
114    // Example 5: Logical Policy Errors
115    println!("5. Logical Policy Errors:");
116
117    // NotPrincipal with Allow effect (invalid)
118    let mut logical_error_policy = IAMStatement::new(Effect::Allow);
119    logical_error_policy.action = Some(Action::Single("s3:GetObject".to_string()));
120    logical_error_policy.resource = Some(Resource::Single("*".to_string()));
121    let mut principal_map = std::collections::HashMap::new();
122    principal_map.insert(
123        PrincipalType::Aws,
124        serde_json::json!("arn:aws:iam::123456789012:user/test"),
125    );
126    logical_error_policy.not_principal = Some(Principal::Mapped(principal_map));
127
128    match logical_error_policy.validate_result() {
129        Err(e) => println!("✗ Logical error detected: {}", e),
130        Ok(()) => println!("✓ Unexpected: validation passed"),
131    }
132
133    // Both Action and NotAction (invalid)
134    let mut conflicting_statement = IAMStatement::new(Effect::Allow);
135    conflicting_statement.action = Some(Action::Single("s3:GetObject".to_string()));
136    conflicting_statement.not_action = Some(Action::Single("s3:PutObject".to_string()));
137    conflicting_statement.resource = Some(Resource::Single("*".to_string()));
138
139    match conflicting_statement.validate_result() {
140        Err(e) => println!("✗ Logical error detected: {}", e),
141        Ok(()) => println!("✓ Unexpected: validation passed"),
142    }
143
144    println!();
145
146    // Example 6: Component Validation
147    println!("6. Individual Component Validation:");
148
149    // Invalid action
150    let invalid_action = Action::Single("invalid-action".to_string());
151    match invalid_action.validate_result() {
152        Err(e) => println!("✗ Invalid action: {}", e),
153        Ok(()) => println!("✓ Action is valid"),
154    }
155
156    // Invalid principal
157    let mut invalid_map = std::collections::HashMap::new();
158    invalid_map.insert(PrincipalType::Aws, serde_json::json!("invalid-principal"));
159    let invalid_principal = Principal::Mapped(invalid_map);
160    match invalid_principal.validate_result() {
161        Err(e) => println!("✗ Invalid principal: {}", e),
162        Ok(()) => println!("✓ Principal is valid"),
163    }
164
165    // Valid service principal
166    let service_principal = Principal::Mapped(
167        [(PrincipalType::Service, json!("lambda.amazonaws.com"))]
168            .iter()
169            .cloned()
170            .collect(),
171    );
172    if service_principal.is_valid() {
173        println!("✓ Service principal is valid");
174    } else {
175        println!("✗ Service principal is invalid");
176    }
177
178    println!("\n=== Validation Demo Complete ===");
179
180    Ok(())
181}
examples/evaluation_demo.rs (line 18)
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(Effect::Allow)
16                .with_sid("AllowS3Read")
17                .with_action(Action::Single("s3:GetObject".to_string()))
18                .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string())),
19        );
20
21    let request = IAMRequest::new(
22        "arn:aws:iam::123456789012:user/alice",
23        "s3:GetObject",
24        "arn:aws:s3:::my-bucket/file.txt",
25    );
26
27    match evaluate_policy(&allow_policy, &request)? {
28        Decision::Allow => println!("✓ Access ALLOWED"),
29        Decision::Deny => println!("✗ Access DENIED"),
30        Decision::NotApplicable => println!("? No applicable policy (implicit deny)"),
31    }
32    println!();
33
34    // Example 2: Simple Deny Policy
35    println!("2. Simple Deny Policy:");
36    let deny_policy = IAMPolicy::new()
37        .with_id("550e8400-e29b-41d4-a716-446655440001")
38        .add_statement(
39            IAMStatement::new(Effect::Deny)
40                .with_sid("DenyS3Delete")
41                .with_action(Action::Single("s3:DeleteObject".to_string()))
42                .with_resource(Resource::Single(
43                    "arn:aws:s3:::protected-bucket/*".to_string(),
44                )),
45        );
46
47    let delete_request = IAMRequest::new(
48        "arn:aws:iam::123456789012:user/alice",
49        "s3:DeleteObject",
50        "arn:aws:s3:::protected-bucket/important.txt",
51    );
52
53    match evaluate_policy(&deny_policy, &delete_request)? {
54        Decision::Allow => println!("✓ Access ALLOWED"),
55        Decision::Deny => println!("✗ Access DENIED"),
56        Decision::NotApplicable => println!("? No applicable policy (implicit deny)"),
57    }
58    println!();
59
60    // Example 3: Wildcard Action Matching
61    println!("3. Wildcard Action Matching:");
62    let wildcard_policy = IAMPolicy::new()
63        .with_id("550e8400-e29b-41d4-a716-446655440002")
64        .add_statement(
65            IAMStatement::new(Effect::Allow)
66                .with_sid("AllowAllS3")
67                .with_action(Action::Single("s3:*".to_string()))
68                .with_resource(Resource::Single("arn:aws:s3:::my-bucket/*".to_string())),
69        );
70
71    let wildcard_request = IAMRequest::new(
72        "arn:aws:iam::123456789012:user/alice",
73        "s3:PutObject",
74        "arn:aws:s3:::my-bucket/new-file.txt",
75    );
76
77    match evaluate_policy(&wildcard_policy, &wildcard_request)? {
78        Decision::Allow => println!("✓ Wildcard action matched - Access ALLOWED"),
79        Decision::Deny => println!("✗ Access DENIED"),
80        Decision::NotApplicable => println!("? No applicable policy"),
81    }
82    println!();
83
84    // Example 4: Condition-Based Policy
85    println!("4. Condition-Based Policy:");
86    let mut context = Context::new();
87    context.insert(
88        "aws:userid".to_string(),
89        ContextValue::String("alice".to_string()),
90    );
91    context.insert(
92        "aws:CurrentTime".to_string(),
93        ContextValue::String("2024-01-15T10:00:00Z".to_string()),
94    );
95
96    let condition_policy = IAMPolicy::new()
97        .with_id("550e8400-e29b-41d4-a716-446655440003")
98        .add_statement(
99            IAMStatement::new(Effect::Allow)
100                .with_sid("AllowWithCondition")
101                .with_action(Action::Single("s3:GetObject".to_string()))
102                .with_resource(Resource::Single(
103                    "arn:aws:s3:::private-bucket/*".to_string(),
104                ))
105                .with_condition(
106                    Operator::StringEquals,
107                    "aws:userid".to_string(),
108                    json!("alice"),
109                ),
110        );
111
112    let condition_request = IAMRequest::new_with_context(
113        "arn:aws:iam::123456789012:user/alice",
114        "s3:GetObject",
115        "arn:aws:s3:::private-bucket/personal.txt",
116        context,
117    );
118
119    match evaluate_policy(&condition_policy, &condition_request)? {
120        Decision::Allow => println!("✓ Condition satisfied - Access ALLOWED"),
121        Decision::Deny => println!("✗ Access DENIED"),
122        Decision::NotApplicable => println!("? Condition not satisfied"),
123    }
124    println!();
125
126    // Example 5: Failed Condition
127    println!("5. Failed Condition:");
128    let mut wrong_context = Context::new();
129    wrong_context.insert(
130        "aws:userid".to_string(),
131        ContextValue::String("bob".to_string()),
132    );
133
134    let failed_condition_request = IAMRequest::new_with_context(
135        "arn:aws:iam::123456789012:user/bob",
136        "s3:GetObject",
137        "arn:aws:s3:::private-bucket/personal.txt",
138        wrong_context,
139    );
140
141    match evaluate_policy(&condition_policy, &failed_condition_request)? {
142        Decision::Allow => println!("✓ Access ALLOWED"),
143        Decision::Deny => println!("✗ Access DENIED"),
144        Decision::NotApplicable => println!("? Condition failed - No applicable policy"),
145    }
146    println!();
147
148    // Example 6: Explicit Deny Overrides Allow
149    println!("6. Explicit Deny Overrides Allow:");
150    let combined_policies = vec![
151        IAMPolicy::new()
152            .with_id("550e8400-e29b-41d4-a716-446655440004")
153            .add_statement(
154                IAMStatement::new(Effect::Allow)
155                    .with_sid("AllowAll")
156                    .with_action(Action::Single("s3:*".to_string()))
157                    .with_resource(Resource::Single("*".to_string())),
158            ),
159        IAMPolicy::new()
160            .with_id("550e8400-e29b-41d4-a716-446655440005")
161            .add_statement(
162                IAMStatement::new(Effect::Deny)
163                    .with_sid("DenyProtected")
164                    .with_action(Action::Single("s3:DeleteObject".to_string()))
165                    .with_resource(Resource::Single(
166                        "arn:aws:s3:::protected-bucket/*".to_string(),
167                    )),
168            ),
169    ];
170
171    let evaluator = PolicyEvaluator::with_policies(combined_policies);
172    let protected_request = IAMRequest::new(
173        "arn:aws:iam::123456789012:user/alice",
174        "s3:DeleteObject",
175        "arn:aws:s3:::protected-bucket/critical.txt",
176    );
177
178    match evaluator.evaluate(&protected_request)?.decision {
179        Decision::Allow => println!("✓ Access ALLOWED"),
180        Decision::Deny => println!("✗ Explicit DENY overrides Allow"),
181        Decision::NotApplicable => println!("? No applicable policy"),
182    }
183    println!();
184
185    // Example 7: Numeric Condition
186    println!("7. Numeric Condition:");
187    let mut numeric_context = Context::new();
188    numeric_context.insert("aws:RequestCount".to_string(), ContextValue::Number(5.0));
189
190    let numeric_policy = IAMPolicy::new()
191        .with_id("550e8400-e29b-41d4-a716-446655440006")
192        .add_statement(
193            IAMStatement::new(Effect::Allow)
194                .with_sid("AllowLimitedRequests")
195                .with_action(Action::Single("s3:GetObject".to_string()))
196                .with_resource(Resource::Single("*".to_string()))
197                .with_condition(
198                    Operator::NumericLessThan,
199                    "aws:RequestCount".to_string(),
200                    json!(10),
201                ),
202        );
203
204    let numeric_request = IAMRequest::new_with_context(
205        "arn:aws:iam::123456789012:user/alice",
206        "s3:GetObject",
207        "arn:aws:s3:::any-bucket/file.txt",
208        numeric_context,
209    );
210
211    match evaluate_policy(&numeric_policy, &numeric_request)? {
212        Decision::Allow => println!("✓ Numeric condition satisfied - Access ALLOWED"),
213        Decision::Deny => println!("✗ Access DENIED"),
214        Decision::NotApplicable => println!("? Numeric condition failed"),
215    }
216    println!();
217
218    // Example 8: Detailed Evaluation with Options
219    println!("8. Detailed Evaluation with Options:");
220    let detailed_evaluator = PolicyEvaluator::with_policies(vec![allow_policy.clone()])
221        .with_options(EvaluationOptions {
222            collect_match_details: true,
223            stop_on_explicit_deny: false,
224            max_statements: 100,
225        });
226
227    let detailed_result = detailed_evaluator.evaluate(&request)?;
228    println!("Decision: {:?}", detailed_result.decision);
229    println!("Matched Statements:");
230    for (i, statement_match) in detailed_result.matched_statements.iter().enumerate() {
231        println!(
232            "  {}. SID: {:?}, Effect: {:?}, Satisfied: {}, Reason: {}",
233            i + 1,
234            statement_match.sid,
235            statement_match.effect,
236            statement_match.conditions_satisfied,
237            statement_match.reason
238        );
239    }
240    println!();
241
242    // Example 9: No Applicable Policy (Implicit Deny)
243    println!("9. No Applicable Policy (Implicit Deny):");
244    let unrelated_request = IAMRequest::new(
245        "arn:aws:iam::123456789012:user/alice",
246        "ec2:DescribeInstances",
247        "arn:aws:ec2:us-east-1:123456789012:instance/*",
248    );
249
250    match evaluate_policy(&allow_policy, &unrelated_request)? {
251        Decision::Allow => println!("✓ Access ALLOWED"),
252        Decision::Deny => println!("✗ Access DENIED"),
253        Decision::NotApplicable => println!("? No applicable policy - Implicit DENY"),
254    }
255    println!();
256
257    // Example 10: Resource Pattern Matching
258    println!("10. Resource Pattern Matching:");
259    let pattern_policy = IAMPolicy::new()
260        .with_id("550e8400-e29b-41d4-a716-446655440007")
261        .add_statement(
262            IAMStatement::new(Effect::Allow)
263                .with_sid("AllowBucketAccess")
264                .with_action(Action::Multiple(vec![
265                    "s3:GetObject".to_string(),
266                    "s3:PutObject".to_string(),
267                ]))
268                .with_resource(Resource::Single("arn:aws:s3:::user-data-*/*".to_string())),
269        );
270
271    let pattern_request = IAMRequest::new(
272        "arn:aws:iam::123456789012:user/alice",
273        "s3:GetObject",
274        "arn:aws:s3:::user-data-alice/profile.json",
275    );
276
277    match evaluate_policy(&pattern_policy, &pattern_request)? {
278        Decision::Allow => println!("✓ Resource pattern matched - Access ALLOWED"),
279        Decision::Deny => println!("✗ Access DENIED"),
280        Decision::NotApplicable => println!("? Resource pattern didn't match"),
281    }
282
283    println!("\n=== Policy Evaluation Demo Complete ===");
284    println!("\nThe Policy Evaluation Engine successfully:");
285    println!("• ✅ Evaluates Allow/Deny effects");
286    println!("• ✅ Handles wildcard actions and resources");
287    println!("• ✅ Processes condition blocks with various operators");
288    println!("• ✅ Implements proper IAM logic (explicit deny overrides)");
289    println!("• ✅ Supports detailed evaluation with match information");
290    println!("• ✅ Handles multiple policies with complex interactions");
291    println!("• ✅ Provides clear Allow/Deny/NotApplicable decisions");
292
293    Ok(())
294}
Source

pub fn with_condition( self, operator: Operator, key: String, value: Value, ) -> Self

Adds a condition to the statement

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

pub fn with_condition_struct(self, condition: Condition) -> Self

Adds a condition using the Condition struct

Trait Implementations§

Source§

impl Clone for IAMStatement

Source§

fn clone(&self) -> IAMStatement

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 IAMStatement

Source§

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

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

impl<'de> Deserialize<'de> for IAMStatement

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 IAMStatement

Source§

fn eq(&self, other: &IAMStatement) -> 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 IAMStatement

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 Validate for IAMStatement

Source§

fn validate(&self, context: &mut ValidationContext) -> ValidationResult

Validate the component within the given context Read more
Source§

fn is_valid(&self) -> bool

Convenience method for basic validation
Source§

fn validate_result(&self) -> ValidationResult

Validate with detailed errors (same as regular validation) Read more
Source§

impl Eq for IAMStatement

Source§

impl StructuralPartialEq for IAMStatement

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>,