1
2
3 package ssooidc
4
5 import (
6 "context"
7 "fmt"
8 "github.com/aws/aws-sdk-go-v2/aws"
9 "github.com/aws/aws-sdk-go-v2/aws/defaults"
10 awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
11 "github.com/aws/aws-sdk-go-v2/aws/retry"
12 "github.com/aws/aws-sdk-go-v2/aws/signer/v4"
13 awshttp "github.com/aws/aws-sdk-go-v2/aws/transport/http"
14 internalauth "github.com/aws/aws-sdk-go-v2/internal/auth"
15 internalauthsmithy "github.com/aws/aws-sdk-go-v2/internal/auth/smithy"
16 internalConfig "github.com/aws/aws-sdk-go-v2/internal/configsources"
17 smithy "github.com/aws/smithy-go"
18 smithydocument "github.com/aws/smithy-go/document"
19 "github.com/aws/smithy-go/logging"
20 "github.com/aws/smithy-go/middleware"
21 smithyhttp "github.com/aws/smithy-go/transport/http"
22 "net"
23 "net/http"
24 "time"
25 )
26
27 const ServiceID = "SSO OIDC"
28 const ServiceAPIVersion = "2019-06-10"
29
30
31 type Client struct {
32 options Options
33 }
34
35
36
37
38 func New(options Options, optFns ...func(*Options)) *Client {
39 options = options.Copy()
40
41 resolveDefaultLogger(&options)
42
43 setResolvedDefaultsMode(&options)
44
45 resolveRetryer(&options)
46
47 resolveHTTPClient(&options)
48
49 resolveHTTPSignerV4(&options)
50
51 resolveEndpointResolverV2(&options)
52
53 resolveAuthSchemeResolver(&options)
54
55 for _, fn := range optFns {
56 fn(&options)
57 }
58
59 finalizeRetryMaxAttempts(&options)
60
61 ignoreAnonymousAuth(&options)
62
63 wrapWithAnonymousAuth(&options)
64
65 resolveAuthSchemes(&options)
66
67 client := &Client{
68 options: options,
69 }
70
71 return client
72 }
73
74
75
76
77
78
79 func (c *Client) Options() Options {
80 return c.options.Copy()
81 }
82
83 func (c *Client) invokeOperation(ctx context.Context, opID string, params interface{}, optFns []func(*Options), stackFns ...func(*middleware.Stack, Options) error) (result interface{}, metadata middleware.Metadata, err error) {
84 ctx = middleware.ClearStackValues(ctx)
85 stack := middleware.NewStack(opID, smithyhttp.NewStackRequest)
86 options := c.options.Copy()
87
88 for _, fn := range optFns {
89 fn(&options)
90 }
91
92 finalizeOperationRetryMaxAttempts(&options, *c)
93
94 finalizeClientEndpointResolverOptions(&options)
95
96 for _, fn := range stackFns {
97 if err := fn(stack, options); err != nil {
98 return nil, metadata, err
99 }
100 }
101
102 for _, fn := range options.APIOptions {
103 if err := fn(stack); err != nil {
104 return nil, metadata, err
105 }
106 }
107
108 handler := middleware.DecorateHandler(smithyhttp.NewClientHandler(options.HTTPClient), stack)
109 result, metadata, err = handler.Handle(ctx, params)
110 if err != nil {
111 err = &smithy.OperationError{
112 ServiceID: ServiceID,
113 OperationName: opID,
114 Err: err,
115 }
116 }
117 return result, metadata, err
118 }
119
120 type operationInputKey struct{}
121
122 func setOperationInput(ctx context.Context, input interface{}) context.Context {
123 return middleware.WithStackValue(ctx, operationInputKey{}, input)
124 }
125
126 func getOperationInput(ctx context.Context) interface{} {
127 return middleware.GetStackValue(ctx, operationInputKey{})
128 }
129
130 type setOperationInputMiddleware struct {
131 }
132
133 func (*setOperationInputMiddleware) ID() string {
134 return "setOperationInput"
135 }
136
137 func (m *setOperationInputMiddleware) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) (
138 out middleware.SerializeOutput, metadata middleware.Metadata, err error,
139 ) {
140 ctx = setOperationInput(ctx, in.Parameters)
141 return next.HandleSerialize(ctx, in)
142 }
143
144 func addProtocolFinalizerMiddlewares(stack *middleware.Stack, options Options, operation string) error {
145 if err := stack.Finalize.Add(&resolveAuthSchemeMiddleware{operation: operation, options: options}, middleware.Before); err != nil {
146 return fmt.Errorf("add ResolveAuthScheme: %w", err)
147 }
148 if err := stack.Finalize.Insert(&getIdentityMiddleware{options: options}, "ResolveAuthScheme", middleware.After); err != nil {
149 return fmt.Errorf("add GetIdentity: %v", err)
150 }
151 if err := stack.Finalize.Insert(&resolveEndpointV2Middleware{options: options}, "GetIdentity", middleware.After); err != nil {
152 return fmt.Errorf("add ResolveEndpointV2: %v", err)
153 }
154 if err := stack.Finalize.Insert(&signRequestMiddleware{}, "ResolveEndpointV2", middleware.After); err != nil {
155 return fmt.Errorf("add Signing: %w", err)
156 }
157 return nil
158 }
159 func resolveAuthSchemeResolver(options *Options) {
160 if options.AuthSchemeResolver == nil {
161 options.AuthSchemeResolver = &defaultAuthSchemeResolver{}
162 }
163 }
164
165 func resolveAuthSchemes(options *Options) {
166 if options.AuthSchemes == nil {
167 options.AuthSchemes = []smithyhttp.AuthScheme{
168 internalauth.NewHTTPAuthScheme("aws.auth#sigv4", &internalauthsmithy.V4SignerAdapter{
169 Signer: options.HTTPSignerV4,
170 Logger: options.Logger,
171 LogSigning: options.ClientLogMode.IsSigning(),
172 }),
173 }
174 }
175 }
176
177 type noSmithyDocumentSerde = smithydocument.NoSerde
178
179 type legacyEndpointContextSetter struct {
180 LegacyResolver EndpointResolver
181 }
182
183 func (*legacyEndpointContextSetter) ID() string {
184 return "legacyEndpointContextSetter"
185 }
186
187 func (m *legacyEndpointContextSetter) HandleInitialize(ctx context.Context, in middleware.InitializeInput, next middleware.InitializeHandler) (
188 out middleware.InitializeOutput, metadata middleware.Metadata, err error,
189 ) {
190 if m.LegacyResolver != nil {
191 ctx = awsmiddleware.SetRequiresLegacyEndpoints(ctx, true)
192 }
193
194 return next.HandleInitialize(ctx, in)
195
196 }
197 func addlegacyEndpointContextSetter(stack *middleware.Stack, o Options) error {
198 return stack.Initialize.Add(&legacyEndpointContextSetter{
199 LegacyResolver: o.EndpointResolver,
200 }, middleware.Before)
201 }
202
203 func resolveDefaultLogger(o *Options) {
204 if o.Logger != nil {
205 return
206 }
207 o.Logger = logging.Nop{}
208 }
209
210 func addSetLoggerMiddleware(stack *middleware.Stack, o Options) error {
211 return middleware.AddSetLoggerMiddleware(stack, o.Logger)
212 }
213
214 func setResolvedDefaultsMode(o *Options) {
215 if len(o.resolvedDefaultsMode) > 0 {
216 return
217 }
218
219 var mode aws.DefaultsMode
220 mode.SetFromString(string(o.DefaultsMode))
221
222 if mode == aws.DefaultsModeAuto {
223 mode = defaults.ResolveDefaultsModeAuto(o.Region, o.RuntimeEnvironment)
224 }
225
226 o.resolvedDefaultsMode = mode
227 }
228
229
230 func NewFromConfig(cfg aws.Config, optFns ...func(*Options)) *Client {
231 opts := Options{
232 Region: cfg.Region,
233 DefaultsMode: cfg.DefaultsMode,
234 RuntimeEnvironment: cfg.RuntimeEnvironment,
235 HTTPClient: cfg.HTTPClient,
236 Credentials: cfg.Credentials,
237 APIOptions: cfg.APIOptions,
238 Logger: cfg.Logger,
239 ClientLogMode: cfg.ClientLogMode,
240 AppID: cfg.AppID,
241 }
242 resolveAWSRetryerProvider(cfg, &opts)
243 resolveAWSRetryMaxAttempts(cfg, &opts)
244 resolveAWSRetryMode(cfg, &opts)
245 resolveAWSEndpointResolver(cfg, &opts)
246 resolveUseDualStackEndpoint(cfg, &opts)
247 resolveUseFIPSEndpoint(cfg, &opts)
248 resolveBaseEndpoint(cfg, &opts)
249 return New(opts, optFns...)
250 }
251
252 func resolveHTTPClient(o *Options) {
253 var buildable *awshttp.BuildableClient
254
255 if o.HTTPClient != nil {
256 var ok bool
257 buildable, ok = o.HTTPClient.(*awshttp.BuildableClient)
258 if !ok {
259 return
260 }
261 } else {
262 buildable = awshttp.NewBuildableClient()
263 }
264
265 modeConfig, err := defaults.GetModeConfiguration(o.resolvedDefaultsMode)
266 if err == nil {
267 buildable = buildable.WithDialerOptions(func(dialer *net.Dialer) {
268 if dialerTimeout, ok := modeConfig.GetConnectTimeout(); ok {
269 dialer.Timeout = dialerTimeout
270 }
271 })
272
273 buildable = buildable.WithTransportOptions(func(transport *http.Transport) {
274 if tlsHandshakeTimeout, ok := modeConfig.GetTLSNegotiationTimeout(); ok {
275 transport.TLSHandshakeTimeout = tlsHandshakeTimeout
276 }
277 })
278 }
279
280 o.HTTPClient = buildable
281 }
282
283 func resolveRetryer(o *Options) {
284 if o.Retryer != nil {
285 return
286 }
287
288 if len(o.RetryMode) == 0 {
289 modeConfig, err := defaults.GetModeConfiguration(o.resolvedDefaultsMode)
290 if err == nil {
291 o.RetryMode = modeConfig.RetryMode
292 }
293 }
294 if len(o.RetryMode) == 0 {
295 o.RetryMode = aws.RetryModeStandard
296 }
297
298 var standardOptions []func(*retry.StandardOptions)
299 if v := o.RetryMaxAttempts; v != 0 {
300 standardOptions = append(standardOptions, func(so *retry.StandardOptions) {
301 so.MaxAttempts = v
302 })
303 }
304
305 switch o.RetryMode {
306 case aws.RetryModeAdaptive:
307 var adaptiveOptions []func(*retry.AdaptiveModeOptions)
308 if len(standardOptions) != 0 {
309 adaptiveOptions = append(adaptiveOptions, func(ao *retry.AdaptiveModeOptions) {
310 ao.StandardOptions = append(ao.StandardOptions, standardOptions...)
311 })
312 }
313 o.Retryer = retry.NewAdaptiveMode(adaptiveOptions...)
314
315 default:
316 o.Retryer = retry.NewStandard(standardOptions...)
317 }
318 }
319
320 func resolveAWSRetryerProvider(cfg aws.Config, o *Options) {
321 if cfg.Retryer == nil {
322 return
323 }
324 o.Retryer = cfg.Retryer()
325 }
326
327 func resolveAWSRetryMode(cfg aws.Config, o *Options) {
328 if len(cfg.RetryMode) == 0 {
329 return
330 }
331 o.RetryMode = cfg.RetryMode
332 }
333 func resolveAWSRetryMaxAttempts(cfg aws.Config, o *Options) {
334 if cfg.RetryMaxAttempts == 0 {
335 return
336 }
337 o.RetryMaxAttempts = cfg.RetryMaxAttempts
338 }
339
340 func finalizeRetryMaxAttempts(o *Options) {
341 if o.RetryMaxAttempts == 0 {
342 return
343 }
344
345 o.Retryer = retry.AddWithMaxAttempts(o.Retryer, o.RetryMaxAttempts)
346 }
347
348 func finalizeOperationRetryMaxAttempts(o *Options, client Client) {
349 if v := o.RetryMaxAttempts; v == 0 || v == client.options.RetryMaxAttempts {
350 return
351 }
352
353 o.Retryer = retry.AddWithMaxAttempts(o.Retryer, o.RetryMaxAttempts)
354 }
355
356 func resolveAWSEndpointResolver(cfg aws.Config, o *Options) {
357 if cfg.EndpointResolver == nil && cfg.EndpointResolverWithOptions == nil {
358 return
359 }
360 o.EndpointResolver = withEndpointResolver(cfg.EndpointResolver, cfg.EndpointResolverWithOptions)
361 }
362
363 func addClientUserAgent(stack *middleware.Stack, options Options) error {
364 ua, err := getOrAddRequestUserAgent(stack)
365 if err != nil {
366 return err
367 }
368
369 ua.AddSDKAgentKeyValue(awsmiddleware.APIMetadata, "ssooidc", goModuleVersion)
370 if len(options.AppID) > 0 {
371 ua.AddSDKAgentKey(awsmiddleware.ApplicationIdentifier, options.AppID)
372 }
373
374 return nil
375 }
376
377 func getOrAddRequestUserAgent(stack *middleware.Stack) (*awsmiddleware.RequestUserAgent, error) {
378 id := (*awsmiddleware.RequestUserAgent)(nil).ID()
379 mw, ok := stack.Build.Get(id)
380 if !ok {
381 mw = awsmiddleware.NewRequestUserAgent()
382 if err := stack.Build.Add(mw, middleware.After); err != nil {
383 return nil, err
384 }
385 }
386
387 ua, ok := mw.(*awsmiddleware.RequestUserAgent)
388 if !ok {
389 return nil, fmt.Errorf("%T for %s middleware did not match expected type", mw, id)
390 }
391
392 return ua, nil
393 }
394
395 type HTTPSignerV4 interface {
396 SignHTTP(ctx context.Context, credentials aws.Credentials, r *http.Request, payloadHash string, service string, region string, signingTime time.Time, optFns ...func(*v4.SignerOptions)) error
397 }
398
399 func resolveHTTPSignerV4(o *Options) {
400 if o.HTTPSignerV4 != nil {
401 return
402 }
403 o.HTTPSignerV4 = newDefaultV4Signer(*o)
404 }
405
406 func newDefaultV4Signer(o Options) *v4.Signer {
407 return v4.NewSigner(func(so *v4.SignerOptions) {
408 so.Logger = o.Logger
409 so.LogSigning = o.ClientLogMode.IsSigning()
410 })
411 }
412
413 func addClientRequestID(stack *middleware.Stack) error {
414 return stack.Build.Add(&awsmiddleware.ClientRequestID{}, middleware.After)
415 }
416
417 func addComputeContentLength(stack *middleware.Stack) error {
418 return stack.Build.Add(&smithyhttp.ComputeContentLength{}, middleware.After)
419 }
420
421 func addRawResponseToMetadata(stack *middleware.Stack) error {
422 return stack.Deserialize.Add(&awsmiddleware.AddRawResponse{}, middleware.Before)
423 }
424
425 func addRecordResponseTiming(stack *middleware.Stack) error {
426 return stack.Deserialize.Add(&awsmiddleware.RecordResponseTiming{}, middleware.After)
427 }
428 func addStreamingEventsPayload(stack *middleware.Stack) error {
429 return stack.Finalize.Add(&v4.StreamingEventsPayload{}, middleware.Before)
430 }
431
432 func addUnsignedPayload(stack *middleware.Stack) error {
433 return stack.Finalize.Insert(&v4.UnsignedPayload{}, "ResolveEndpointV2", middleware.After)
434 }
435
436 func addComputePayloadSHA256(stack *middleware.Stack) error {
437 return stack.Finalize.Insert(&v4.ComputePayloadSHA256{}, "ResolveEndpointV2", middleware.After)
438 }
439
440 func addContentSHA256Header(stack *middleware.Stack) error {
441 return stack.Finalize.Insert(&v4.ContentSHA256Header{}, (*v4.ComputePayloadSHA256)(nil).ID(), middleware.After)
442 }
443
444 func addRetry(stack *middleware.Stack, o Options) error {
445 attempt := retry.NewAttemptMiddleware(o.Retryer, smithyhttp.RequestCloner, func(m *retry.Attempt) {
446 m.LogAttempts = o.ClientLogMode.IsRetries()
447 })
448 if err := stack.Finalize.Insert(attempt, "Signing", middleware.Before); err != nil {
449 return err
450 }
451 if err := stack.Finalize.Insert(&retry.MetricsHeader{}, attempt.ID(), middleware.After); err != nil {
452 return err
453 }
454 return nil
455 }
456
457
458 func resolveUseDualStackEndpoint(cfg aws.Config, o *Options) error {
459 if len(cfg.ConfigSources) == 0 {
460 return nil
461 }
462 value, found, err := internalConfig.ResolveUseDualStackEndpoint(context.Background(), cfg.ConfigSources)
463 if err != nil {
464 return err
465 }
466 if found {
467 o.EndpointOptions.UseDualStackEndpoint = value
468 }
469 return nil
470 }
471
472
473 func resolveUseFIPSEndpoint(cfg aws.Config, o *Options) error {
474 if len(cfg.ConfigSources) == 0 {
475 return nil
476 }
477 value, found, err := internalConfig.ResolveUseFIPSEndpoint(context.Background(), cfg.ConfigSources)
478 if err != nil {
479 return err
480 }
481 if found {
482 o.EndpointOptions.UseFIPSEndpoint = value
483 }
484 return nil
485 }
486
487 func addRecursionDetection(stack *middleware.Stack) error {
488 return stack.Build.Add(&awsmiddleware.RecursionDetection{}, middleware.After)
489 }
490
491 func addRequestIDRetrieverMiddleware(stack *middleware.Stack) error {
492 return stack.Deserialize.Insert(&awsmiddleware.RequestIDRetriever{}, "OperationDeserializer", middleware.Before)
493
494 }
495
496 func addResponseErrorMiddleware(stack *middleware.Stack) error {
497 return stack.Deserialize.Insert(&awshttp.ResponseErrorWrapper{}, "RequestIDRetriever", middleware.Before)
498
499 }
500
501 func addRequestResponseLogging(stack *middleware.Stack, o Options) error {
502 return stack.Deserialize.Add(&smithyhttp.RequestResponseLogger{
503 LogRequest: o.ClientLogMode.IsRequest(),
504 LogRequestWithBody: o.ClientLogMode.IsRequestWithBody(),
505 LogResponse: o.ClientLogMode.IsResponse(),
506 LogResponseWithBody: o.ClientLogMode.IsResponseWithBody(),
507 }, middleware.After)
508 }
509
510 type disableHTTPSMiddleware struct {
511 DisableHTTPS bool
512 }
513
514 func (*disableHTTPSMiddleware) ID() string {
515 return "disableHTTPS"
516 }
517
518 func (m *disableHTTPSMiddleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (
519 out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
520 ) {
521 req, ok := in.Request.(*smithyhttp.Request)
522 if !ok {
523 return out, metadata, fmt.Errorf("unknown transport type %T", in.Request)
524 }
525
526 if m.DisableHTTPS && !smithyhttp.GetHostnameImmutable(ctx) {
527 req.URL.Scheme = "http"
528 }
529
530 return next.HandleFinalize(ctx, in)
531 }
532
533 func addDisableHTTPSMiddleware(stack *middleware.Stack, o Options) error {
534 return stack.Finalize.Insert(&disableHTTPSMiddleware{
535 DisableHTTPS: o.EndpointOptions.DisableHTTPS,
536 }, "ResolveEndpointV2", middleware.After)
537 }
538
View as plain text