diff --git a/lib/utils/aws/aws.go b/lib/utils/aws/aws.go index 7b0933b2c16b5..c06636c109150 100644 --- a/lib/utils/aws/aws.go +++ b/lib/utils/aws/aws.go @@ -97,24 +97,33 @@ type SigV4 struct { } // ParseSigV4 AWS SigV4 credentials string sections. -// AWS SigV4 header example: -// Authorization: AWS4-HMAC-SHA256 -// Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request, +// AWS SigV4 header example below adds newlines for readability only - the real +// header must be a single continuous string with commas (and optional spaces) +// between the Credential, SignedHeaders, and Signature: +// Authorization: AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request, // SignedHeaders=host;range;x-amz-date, // Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024 func ParseSigV4(header string) (*SigV4, error) { if header == "" { return nil, trace.BadParameter("empty AWS SigV4 header") } - sectionParts := strings.Split(header, " ") + if !strings.HasPrefix(header, AmazonSigV4AuthorizationPrefix+" ") { + return nil, trace.BadParameter("missing AWS SigV4 authorization algorithm") + } + header = strings.TrimPrefix(header, AmazonSigV4AuthorizationPrefix+" ") + + components := strings.Split(header, ",") + if len(components) != 3 { + return nil, trace.BadParameter("expected AWS SigV4 Authorization header with 3 comma-separated components but got %d", len(components)) + } m := make(map[string]string) - for _, v := range sectionParts { - kv := strings.Split(v, "=") + for _, v := range components { + kv := strings.Split(strings.Trim(v, " "), "=") if len(kv) != 2 { continue } - m[kv[0]] = strings.TrimSuffix(kv[1], ",") + m[kv[0]] = kv[1] } authParts := strings.Split(m[credentialAuthHeaderElem], "/") diff --git a/lib/utils/aws/aws_test.go b/lib/utils/aws/aws_test.go index e42da143252fa..fa7c8b67785d8 100644 --- a/lib/utils/aws/aws_test.go +++ b/lib/utils/aws/aws_test.go @@ -50,19 +50,29 @@ func TestExtractCredFromAuthHeader(t *testing.T) { wantErr: require.NoError, }, { - name: "signed headers section missing", - input: "AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request, Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024", + name: "valid header without spaces", + input: "AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request,SignedHeaders=host;x-amz-content-sha256;x-amz-date,Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024", expCred: &SigV4{ KeyID: "AKIAIOSFODNN7EXAMPLE", Date: "20130524", Region: "us-east-1", Service: "s3", Signature: "fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024", + SignedHeaders: []string{ + "host", + "x-amz-content-sha256", + "x-amz-date", + }, }, wantErr: require.NoError, }, { - name: "credential section missing", + name: "signed headers section missing", + input: "AWS4-HMAC-SHA256 Credential=AKIAIOSFODNN7EXAMPLE/20130524/us-east-1/s3/aws4_request, Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024", + wantErr: require.Error, + }, + { + name: "credential section missing", input: "AWS4-HMAC-SHA256 SignedHeaders=host;range;x-amz-date, Signature=fe5f80f77d5fa3beca038a248ff027d0445342fe2855ddc963176630326f1024", wantErr: require.Error, },