1// Code generated by smithy-go-codegen DO NOT EDIT.
2
3package ssooidc
4
5import (
6 "context"
7 "errors"
8 "fmt"
9 "github.com/aws/aws-sdk-go-v2/aws"
10 awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware"
11 internalConfig "github.com/aws/aws-sdk-go-v2/internal/configsources"
12 "github.com/aws/aws-sdk-go-v2/internal/endpoints"
13 "github.com/aws/aws-sdk-go-v2/internal/endpoints/awsrulesfn"
14 internalendpoints "github.com/aws/aws-sdk-go-v2/service/ssooidc/internal/endpoints"
15 smithyauth "github.com/aws/smithy-go/auth"
16 smithyendpoints "github.com/aws/smithy-go/endpoints"
17 "github.com/aws/smithy-go/middleware"
18 "github.com/aws/smithy-go/ptr"
19 smithyhttp "github.com/aws/smithy-go/transport/http"
20 "net/http"
21 "net/url"
22 "os"
23 "strings"
24)
25
26// EndpointResolverOptions is the service endpoint resolver options
27type EndpointResolverOptions = internalendpoints.Options
28
29// EndpointResolver interface for resolving service endpoints.
30type EndpointResolver interface {
31 ResolveEndpoint(region string, options EndpointResolverOptions) (aws.Endpoint, error)
32}
33
34var _ EndpointResolver = &internalendpoints.Resolver{}
35
36// NewDefaultEndpointResolver constructs a new service endpoint resolver
37func NewDefaultEndpointResolver() *internalendpoints.Resolver {
38 return internalendpoints.New()
39}
40
41// EndpointResolverFunc is a helper utility that wraps a function so it satisfies
42// the EndpointResolver interface. This is useful when you want to add additional
43// endpoint resolving logic, or stub out specific endpoints with custom values.
44type EndpointResolverFunc func(region string, options EndpointResolverOptions) (aws.Endpoint, error)
45
46func (fn EndpointResolverFunc) ResolveEndpoint(region string, options EndpointResolverOptions) (endpoint aws.Endpoint, err error) {
47 return fn(region, options)
48}
49
50// EndpointResolverFromURL returns an EndpointResolver configured using the
51// provided endpoint url. By default, the resolved endpoint resolver uses the
52// client region as signing region, and the endpoint source is set to
53// EndpointSourceCustom.You can provide functional options to configure endpoint
54// values for the resolved endpoint.
55func EndpointResolverFromURL(url string, optFns ...func(*aws.Endpoint)) EndpointResolver {
56 e := aws.Endpoint{URL: url, Source: aws.EndpointSourceCustom}
57 for _, fn := range optFns {
58 fn(&e)
59 }
60
61 return EndpointResolverFunc(
62 func(region string, options EndpointResolverOptions) (aws.Endpoint, error) {
63 if len(e.SigningRegion) == 0 {
64 e.SigningRegion = region
65 }
66 return e, nil
67 },
68 )
69}
70
71type ResolveEndpoint struct {
72 Resolver EndpointResolver
73 Options EndpointResolverOptions
74}
75
76func (*ResolveEndpoint) ID() string {
77 return "ResolveEndpoint"
78}
79
80func (m *ResolveEndpoint) HandleSerialize(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) (
81 out middleware.SerializeOutput, metadata middleware.Metadata, err error,
82) {
83 if !awsmiddleware.GetRequiresLegacyEndpoints(ctx) {
84 return next.HandleSerialize(ctx, in)
85 }
86
87 req, ok := in.Request.(*smithyhttp.Request)
88 if !ok {
89 return out, metadata, fmt.Errorf("unknown transport type %T", in.Request)
90 }
91
92 if m.Resolver == nil {
93 return out, metadata, fmt.Errorf("expected endpoint resolver to not be nil")
94 }
95
96 eo := m.Options
97 eo.Logger = middleware.GetLogger(ctx)
98
99 var endpoint aws.Endpoint
100 endpoint, err = m.Resolver.ResolveEndpoint(awsmiddleware.GetRegion(ctx), eo)
101 if err != nil {
102 nf := (&aws.EndpointNotFoundError{})
103 if errors.As(err, &nf) {
104 ctx = awsmiddleware.SetRequiresLegacyEndpoints(ctx, false)
105 return next.HandleSerialize(ctx, in)
106 }
107 return out, metadata, fmt.Errorf("failed to resolve service endpoint, %w", err)
108 }
109
110 req.URL, err = url.Parse(endpoint.URL)
111 if err != nil {
112 return out, metadata, fmt.Errorf("failed to parse endpoint URL: %w", err)
113 }
114
115 if len(awsmiddleware.GetSigningName(ctx)) == 0 {
116 signingName := endpoint.SigningName
117 if len(signingName) == 0 {
118 signingName = "sso-oauth"
119 }
120 ctx = awsmiddleware.SetSigningName(ctx, signingName)
121 }
122 ctx = awsmiddleware.SetEndpointSource(ctx, endpoint.Source)
123 ctx = smithyhttp.SetHostnameImmutable(ctx, endpoint.HostnameImmutable)
124 ctx = awsmiddleware.SetSigningRegion(ctx, endpoint.SigningRegion)
125 ctx = awsmiddleware.SetPartitionID(ctx, endpoint.PartitionID)
126 return next.HandleSerialize(ctx, in)
127}
128func addResolveEndpointMiddleware(stack *middleware.Stack, o Options) error {
129 return stack.Serialize.Insert(&ResolveEndpoint{
130 Resolver: o.EndpointResolver,
131 Options: o.EndpointOptions,
132 }, "OperationSerializer", middleware.Before)
133}
134
135func removeResolveEndpointMiddleware(stack *middleware.Stack) error {
136 _, err := stack.Serialize.Remove((&ResolveEndpoint{}).ID())
137 return err
138}
139
140type wrappedEndpointResolver struct {
141 awsResolver aws.EndpointResolverWithOptions
142}
143
144func (w *wrappedEndpointResolver) ResolveEndpoint(region string, options EndpointResolverOptions) (endpoint aws.Endpoint, err error) {
145 return w.awsResolver.ResolveEndpoint(ServiceID, region, options)
146}
147
148type awsEndpointResolverAdaptor func(service, region string) (aws.Endpoint, error)
149
150func (a awsEndpointResolverAdaptor) ResolveEndpoint(service, region string, options ...interface{}) (aws.Endpoint, error) {
151 return a(service, region)
152}
153
154var _ aws.EndpointResolverWithOptions = awsEndpointResolverAdaptor(nil)
155
156// withEndpointResolver returns an aws.EndpointResolverWithOptions that first delegates endpoint resolution to the awsResolver.
157// If awsResolver returns aws.EndpointNotFoundError error, the v1 resolver middleware will swallow the error,
158// and set an appropriate context flag such that fallback will occur when EndpointResolverV2 is invoked
159// via its middleware.
160//
161// If another error (besides aws.EndpointNotFoundError) is returned, then that error will be propagated.
162func withEndpointResolver(awsResolver aws.EndpointResolver, awsResolverWithOptions aws.EndpointResolverWithOptions) EndpointResolver {
163 var resolver aws.EndpointResolverWithOptions
164
165 if awsResolverWithOptions != nil {
166 resolver = awsResolverWithOptions
167 } else if awsResolver != nil {
168 resolver = awsEndpointResolverAdaptor(awsResolver.ResolveEndpoint)
169 }
170
171 return &wrappedEndpointResolver{
172 awsResolver: resolver,
173 }
174}
175
176func finalizeClientEndpointResolverOptions(options *Options) {
177 options.EndpointOptions.LogDeprecated = options.ClientLogMode.IsDeprecatedUsage()
178
179 if len(options.EndpointOptions.ResolvedRegion) == 0 {
180 const fipsInfix = "-fips-"
181 const fipsPrefix = "fips-"
182 const fipsSuffix = "-fips"
183
184 if strings.Contains(options.Region, fipsInfix) ||
185 strings.Contains(options.Region, fipsPrefix) ||
186 strings.Contains(options.Region, fipsSuffix) {
187 options.EndpointOptions.ResolvedRegion = strings.ReplaceAll(strings.ReplaceAll(strings.ReplaceAll(
188 options.Region, fipsInfix, "-"), fipsPrefix, ""), fipsSuffix, "")
189 options.EndpointOptions.UseFIPSEndpoint = aws.FIPSEndpointStateEnabled
190 }
191 }
192
193}
194
195func resolveEndpointResolverV2(options *Options) {
196 if options.EndpointResolverV2 == nil {
197 options.EndpointResolverV2 = NewDefaultEndpointResolverV2()
198 }
199}
200
201func resolveBaseEndpoint(cfg aws.Config, o *Options) {
202 if cfg.BaseEndpoint != nil {
203 o.BaseEndpoint = cfg.BaseEndpoint
204 }
205
206 _, g := os.LookupEnv("AWS_ENDPOINT_URL")
207 _, s := os.LookupEnv("AWS_ENDPOINT_URL_SSO_OIDC")
208
209 if g && !s {
210 return
211 }
212
213 value, found, err := internalConfig.ResolveServiceBaseEndpoint(context.Background(), "SSO OIDC", cfg.ConfigSources)
214 if found && err == nil {
215 o.BaseEndpoint = &value
216 }
217}
218
219func bindRegion(region string) *string {
220 if region == "" {
221 return nil
222 }
223 return aws.String(endpoints.MapFIPSRegion(region))
224}
225
226// EndpointParameters provides the parameters that influence how endpoints are
227// resolved.
228type EndpointParameters struct {
229 // The AWS region used to dispatch the request.
230 //
231 // Parameter is
232 // required.
233 //
234 // AWS::Region
235 Region *string
236
237 // When true, use the dual-stack endpoint. If the configured endpoint does not
238 // support dual-stack, dispatching the request MAY return an error.
239 //
240 // Defaults to
241 // false if no value is provided.
242 //
243 // AWS::UseDualStack
244 UseDualStack *bool
245
246 // When true, send this request to the FIPS-compliant regional endpoint. If the
247 // configured endpoint does not have a FIPS compliant endpoint, dispatching the
248 // request will return an error.
249 //
250 // Defaults to false if no value is
251 // provided.
252 //
253 // AWS::UseFIPS
254 UseFIPS *bool
255
256 // Override the endpoint used to send this request
257 //
258 // Parameter is
259 // required.
260 //
261 // SDK::Endpoint
262 Endpoint *string
263}
264
265// ValidateRequired validates required parameters are set.
266func (p EndpointParameters) ValidateRequired() error {
267 if p.UseDualStack == nil {
268 return fmt.Errorf("parameter UseDualStack is required")
269 }
270
271 if p.UseFIPS == nil {
272 return fmt.Errorf("parameter UseFIPS is required")
273 }
274
275 return nil
276}
277
278// WithDefaults returns a shallow copy of EndpointParameterswith default values
279// applied to members where applicable.
280func (p EndpointParameters) WithDefaults() EndpointParameters {
281 if p.UseDualStack == nil {
282 p.UseDualStack = ptr.Bool(false)
283 }
284
285 if p.UseFIPS == nil {
286 p.UseFIPS = ptr.Bool(false)
287 }
288 return p
289}
290
291type stringSlice []string
292
293func (s stringSlice) Get(i int) *string {
294 if i < 0 || i >= len(s) {
295 return nil
296 }
297
298 v := s[i]
299 return &v
300}
301
302// EndpointResolverV2 provides the interface for resolving service endpoints.
303type EndpointResolverV2 interface {
304 // ResolveEndpoint attempts to resolve the endpoint with the provided options,
305 // returning the endpoint if found. Otherwise an error is returned.
306 ResolveEndpoint(ctx context.Context, params EndpointParameters) (
307 smithyendpoints.Endpoint, error,
308 )
309}
310
311// resolver provides the implementation for resolving endpoints.
312type resolver struct{}
313
314func NewDefaultEndpointResolverV2() EndpointResolverV2 {
315 return &resolver{}
316}
317
318// ResolveEndpoint attempts to resolve the endpoint with the provided options,
319// returning the endpoint if found. Otherwise an error is returned.
320func (r *resolver) ResolveEndpoint(
321 ctx context.Context, params EndpointParameters,
322) (
323 endpoint smithyendpoints.Endpoint, err error,
324) {
325 params = params.WithDefaults()
326 if err = params.ValidateRequired(); err != nil {
327 return endpoint, fmt.Errorf("endpoint parameters are not valid, %w", err)
328 }
329 _UseDualStack := *params.UseDualStack
330 _UseFIPS := *params.UseFIPS
331
332 if exprVal := params.Endpoint; exprVal != nil {
333 _Endpoint := *exprVal
334 _ = _Endpoint
335 if _UseFIPS == true {
336 return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: FIPS and custom endpoint are not supported")
337 }
338 if _UseDualStack == true {
339 return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Dualstack and custom endpoint are not supported")
340 }
341 uriString := _Endpoint
342
343 uri, err := url.Parse(uriString)
344 if err != nil {
345 return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
346 }
347
348 return smithyendpoints.Endpoint{
349 URI: *uri,
350 Headers: http.Header{},
351 }, nil
352 }
353 if exprVal := params.Region; exprVal != nil {
354 _Region := *exprVal
355 _ = _Region
356 if exprVal := awsrulesfn.GetPartition(_Region); exprVal != nil {
357 _PartitionResult := *exprVal
358 _ = _PartitionResult
359 if _UseFIPS == true {
360 if _UseDualStack == true {
361 if true == _PartitionResult.SupportsFIPS {
362 if true == _PartitionResult.SupportsDualStack {
363 uriString := func() string {
364 var out strings.Builder
365 out.WriteString("https://oidc-fips.")
366 out.WriteString(_Region)
367 out.WriteString(".")
368 out.WriteString(_PartitionResult.DualStackDnsSuffix)
369 return out.String()
370 }()
371
372 uri, err := url.Parse(uriString)
373 if err != nil {
374 return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
375 }
376
377 return smithyendpoints.Endpoint{
378 URI: *uri,
379 Headers: http.Header{},
380 }, nil
381 }
382 }
383 return endpoint, fmt.Errorf("endpoint rule error, %s", "FIPS and DualStack are enabled, but this partition does not support one or both")
384 }
385 }
386 if _UseFIPS == true {
387 if _PartitionResult.SupportsFIPS == true {
388 if _PartitionResult.Name == "aws-us-gov" {
389 uriString := func() string {
390 var out strings.Builder
391 out.WriteString("https://oidc.")
392 out.WriteString(_Region)
393 out.WriteString(".amazonaws.com")
394 return out.String()
395 }()
396
397 uri, err := url.Parse(uriString)
398 if err != nil {
399 return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
400 }
401
402 return smithyendpoints.Endpoint{
403 URI: *uri,
404 Headers: http.Header{},
405 }, nil
406 }
407 uriString := func() string {
408 var out strings.Builder
409 out.WriteString("https://oidc-fips.")
410 out.WriteString(_Region)
411 out.WriteString(".")
412 out.WriteString(_PartitionResult.DnsSuffix)
413 return out.String()
414 }()
415
416 uri, err := url.Parse(uriString)
417 if err != nil {
418 return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
419 }
420
421 return smithyendpoints.Endpoint{
422 URI: *uri,
423 Headers: http.Header{},
424 }, nil
425 }
426 return endpoint, fmt.Errorf("endpoint rule error, %s", "FIPS is enabled but this partition does not support FIPS")
427 }
428 if _UseDualStack == true {
429 if true == _PartitionResult.SupportsDualStack {
430 uriString := func() string {
431 var out strings.Builder
432 out.WriteString("https://oidc.")
433 out.WriteString(_Region)
434 out.WriteString(".")
435 out.WriteString(_PartitionResult.DualStackDnsSuffix)
436 return out.String()
437 }()
438
439 uri, err := url.Parse(uriString)
440 if err != nil {
441 return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
442 }
443
444 return smithyendpoints.Endpoint{
445 URI: *uri,
446 Headers: http.Header{},
447 }, nil
448 }
449 return endpoint, fmt.Errorf("endpoint rule error, %s", "DualStack is enabled but this partition does not support DualStack")
450 }
451 uriString := func() string {
452 var out strings.Builder
453 out.WriteString("https://oidc.")
454 out.WriteString(_Region)
455 out.WriteString(".")
456 out.WriteString(_PartitionResult.DnsSuffix)
457 return out.String()
458 }()
459
460 uri, err := url.Parse(uriString)
461 if err != nil {
462 return endpoint, fmt.Errorf("Failed to parse uri: %s", uriString)
463 }
464
465 return smithyendpoints.Endpoint{
466 URI: *uri,
467 Headers: http.Header{},
468 }, nil
469 }
470 return endpoint, fmt.Errorf("Endpoint resolution failed. Invalid operation or environment input.")
471 }
472 return endpoint, fmt.Errorf("endpoint rule error, %s", "Invalid Configuration: Missing Region")
473}
474
475type endpointParamsBinder interface {
476 bindEndpointParams(*EndpointParameters)
477}
478
479func bindEndpointParams(ctx context.Context, input interface{}, options Options) *EndpointParameters {
480 params := &EndpointParameters{}
481
482 params.Region = bindRegion(options.Region)
483 params.UseDualStack = aws.Bool(options.EndpointOptions.UseDualStackEndpoint == aws.DualStackEndpointStateEnabled)
484 params.UseFIPS = aws.Bool(options.EndpointOptions.UseFIPSEndpoint == aws.FIPSEndpointStateEnabled)
485 params.Endpoint = options.BaseEndpoint
486
487 if b, ok := input.(endpointParamsBinder); ok {
488 b.bindEndpointParams(params)
489 }
490
491 return params
492}
493
494type resolveEndpointV2Middleware struct {
495 options Options
496}
497
498func (*resolveEndpointV2Middleware) ID() string {
499 return "ResolveEndpointV2"
500}
501
502func (m *resolveEndpointV2Middleware) HandleFinalize(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (
503 out middleware.FinalizeOutput, metadata middleware.Metadata, err error,
504) {
505 if awsmiddleware.GetRequiresLegacyEndpoints(ctx) {
506 return next.HandleFinalize(ctx, in)
507 }
508
509 if err := checkAccountID(getIdentity(ctx), m.options.AccountIDEndpointMode); err != nil {
510 return out, metadata, fmt.Errorf("invalid accountID set: %w", err)
511 }
512
513 req, ok := in.Request.(*smithyhttp.Request)
514 if !ok {
515 return out, metadata, fmt.Errorf("unknown transport type %T", in.Request)
516 }
517
518 if m.options.EndpointResolverV2 == nil {
519 return out, metadata, fmt.Errorf("expected endpoint resolver to not be nil")
520 }
521
522 params := bindEndpointParams(ctx, getOperationInput(ctx), m.options)
523 endpt, err := m.options.EndpointResolverV2.ResolveEndpoint(ctx, *params)
524 if err != nil {
525 return out, metadata, fmt.Errorf("failed to resolve service endpoint, %w", err)
526 }
527
528 if endpt.URI.RawPath == "" && req.URL.RawPath != "" {
529 endpt.URI.RawPath = endpt.URI.Path
530 }
531 req.URL.Scheme = endpt.URI.Scheme
532 req.URL.Host = endpt.URI.Host
533 req.URL.Path = smithyhttp.JoinPath(endpt.URI.Path, req.URL.Path)
534 req.URL.RawPath = smithyhttp.JoinPath(endpt.URI.RawPath, req.URL.RawPath)
535 for k := range endpt.Headers {
536 req.Header.Set(k, endpt.Headers.Get(k))
537 }
538
539 rscheme := getResolvedAuthScheme(ctx)
540 if rscheme == nil {
541 return out, metadata, fmt.Errorf("no resolved auth scheme")
542 }
543
544 opts, _ := smithyauth.GetAuthOptions(&endpt.Properties)
545 for _, o := range opts {
546 rscheme.SignerProperties.SetAll(&o.SignerProperties)
547 }
548
549 return next.HandleFinalize(ctx, in)
550}