1package auth
2
3import (
4 "context"
5 "fmt"
6
7 smithy "github.com/aws/smithy-go"
8 "github.com/aws/smithy-go/middleware"
9)
10
11// SigV4 is a constant representing
12// Authentication Scheme Signature Version 4
13const SigV4 = "sigv4"
14
15// SigV4A is a constant representing
16// Authentication Scheme Signature Version 4A
17const SigV4A = "sigv4a"
18
19// SigV4S3Express identifies the S3 S3Express auth scheme.
20const SigV4S3Express = "sigv4-s3express"
21
22// None is a constant representing the
23// None Authentication Scheme
24const None = "none"
25
26// SupportedSchemes is a data structure
27// that indicates the list of supported AWS
28// authentication schemes
29var SupportedSchemes = map[string]bool{
30 SigV4: true,
31 SigV4A: true,
32 SigV4S3Express: true,
33 None: true,
34}
35
36// AuthenticationScheme is a representation of
37// AWS authentication schemes
38type AuthenticationScheme interface {
39 isAuthenticationScheme()
40}
41
42// AuthenticationSchemeV4 is a AWS SigV4 representation
43type AuthenticationSchemeV4 struct {
44 Name string
45 SigningName *string
46 SigningRegion *string
47 DisableDoubleEncoding *bool
48}
49
50func (a *AuthenticationSchemeV4) isAuthenticationScheme() {}
51
52// AuthenticationSchemeV4A is a AWS SigV4A representation
53type AuthenticationSchemeV4A struct {
54 Name string
55 SigningName *string
56 SigningRegionSet []string
57 DisableDoubleEncoding *bool
58}
59
60func (a *AuthenticationSchemeV4A) isAuthenticationScheme() {}
61
62// AuthenticationSchemeNone is a representation for the none auth scheme
63type AuthenticationSchemeNone struct{}
64
65func (a *AuthenticationSchemeNone) isAuthenticationScheme() {}
66
67// NoAuthenticationSchemesFoundError is used in signaling
68// that no authentication schemes have been specified.
69type NoAuthenticationSchemesFoundError struct{}
70
71func (e *NoAuthenticationSchemesFoundError) Error() string {
72 return fmt.Sprint("No authentication schemes specified.")
73}
74
75// UnSupportedAuthenticationSchemeSpecifiedError is used in
76// signaling that only unsupported authentication schemes
77// were specified.
78type UnSupportedAuthenticationSchemeSpecifiedError struct {
79 UnsupportedSchemes []string
80}
81
82func (e *UnSupportedAuthenticationSchemeSpecifiedError) Error() string {
83 return fmt.Sprint("Unsupported authentication scheme specified.")
84}
85
86// GetAuthenticationSchemes extracts the relevant authentication scheme data
87// into a custom strongly typed Go data structure.
88func GetAuthenticationSchemes(p *smithy.Properties) ([]AuthenticationScheme, error) {
89 var result []AuthenticationScheme
90 if !p.Has("authSchemes") {
91 return nil, &NoAuthenticationSchemesFoundError{}
92 }
93
94 authSchemes, _ := p.Get("authSchemes").([]interface{})
95
96 var unsupportedSchemes []string
97 for _, scheme := range authSchemes {
98 authScheme, _ := scheme.(map[string]interface{})
99
100 version := authScheme["name"].(string)
101 switch version {
102 case SigV4, SigV4S3Express:
103 v4Scheme := AuthenticationSchemeV4{
104 Name: version,
105 SigningName: getSigningName(authScheme),
106 SigningRegion: getSigningRegion(authScheme),
107 DisableDoubleEncoding: getDisableDoubleEncoding(authScheme),
108 }
109 result = append(result, AuthenticationScheme(&v4Scheme))
110 case SigV4A:
111 v4aScheme := AuthenticationSchemeV4A{
112 Name: SigV4A,
113 SigningName: getSigningName(authScheme),
114 SigningRegionSet: getSigningRegionSet(authScheme),
115 DisableDoubleEncoding: getDisableDoubleEncoding(authScheme),
116 }
117 result = append(result, AuthenticationScheme(&v4aScheme))
118 case None:
119 noneScheme := AuthenticationSchemeNone{}
120 result = append(result, AuthenticationScheme(&noneScheme))
121 default:
122 unsupportedSchemes = append(unsupportedSchemes, authScheme["name"].(string))
123 continue
124 }
125 }
126
127 if len(result) == 0 {
128 return nil, &UnSupportedAuthenticationSchemeSpecifiedError{
129 UnsupportedSchemes: unsupportedSchemes,
130 }
131 }
132
133 return result, nil
134}
135
136type disableDoubleEncoding struct{}
137
138// SetDisableDoubleEncoding sets or modifies the disable double encoding option
139// on the context.
140//
141// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
142// to clear all stack values.
143func SetDisableDoubleEncoding(ctx context.Context, value bool) context.Context {
144 return middleware.WithStackValue(ctx, disableDoubleEncoding{}, value)
145}
146
147// GetDisableDoubleEncoding retrieves the disable double encoding option
148// from the context.
149//
150// Scoped to stack values. Use github.com/aws/smithy-go/middleware#ClearStackValues
151// to clear all stack values.
152func GetDisableDoubleEncoding(ctx context.Context) (value bool, ok bool) {
153 value, ok = middleware.GetStackValue(ctx, disableDoubleEncoding{}).(bool)
154 return value, ok
155}
156
157func getSigningName(authScheme map[string]interface{}) *string {
158 signingName, ok := authScheme["signingName"].(string)
159 if !ok || signingName == "" {
160 return nil
161 }
162 return &signingName
163}
164
165func getSigningRegionSet(authScheme map[string]interface{}) []string {
166 untypedSigningRegionSet, ok := authScheme["signingRegionSet"].([]interface{})
167 if !ok {
168 return nil
169 }
170 signingRegionSet := []string{}
171 for _, item := range untypedSigningRegionSet {
172 signingRegionSet = append(signingRegionSet, item.(string))
173 }
174 return signingRegionSet
175}
176
177func getSigningRegion(authScheme map[string]interface{}) *string {
178 signingRegion, ok := authScheme["signingRegion"].(string)
179 if !ok || signingRegion == "" {
180 return nil
181 }
182 return &signingRegion
183}
184
185func getDisableDoubleEncoding(authScheme map[string]interface{}) *bool {
186 disableDoubleEncoding, ok := authScheme["disableDoubleEncoding"].(bool)
187 if !ok {
188 return nil
189 }
190 return &disableDoubleEncoding
191}