diff --git a/generator/ServiceClientGeneratorLib/GeneratorDriver.cs b/generator/ServiceClientGeneratorLib/GeneratorDriver.cs index 78f9c8351aeb..868f9b31e3a2 100644 --- a/generator/ServiceClientGeneratorLib/GeneratorDriver.cs +++ b/generator/ServiceClientGeneratorLib/GeneratorDriver.cs @@ -112,18 +112,6 @@ public class GeneratorDriver private static ConcurrentBag codeGeneratedServiceNames = new ConcurrentBag(); - /// - /// Collection of services for which modeled auth resolvers (i.e. using information from their model files) should be generated. - /// - /// - /// This is an allow-list for now (to prevent creating >400 files), but will be updated to a deny-list in the future (only a handful - /// of services such as S3 and EventBridge won't use modeled auth resolvers). - /// - private static readonly HashSet _allowListModeledAuthResolvers = new HashSet - { - "AutoScaling", - }; - public GeneratorDriver(ServiceConfiguration config, GenerationManifest generationManifest, GeneratorOptions options) { FilesWrittenToGeneratorFolder = new HashSet(); @@ -209,7 +197,9 @@ public void Execute() ExecuteTestGenerator(new EndpointProviderTests(), Configuration.ClassName + "EndpointProviderTests.cs", "Endpoints"); } - if (_allowListModeledAuthResolvers.Contains(Configuration.ClassName)) + // TODO: We'll eventually generate auth resolvers for all services, but only including a couple for now to keep + // the number of generated changes low. + if (Configuration.ClassName == "AutoScaling" || Configuration.ClassName == "S3") { ExecuteGenerator(new ModeledResolver(), "Amazon" + Configuration.ClassName + "AuthResolver.cs", "Internal"); } diff --git a/generator/ServiceClientGeneratorLib/Generators/AuthResolvers/ModeledResolver.cs b/generator/ServiceClientGeneratorLib/Generators/AuthResolvers/ModeledResolver.cs index ec950d80ae70..4e011a1487d8 100644 --- a/generator/ServiceClientGeneratorLib/Generators/AuthResolvers/ModeledResolver.cs +++ b/generator/ServiceClientGeneratorLib/Generators/AuthResolvers/ModeledResolver.cs @@ -79,21 +79,80 @@ public override string TransformText() #line default #line hidden - this.Write("AuthSchemeHandler : BaseAuthResolverHandler\r\n {\r\n /// \r\n " + - " /// Auth scheme resolver for AutoScaling.\r\n /// \r\n pub" + - "lic Amazon"); + this.Write("AuthSchemeHandler : BaseAuthResolverHandler\r\n {\r\n"); + + #line 38 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + if (IsServiceAllowListedForRulesBasedResolver()) { + + #line default + #line hidden + this.Write(" private readonly Amazon"); + + #line 39 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(this.Config.ClassName)); + + #line default + #line hidden + this.Write("EndpointResolver _endpointResolver = new();\r\n\r\n"); #line 41 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + } + + #line default + #line hidden + this.Write(" /// \r\n /// Modeled auth scheme resolver for "); + + #line 43 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(this.Config.ClassName)); + + #line default + #line hidden + this.Write(".\r\n /// \r\n public Amazon"); + + #line 45 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" this.Write(this.ToStringHelper.ToStringWithCulture(this.Config.ClassName)); #line default #line hidden this.Write("AuthSchemeResolver AuthSchemeResolver { get; } = new();\r\n\r\n /// \r\n protected override List ResolveAuthOptions(IRequ" + - "estContext requestContext)\r\n {\r\n var mappedParameters = new Am" + - "azon"); + "c/>\r\n protected override List ResolveAuthOptions(IExec" + + "utionContext executionContext)\r\n {\r\n"); + + #line 50 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + if (IsServiceAllowListedForRulesBasedResolver()) { - #line 46 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line default + #line hidden + this.Write(" // Since "); + + #line 51 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + this.Write(this.ToStringHelper.ToStringWithCulture(this.Config.ClassName)); + + #line default + #line hidden + this.Write(@" includes auth schemes in its endpoint rules, we'll attempt to delegate resolution to the endpoint + // resolver first (falling back to the modeled resolver if no options are returned). + var endpoint = _endpointResolver.GetEndpoint(executionContext); + + // This means the endpoints resolver is executed twice intentionally (at this point and then later in the pipeline + // to determine which endpoint the SDK should use for the request). + var endpointAuthSchemes = RetrieveSchemesFromEndpoint(endpoint); + if (endpointAuthSchemes != null) + { + return endpointAuthSchemes; + } + +"); + + #line 63 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + } + + #line default + #line hidden + this.Write(" var requestContext = executionContext.RequestContext;\r\n va" + + "r mappedParameters = new Amazon"); + + #line 65 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" this.Write(this.ToStringHelper.ToStringWithCulture(this.Config.ClassName)); #line default @@ -101,7 +160,7 @@ public override string TransformText() this.Write("AuthSchemeParameters\r\n {\r\n Operation = requestContext.R" + "equest.RequestName,\r\n"); - #line 49 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 68 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" if (IsSigV4Supported()) { #line default @@ -109,7 +168,7 @@ public override string TransformText() this.Write(" Region = requestContext.ClientConfig.RegionEndpoint?.SystemName,\r" + "\n"); - #line 51 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 70 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" } #line default @@ -118,14 +177,14 @@ public override string TransformText() "arameters);\r\n }\r\n }\r\n\r\n /// \r\n public class Amazon"); - #line 59 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 78 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" this.Write(this.ToStringHelper.ToStringWithCulture(this.Config.ClassName)); #line default #line hidden this.Write("AuthSchemeResolver : IAuthSchemeResolver\r\n {\r\n /// \r\n public List ResolveAuthScheme(Amazon"); - #line 62 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 81 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" this.Write(this.ToStringHelper.ToStringWithCulture(this.Config.ClassName)); #line default @@ -141,63 +200,63 @@ public override string TransformText() this.Write("AuthSchemeParameters authParameters)\r\n {\r\n switch (authParamete" + "rs.Operation)\r\n {\r\n"); - #line 66 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 85 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" foreach (var operation in GetOperationsWithAuthSchemes()) { #line default #line hidden this.Write("\t\t\t\tcase \""); - #line 67 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 86 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" this.Write(this.ToStringHelper.ToStringWithCulture(operation.Name)); #line default #line hidden this.Write("Request\":\r\n"); - #line 68 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 87 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" if (IsKnownSchemeList(operation.AuthSchemes, out string operationSchemesContent)) { #line default #line hidden this.Write(" return "); - #line 69 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 88 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" this.Write(this.ToStringHelper.ToStringWithCulture(operationSchemesContent)); #line default #line hidden this.Write(";\r\n"); - #line 70 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 89 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" } else { #line default #line hidden this.Write(" return new List \r\n {\r\n"); - #line 73 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 92 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" foreach (var operationScheme in operation.AuthSchemes) { #line default #line hidden this.Write(" new AuthSchemeOption { SchemeId = \""); - #line 74 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 93 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" this.Write(this.ToStringHelper.ToStringWithCulture(operationScheme)); #line default #line hidden this.Write("\" },\r\n"); - #line 75 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 94 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" } #line default #line hidden this.Write(" };\r\n"); - #line 77 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 96 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" }} #line default @@ -205,49 +264,49 @@ public override string TransformText() this.Write(" default:\r\n // Default for the service, applies" + " to all remaining operations.\r\n"); - #line 80 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 99 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" if (IsKnownSchemeList(GetServiceAuthSchemes(), out string serviceSchemesContent)) { #line default #line hidden this.Write(" return "); - #line 81 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 100 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" this.Write(this.ToStringHelper.ToStringWithCulture(serviceSchemesContent)); #line default #line hidden this.Write(";\r\n"); - #line 82 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 101 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" } else { #line default #line hidden this.Write(" return new List \r\n {\r\n"); - #line 85 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 104 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" foreach (var serviceScheme in GetServiceAuthSchemes()) { #line default #line hidden this.Write(" \t\t new AuthSchemeOption { SchemeId = \""); - #line 86 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 105 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" this.Write(this.ToStringHelper.ToStringWithCulture(serviceScheme)); #line default #line hidden this.Write("\" },\r\n"); - #line 87 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 106 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" } #line default #line hidden this.Write(" };\r\n"); - #line 89 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" + #line 108 "C:\Projects\aws-sdk-net-v4\generator\ServiceClientGeneratorLib\Generators\AuthResolvers\ModeledResolver.tt" } #line default diff --git a/generator/ServiceClientGeneratorLib/Generators/AuthResolvers/ModeledResolver.partial.cs b/generator/ServiceClientGeneratorLib/Generators/AuthResolvers/ModeledResolver.partial.cs index 533bbf402e61..ea654cba4da6 100644 --- a/generator/ServiceClientGeneratorLib/Generators/AuthResolvers/ModeledResolver.partial.cs +++ b/generator/ServiceClientGeneratorLib/Generators/AuthResolvers/ModeledResolver.partial.cs @@ -5,6 +5,20 @@ namespace ServiceClientGenerator.Generators.AuthResolvers { public partial class ModeledResolver { + private readonly HashSet _allowListedServices = new HashSet + { + "S3", + "EventBridge", + "SimpleEmailServiceV2", + "CloudFrontKeyValueStore", + }; + + /// + /// Returns whether the generated resolver should delegate auth scheme resolution to the endpoints resolver. + /// + private bool IsServiceAllowListedForRulesBasedResolver() => + _allowListedServices.Contains(Config.ClassName); + /// /// Returns whether this service supports SigV4 (and therefore should include region in its auth scheme parameters). /// diff --git a/generator/ServiceClientGeneratorLib/Generators/AuthResolvers/ModeledResolver.tt b/generator/ServiceClientGeneratorLib/Generators/AuthResolvers/ModeledResolver.tt index 7beac04d2b04..24d19c04cf34 100644 --- a/generator/ServiceClientGeneratorLib/Generators/AuthResolvers/ModeledResolver.tt +++ b/generator/ServiceClientGeneratorLib/Generators/AuthResolvers/ModeledResolver.tt @@ -35,14 +35,33 @@ namespace <#=this.Config.Namespace#>.Internal /// public class Amazon<#=this.Config.ClassName#>AuthSchemeHandler : BaseAuthResolverHandler { +<# if (IsServiceAllowListedForRulesBasedResolver()) { #> + private readonly Amazon<#=this.Config.ClassName#>EndpointResolver _endpointResolver = new(); + +<# } #> /// - /// Auth scheme resolver for AutoScaling. + /// Modeled auth scheme resolver for <#=this.Config.ClassName#>. /// public Amazon<#=this.Config.ClassName#>AuthSchemeResolver AuthSchemeResolver { get; } = new(); /// - protected override List ResolveAuthOptions(IRequestContext requestContext) + protected override List ResolveAuthOptions(IExecutionContext executionContext) { +<# if (IsServiceAllowListedForRulesBasedResolver()) { #> + // Since <#=this.Config.ClassName#> includes auth schemes in its endpoint rules, we'll attempt to delegate resolution to the endpoint + // resolver first (falling back to the modeled resolver if no options are returned). + var endpoint = _endpointResolver.GetEndpoint(executionContext); + + // This means the endpoints resolver is executed twice intentionally (at this point and then later in the pipeline + // to determine which endpoint the SDK should use for the request). + var endpointAuthSchemes = RetrieveSchemesFromEndpoint(endpoint); + if (endpointAuthSchemes != null) + { + return endpointAuthSchemes; + } + +<# } #> + var requestContext = executionContext.RequestContext; var mappedParameters = new Amazon<#=this.Config.ClassName#>AuthSchemeParameters { Operation = requestContext.Request.RequestName, diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AnonymousAuthScheme.cs b/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AnonymousAuthScheme.cs index d746468266e8..a9144a3c5b0e 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AnonymousAuthScheme.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AnonymousAuthScheme.cs @@ -23,7 +23,7 @@ namespace Amazon.Runtime.Credentials.Internal public class AnonymousAuthScheme : IAuthScheme { /// - public string SchemeId => "smithy.api#noAuth"; + public string SchemeId => AuthSchemeOption.NoAuth; /// public IIdentityResolver GetIdentityResolver(IIdentityResolverConfiguration configuration) diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AuthSchemeOption.cs b/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AuthSchemeOption.cs index 2e4dc414cf71..fd8c2c275c3c 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AuthSchemeOption.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AuthSchemeOption.cs @@ -23,12 +23,17 @@ public class AuthSchemeOption : IAuthSchemeOption /// public string SchemeId { get; set; } + internal const string SigV4 = "aws.auth#sigv4"; + internal const string SigV4A = "aws.auth#sigv4a"; + internal const string Bearer = "smithy.api#httpBearerAuth"; + internal const string NoAuth = "smithy.api#noAuth"; + /// /// Default auth scheme options for services / operations that only support SigV4. /// public static readonly List DEFAULT_SIGV4 = new() { - new AuthSchemeOption { SchemeId = "aws.auth#sigv4" }, + new AuthSchemeOption { SchemeId = SigV4 }, }; /// @@ -36,7 +41,7 @@ public class AuthSchemeOption : IAuthSchemeOption /// public static readonly List DEFAULT_SIGV4A = new() { - new AuthSchemeOption { SchemeId = "aws.auth#sigv4a" }, + new AuthSchemeOption { SchemeId = SigV4A }, }; /// @@ -44,8 +49,8 @@ public class AuthSchemeOption : IAuthSchemeOption /// public static readonly List DEFAULT_SIGV4_SIGV4A = new() { - new AuthSchemeOption { SchemeId = "aws.auth#sigv4" }, - new AuthSchemeOption { SchemeId = "aws.auth#sigv4a" }, + new AuthSchemeOption { SchemeId = SigV4 }, + new AuthSchemeOption { SchemeId = SigV4A }, }; /// @@ -53,7 +58,7 @@ public class AuthSchemeOption : IAuthSchemeOption /// public static readonly List DEFAULT_BEARER = new() { - new AuthSchemeOption { SchemeId = "smithy.api#httpBearerAuth" }, + new AuthSchemeOption { SchemeId = Bearer }, }; /// @@ -61,7 +66,7 @@ public class AuthSchemeOption : IAuthSchemeOption /// public static readonly List DEFAULT_NOAUTH = new() { - new AuthSchemeOption { SchemeId = "smithy.api#noAuth" }, + new AuthSchemeOption { SchemeId = NoAuth }, }; } } diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AwsV4AuthScheme.cs b/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AwsV4AuthScheme.cs index c13995d7a9a1..65fa72c1c411 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AwsV4AuthScheme.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AwsV4AuthScheme.cs @@ -24,7 +24,7 @@ namespace Amazon.Runtime.Credentials.Internal public class AwsV4AuthScheme : IAuthScheme { /// - public string SchemeId => "aws.auth#sigv4"; + public string SchemeId => AuthSchemeOption.SigV4; /// public IIdentityResolver GetIdentityResolver(IIdentityResolverConfiguration configuration) diff --git a/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AwsV4aAuthScheme.cs b/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AwsV4aAuthScheme.cs index b997fd7d9262..a416c108f9e9 100644 --- a/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AwsV4aAuthScheme.cs +++ b/sdk/src/Core/Amazon.Runtime/Credentials/Internal/AwsV4aAuthScheme.cs @@ -24,7 +24,7 @@ namespace Amazon.Runtime.Credentials.Internal public class AwsV4aAuthScheme : IAuthScheme { /// - public string SchemeId => "aws.auth#sigv4a"; + public string SchemeId => AuthSchemeOption.SigV4A; /// public IIdentityResolver GetIdentityResolver(IIdentityResolverConfiguration configuration) diff --git a/sdk/src/Core/Amazon.Runtime/Pipeline/Handlers/BaseAuthResolverHandler.cs b/sdk/src/Core/Amazon.Runtime/Pipeline/Handlers/BaseAuthResolverHandler.cs index 149dcf10c97c..01063432e77a 100644 --- a/sdk/src/Core/Amazon.Runtime/Pipeline/Handlers/BaseAuthResolverHandler.cs +++ b/sdk/src/Core/Amazon.Runtime/Pipeline/Handlers/BaseAuthResolverHandler.cs @@ -14,7 +14,9 @@ */ using Amazon.Runtime.Credentials.Internal; +using Amazon.Runtime.Endpoints; using Smithy.Identity.Abstractions; +using System.Collections; using System.Collections.Generic; using System.Linq; @@ -39,7 +41,7 @@ public override void InvokeSync(IExecutionContext executionContext) protected void PreInvoke(IExecutionContext executionContext) { - var authOptions = ResolveAuthOptions(executionContext.RequestContext); + var authOptions = ResolveAuthOptions(executionContext); if (authOptions == null || !authOptions.Any()) { throw new AmazonClientException("TBD - no valid auth schemes for the current request"); @@ -65,9 +67,66 @@ protected void PreInvoke(IExecutionContext executionContext) } } + /// + /// Certain allow-listed services contain auth schemes in their endpoint ruleset. For those, we'll attempt to + /// retrieve the auth options from the attributes of the resolved endpoint. + /// + protected static List RetrieveSchemesFromEndpoint(Endpoint endpoint) + { + if (endpoint == null || endpoint.Attributes == null) + { + return null; + } + + var authSchemes = endpoint.Attributes["authSchemes"] as IList; + if (authSchemes == null) + { + return null; + } + + var schemeNames = authSchemes.OfType().Select(scheme => (string)scheme["name"]).ToList(); + + // If there's only one scheme, we'll try to return one of the default collections to avoid extra allocations. + if (schemeNames.Count == 1) + { + var schemeName = schemeNames.First(); + switch (schemeName) + { + case "sigv4": + case "sigv4-s3express": + return AuthSchemeOption.DEFAULT_SIGV4; + case "sigv4a": + return AuthSchemeOption.DEFAULT_SIGV4A; + default: + break; + } + } + + // If there's more than one scheme, we'll just return them as is (adding prefixes since the model doesn't have them). + // Another important callout is that the BaseEndpointResolver will handle populating the request context with additional + // parameters from the endpoint attributes (e.g. whether to disable double encoding). + var options = new List(); + foreach (var schemeName in schemeNames) + { + switch (schemeName) + { + case "sigv4": + case "sigv4-s3express": + options.Add(new AuthSchemeOption { SchemeId = AuthSchemeOption.SigV4 }); + break; + case "sigv4a": + options.Add(new AuthSchemeOption { SchemeId = AuthSchemeOption.SigV4A }); + break; + default: + break; + } + } + return options; + } + /// /// Invokes the service auth scheme resolver to determine which auth options we should consider for this request. /// - protected abstract List ResolveAuthOptions(IRequestContext requestContext); + protected abstract List ResolveAuthOptions(IExecutionContext executionContext); } } diff --git a/sdk/src/Services/AutoScaling/Generated/Internal/AmazonAutoScalingAuthResolver.cs b/sdk/src/Services/AutoScaling/Generated/Internal/AmazonAutoScalingAuthResolver.cs index e55df6aef3ab..84eda5d50a82 100644 --- a/sdk/src/Services/AutoScaling/Generated/Internal/AmazonAutoScalingAuthResolver.cs +++ b/sdk/src/Services/AutoScaling/Generated/Internal/AmazonAutoScalingAuthResolver.cs @@ -43,13 +43,14 @@ public class AmazonAutoScalingAuthSchemeParameters : IAuthSchemeParameters public class AmazonAutoScalingAuthSchemeHandler : BaseAuthResolverHandler { /// - /// Auth scheme resolver for AutoScaling. + /// Modeled auth scheme resolver for AutoScaling. /// public AmazonAutoScalingAuthSchemeResolver AuthSchemeResolver { get; } = new(); /// - protected override List ResolveAuthOptions(IRequestContext requestContext) + protected override List ResolveAuthOptions(IExecutionContext executionContext) { + var requestContext = executionContext.RequestContext; var mappedParameters = new AmazonAutoScalingAuthSchemeParameters { Operation = requestContext.Request.RequestName, diff --git a/sdk/src/Services/S3/Generated/Internal/AmazonS3AuthResolver.cs b/sdk/src/Services/S3/Generated/Internal/AmazonS3AuthResolver.cs new file mode 100644 index 000000000000..7f9be298b1dd --- /dev/null +++ b/sdk/src/Services/S3/Generated/Internal/AmazonS3AuthResolver.cs @@ -0,0 +1,92 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"). + * You may not use this file except in compliance with the License. + * A copy of the License is located at + * + * http://aws.amazon.com/apache2.0 + * + * or in the "license" file accompanying this file. This file is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ + +/* + * Do not modify this file. This file is generated from the s3-2006-03-01.normal.json service model. + */ + +using Amazon.Runtime; +using Amazon.Runtime.Credentials.Internal; +using Amazon.Runtime.Internal; +using Smithy.Identity.Abstractions; +using System.Collections.Generic; + +namespace Amazon.S3.Internal +{ + /// + public class AmazonS3AuthSchemeParameters : IAuthSchemeParameters + { + /// + public string Operation { get; set; } + + /// + /// Region is included as the service supports SigV4. + /// + public string Region { get; set; } + } + + /// + /// Handler responsible for converting the request context into the parameters expected by the auth scheme resolver. + /// + public class AmazonS3AuthSchemeHandler : BaseAuthResolverHandler + { + private readonly AmazonS3EndpointResolver _endpointResolver = new(); + + /// + /// Modeled auth scheme resolver for S3. + /// + public AmazonS3AuthSchemeResolver AuthSchemeResolver { get; } = new(); + + /// + protected override List ResolveAuthOptions(IExecutionContext executionContext) + { + // Since S3 includes auth schemes in its endpoint rules, we'll attempt to delegate resolution to the endpoint + // resolver first (falling back to the modeled resolver if no options are returned). + var endpoint = _endpointResolver.GetEndpoint(executionContext); + + // This means the endpoints resolver is executed twice intentionally (at this point and then later in the pipeline + // to determine which endpoint the SDK should use for the request). + var endpointAuthSchemes = RetrieveSchemesFromEndpoint(endpoint); + if (endpointAuthSchemes != null) + { + return endpointAuthSchemes; + } + + var requestContext = executionContext.RequestContext; + var mappedParameters = new AmazonS3AuthSchemeParameters + { + Operation = requestContext.Request.RequestName, + Region = requestContext.ClientConfig.RegionEndpoint?.SystemName, + }; + + return AuthSchemeResolver.ResolveAuthScheme(mappedParameters); + } + } + + /// + public class AmazonS3AuthSchemeResolver : IAuthSchemeResolver + { + /// + public List ResolveAuthScheme(AmazonS3AuthSchemeParameters authParameters) + { + switch (authParameters.Operation) + { + default: + // Default for the service, applies to all remaining operations. + return AuthSchemeOption.DEFAULT_SIGV4; + } + } + } +} \ No newline at end of file