1
2
3 package ssooidc
4
5 import (
6 "context"
7 "fmt"
8 awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
9 smithy "github.com/aws/smithy-go"
10 smithyauth "github.com/aws/smithy-go/auth"
11 "github.com/aws/smithy-go/middleware"
12 smithyhttp "github.com/aws/smithy-go/transport/http"
13 )
14
15 func bindAuthParamsRegion(params *AuthResolverParameters, _ interface{}, options Options) {
16 params.Region = options.Region
17 }
18
19 type setLegacyContextSigningOptionsMiddleware struct {
20 }
21
22 func (*setLegacyContextSigningOptionsMiddleware) ID() string {
23 return "setLegacyContextSigningOptions"
24 }
25
26 func (m *setLegacyContextSigningOptionsMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (
27 out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
28 ) {
29 rscheme := getResolvedAuthScheme(ctx)
30 schemeID := rscheme.Scheme.SchemeID()
31
32 if sn := awsmiddleware.GetSigningName(ctx); sn != "" {
33 if schemeID == "aws.auth#sigv4" {
34 smithyhttp.SetSigV4SigningName(&rscheme.SignerProperties, sn)
35 } else if schemeID == "aws.auth#sigv4a" {
36 smithyhttp.SetSigV4ASigningName(&rscheme.SignerProperties, sn)
37 }
38 }
39
40 if sr := awsmiddleware.GetSigningRegion(ctx); sr != "" {
41 if schemeID == "aws.auth#sigv4" {
42 smithyhttp.SetSigV4SigningRegion(&rscheme.SignerProperties, sr)
43 } else if schemeID == "aws.auth#sigv4a" {
44 smithyhttp.SetSigV4ASigningRegions(&rscheme.SignerProperties, []string{sr})
45 }
46 }
47
48 return next.HandleFinalize(ctx, in)
49 }
50
51 func addSetLegacyContextSigningOptionsMiddleware(stack *middleware.Stack) error {
52 return stack.Finalize.Insert(&setLegacyContextSigningOptionsMiddleware{}, "Signing", middleware.Before)
53 }
54
55 type withAnonymous struct {
56 resolver AuthSchemeResolver
57 }
58
59 var _ AuthSchemeResolver = (*withAnonymous)(nil)
60
61 func (v *withAnonymous) ResolveAuthSchemes(ctx context.Context, params *AuthResolverParameters) ([]*smithyauth.Option, error) {
62 opts, err := v.resolver.ResolveAuthSchemes(ctx, params)
63 if err != nil {
64 return nil, err
65 }
66
67 opts = append(opts, &smithyauth.Option{
68 SchemeID: smithyauth.SchemeIDAnonymous,
69 })
70 return opts, nil
71 }
72
73 func wrapWithAnonymousAuth(options *Options) {
74 if _, ok := options.AuthSchemeResolver.(*defaultAuthSchemeResolver); !ok {
75 return
76 }
77
78 options.AuthSchemeResolver = &withAnonymous{
79 resolver: options.AuthSchemeResolver,
80 }
81 }
82
83
84
85 type AuthResolverParameters struct {
86
87 Operation string
88
89
90 Region string
91 }
92
93 func bindAuthResolverParams(operation string, input interface{}, options Options) *AuthResolverParameters {
94 params := &AuthResolverParameters{
95 Operation: operation,
96 }
97
98 bindAuthParamsRegion(params, input, options)
99
100 return params
101 }
102
103
104
105 type AuthSchemeResolver interface {
106 ResolveAuthSchemes(context.Context, *AuthResolverParameters) ([]*smithyauth.Option, error)
107 }
108
109 type defaultAuthSchemeResolver struct{}
110
111 var _ AuthSchemeResolver = (*defaultAuthSchemeResolver)(nil)
112
113 func (*defaultAuthSchemeResolver) ResolveAuthSchemes(ctx context.Context, params *AuthResolverParameters) ([]*smithyauth.Option, error) {
114 if overrides, ok := operationAuthOptions[params.Operation]; ok {
115 return overrides(params), nil
116 }
117 return serviceAuthOptions(params), nil
118 }
119
120 var operationAuthOptions = map[string]func(*AuthResolverParameters) []*smithyauth.Option{
121 "CreateToken": func(params *AuthResolverParameters) []*smithyauth.Option {
122 return []*smithyauth.Option{
123 {SchemeID: smithyauth.SchemeIDAnonymous},
124 }
125 },
126
127 "RegisterClient": func(params *AuthResolverParameters) []*smithyauth.Option {
128 return []*smithyauth.Option{
129 {SchemeID: smithyauth.SchemeIDAnonymous},
130 }
131 },
132
133 "StartDeviceAuthorization": func(params *AuthResolverParameters) []*smithyauth.Option {
134 return []*smithyauth.Option{
135 {SchemeID: smithyauth.SchemeIDAnonymous},
136 }
137 },
138 }
139
140 func serviceAuthOptions(params *AuthResolverParameters) []*smithyauth.Option {
141 return []*smithyauth.Option{
142 {
143 SchemeID: smithyauth.SchemeIDSigV4,
144 SignerProperties: func() smithy.Properties {
145 var props smithy.Properties
146 smithyhttp.SetSigV4SigningName(&props, "sso-oauth")
147 smithyhttp.SetSigV4SigningRegion(&props, params.Region)
148 return props
149 }(),
150 },
151 }
152 }
153
154 type resolveAuthSchemeMiddleware struct {
155 operation string
156 options Options
157 }
158
159 func (*resolveAuthSchemeMiddleware) ID() string {
160 return "ResolveAuthScheme"
161 }
162
163 func (m *resolveAuthSchemeMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (
164 out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
165 ) {
166 params := bindAuthResolverParams(m.operation, getOperationInput(ctx), m.options)
167 options, err := m.options.AuthSchemeResolver.ResolveAuthSchemes(ctx, params)
168 if err != nil {
169 return out, metadata, fmt.Errorf("resolve auth scheme: %w", err)
170 }
171
172 scheme, ok := m.selectScheme(options)
173 if !ok {
174 return out, metadata, fmt.Errorf("could not select an auth scheme")
175 }
176
177 ctx = setResolvedAuthScheme(ctx, scheme)
178 return next.HandleFinalize(ctx, in)
179 }
180
181 func (m *resolveAuthSchemeMiddleware) selectScheme(options []*smithyauth.Option) (*resolvedAuthScheme, bool) {
182 for _, option := range options {
183 if option.SchemeID == smithyauth.SchemeIDAnonymous {
184 return newResolvedAuthScheme(smithyhttp.NewAnonymousScheme(), option), true
185 }
186
187 for _, scheme := range m.options.AuthSchemes {
188 if scheme.SchemeID() != option.SchemeID {
189 continue
190 }
191
192 if scheme.IdentityResolver(m.options) != nil {
193 return newResolvedAuthScheme(scheme, option), true
194 }
195 }
196 }
197
198 return nil, false
199 }
200
201 type resolvedAuthSchemeKey struct{}
202
203 type resolvedAuthScheme struct {
204 Scheme smithyhttp.AuthScheme
205 IdentityProperties smithy.Properties
206 SignerProperties smithy.Properties
207 }
208
209 func newResolvedAuthScheme(scheme smithyhttp.AuthScheme, option *smithyauth.Option) *resolvedAuthScheme {
210 return &resolvedAuthScheme{
211 Scheme: scheme,
212 IdentityProperties: option.IdentityProperties,
213 SignerProperties: option.SignerProperties,
214 }
215 }
216
217 func setResolvedAuthScheme(ctx context.Context, scheme *resolvedAuthScheme) context.Context {
218 return middleware.WithStackValue(ctx, resolvedAuthSchemeKey{}, scheme)
219 }
220
221 func getResolvedAuthScheme(ctx context.Context) *resolvedAuthScheme {
222 v, _ := middleware.GetStackValue(ctx, resolvedAuthSchemeKey{}).(*resolvedAuthScheme)
223 return v
224 }
225
226 type getIdentityMiddleware struct {
227 options Options
228 }
229
230 func (*getIdentityMiddleware) ID() string {
231 return "GetIdentity"
232 }
233
234 func (m *getIdentityMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (
235 out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
236 ) {
237 rscheme := getResolvedAuthScheme(ctx)
238 if rscheme == nil {
239 return out, metadata, fmt.Errorf("no resolved auth scheme")
240 }
241
242 resolver := rscheme.Scheme.IdentityResolver(m.options)
243 if resolver == nil {
244 return out, metadata, fmt.Errorf("no identity resolver")
245 }
246
247 identity, err := resolver.GetIdentity(ctx, rscheme.IdentityProperties)
248 if err != nil {
249 return out, metadata, fmt.Errorf("get identity: %w", err)
250 }
251
252 ctx = setIdentity(ctx, identity)
253 return next.HandleFinalize(ctx, in)
254 }
255
256 type identityKey struct{}
257
258 func setIdentity(ctx context.Context, identity smithyauth.Identity) context.Context {
259 return middleware.WithStackValue(ctx, identityKey{}, identity)
260 }
261
262 func getIdentity(ctx context.Context) smithyauth.Identity {
263 v, _ := middleware.GetStackValue(ctx, identityKey{}).(smithyauth.Identity)
264 return v
265 }
266
267 type signRequestMiddleware struct {
268 }
269
270 func (*signRequestMiddleware) ID() string {
271 return "Signing"
272 }
273
274 func (m *signRequestMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (
275 out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
276 ) {
277 req, ok := in.Request.(*smithyhttp.Request)
278 if !ok {
279 return out, metadata, fmt.Errorf("unexpected transport type %T", in.Request)
280 }
281
282 rscheme := getResolvedAuthScheme(ctx)
283 if rscheme == nil {
284 return out, metadata, fmt.Errorf("no resolved auth scheme")
285 }
286
287 identity := getIdentity(ctx)
288 if identity == nil {
289 return out, metadata, fmt.Errorf("no identity")
290 }
291
292 signer := rscheme.Scheme.Signer()
293 if signer == nil {
294 return out, metadata, fmt.Errorf("no signer")
295 }
296
297 if err := signer.SignRequest(ctx, req, identity, rscheme.SignerProperties); err != nil {
298 return out, metadata, fmt.Errorf("sign request: %w", err)
299 }
300
301 return next.HandleFinalize(ctx, in)
302 }
303
View as plain text