Repository: smithy-lang/smithy
Pull request #2000 (2023-10-04 20:24:01)

Add sigv4 subscheme auth validation
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.



Patch:
diff --git a/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/language/functions/AwsRuleSetExtension.java b/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/language/functions/AwsRuleSetExtension.java
index 889824df2..245af6c64 100644
--- a/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/language/functions/AwsRuleSetExtension.java
+++ b/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/language/functions/AwsRuleSetExtension.java
@@ -44,6 +44,7 @@ public final class AwsRuleSetExtension implements EndpointRuleSetExtension {
         return ListUtils.of(
                 new EndpointAuthUtils.SigV4SchemeValidator(),
                 new EndpointAuthUtils.SigV4aSchemeValidator(),
+                new EndpointAuthUtils.SigV4SubSchemeValidator(),
                 new EndpointAuthUtils.BetaSchemeValidator());
     }
 }
diff --git a/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/language/functions/EndpointAuthUtils.java b/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/language/functions/EndpointAuthUtils.java
index a1d62e09f..1c25ea94b 100644
--- a/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/language/functions/EndpointAuthUtils.java
+++ b/smithy-aws-endpoints/src/main/java/software/amazon/smithy/rulesengine/aws/language/functions/EndpointAuthUtils.java
@@ -12,6 +12,7 @@ import java.util.Optional;
 import java.util.function.BiFunction;
 import java.util.function.Function;
 import software.amazon.smithy.model.FromSourceLocation;
+import software.amazon.smithy.model.validation.Severity;
 import software.amazon.smithy.model.validation.ValidationEvent;
 import software.amazon.smithy.rulesengine.language.Endpoint;
 import software.amazon.smithy.rulesengine.language.syntax.Identifier;
@@ -167,6 +168,48 @@ public final class EndpointAuthUtils {
         }
     }
 
+    static final class SigV4SubSchemeValidator implements AuthSchemeValidator {
+        SigV4SubSchemeValidator() {}
+
+        @Override
+        public boolean test(String name) {
+            return name.startsWith("sigv4-");
+        }
+
+        @Override
+        public List<ValidationEvent> validateScheme(
+                Map<Identifier, Literal> authScheme,
+                FromSourceLocation sourceLocation,
+                BiFunction<FromSourceLocation, String, ValidationEvent> emitter
+        ) {
+            List<ValidationEvent> events = hasAllKeys(emitter, authScheme,
+                    ListUtils.of(RuleSetAuthSchemesValidator.NAME, ID_SIGNING_NAME), sourceLocation);
+            validateStringProperty(emitter, authScheme, ID_SIGNING_NAME).ifPresent(events::add);
+
+            // Events are emitted by default as ERROR, but we want to make this viable with acknowledgement.
+            ValidationEvent event = emitter.apply(sourceLocation,
+                    "Requirements for `sigv4-` auth sub-scheme validation may change.");
+            events.add(event.toBuilder().severity(Severity.DANGER).build());
+
+            return events;
+        }
+
+        private List<ValidationEvent> hasAllKeys(
+                BiFunction<FromSourceLocation, String, ValidationEvent> emitter,
+                Map<Identifier, Literal> authScheme,
+                List<Identifier> requiredKeys,
+                FromSourceLocation sourceLocation
+        ) {
+            List<ValidationEvent> events = new ArrayList<>();
+            for (Identifier key : requiredKeys) {
+                if (!authScheme.containsKey(key)) {
+                    emitter.apply(sourceLocation, String.format("Missing key: `%s`", key));
+                }
+            }
+            return events;
+        }
+    }
+
     static final class BetaSchemeValidator implements AuthSchemeValidator {
         BetaSchemeValidator() {}
 


Test patch:
diff --git a/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/valid/sigv4subscheme-auth-scheme.errors b/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/valid/sigv4subscheme-auth-scheme.errors
new file mode 100644
index 000000000..fda5da7cb
--- /dev/null
+++ b/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/valid/sigv4subscheme-auth-scheme.errors
@@ -0,0 +1,3 @@
+[WARNING] example#FizzBuzz: This shape applies a trait that is unstable: smithy.rules#clientContextParams | UnstableTrait
+[WARNING] example#FizzBuzz: This shape applies a trait that is unstable: smithy.rules#endpointRuleSet | UnstableTrait
+[DANGER] example#FizzBuzz: Requirements for `sigv4-` auth sub-scheme validation may change. | RuleSetAuthSchemes
diff --git a/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/valid/sigv4subscheme-auth-scheme.smithy b/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/valid/sigv4subscheme-auth-scheme.smithy
new file mode 100644
index 000000000..2c14b9501
--- /dev/null
+++ b/smithy-aws-endpoints/src/test/resources/software/amazon/smithy/rulesengine/aws/language/functions/errorfiles/valid/sigv4subscheme-auth-scheme.smithy
@@ -0,0 +1,42 @@
+$version: "2.0"
+
+namespace example
+
+use smithy.rules#clientContextParams
+use smithy.rules#endpointRuleSet
+
+@endpointRuleSet({
+    "version": "1.3",
+    "parameters": {
+        "Region": {
+            "required": true,
+            "type": "String",
+            "documentation": "docs"
+        }
+    },
+    "rules": [
+        {
+            "conditions": [],
+            "documentation": "base rule",
+            "endpoint": {
+                "url": "https://{Region}.amazonaws.com",
+                "properties": {
+                    "authSchemes": [
+                        {
+                            "name": "sigv4-sub",
+                            "signingName": "serviceName",
+                            "signingRegion": "{Region}",
+                            "additionalField": "test"
+                        }
+                    ]
+                },
+                "headers": {}
+            },
+            "type": "endpoint"
+        }
+    ]
+})
+@clientContextParams(
+    Region: {type: "string", documentation: "docs"}
+)
+service FizzBuzz {}