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