api_op_GetToken.go (2828B)
1 package imds 2 3 import ( 4 "context" 5 "fmt" 6 "io" 7 "strconv" 8 "strings" 9 "time" 10 11 "github.com/aws/smithy-go/middleware" 12 smithyhttp "github.com/aws/smithy-go/transport/http" 13 ) 14 15 const getTokenPath = "/latest/api/token" 16 const tokenTTLHeader = "X-Aws-Ec2-Metadata-Token-Ttl-Seconds" 17 18 // getToken uses the duration to return a token for EC2 IMDS, or an error if 19 // the request failed. 20 func (c *Client) getToken(ctx context.Context, params *getTokenInput, optFns ...func(*Options)) (*getTokenOutput, error) { 21 if params == nil { 22 params = &getTokenInput{} 23 } 24 25 result, metadata, err := c.invokeOperation(ctx, "getToken", params, optFns, 26 addGetTokenMiddleware, 27 ) 28 if err != nil { 29 return nil, err 30 } 31 32 out := result.(*getTokenOutput) 33 out.ResultMetadata = metadata 34 return out, nil 35 } 36 37 type getTokenInput struct { 38 TokenTTL time.Duration 39 } 40 41 type getTokenOutput struct { 42 Token string 43 TokenTTL time.Duration 44 45 ResultMetadata middleware.Metadata 46 } 47 48 func addGetTokenMiddleware(stack *middleware.Stack, options Options) error { 49 err := addRequestMiddleware(stack, 50 options, 51 "PUT", 52 buildGetTokenPath, 53 buildGetTokenOutput) 54 if err != nil { 55 return err 56 } 57 58 err = stack.Serialize.Add(&tokenTTLRequestHeader{}, middleware.After) 59 if err != nil { 60 return err 61 } 62 63 return nil 64 } 65 66 func buildGetTokenPath(interface{}) (string, error) { 67 return getTokenPath, nil 68 } 69 70 func buildGetTokenOutput(resp *smithyhttp.Response) (v interface{}, err error) { 71 defer func() { 72 closeErr := resp.Body.Close() 73 if err == nil { 74 err = closeErr 75 } else if closeErr != nil { 76 err = fmt.Errorf("response body close error: %v, original error: %w", closeErr, err) 77 } 78 }() 79 80 ttlHeader := resp.Header.Get(tokenTTLHeader) 81 tokenTTL, err := strconv.ParseInt(ttlHeader, 10, 64) 82 if err != nil { 83 return nil, fmt.Errorf("unable to parse API token, %w", err) 84 } 85 86 var token strings.Builder 87 if _, err = io.Copy(&token, resp.Body); err != nil { 88 return nil, fmt.Errorf("unable to read API token, %w", err) 89 } 90 91 return &getTokenOutput{ 92 Token: token.String(), 93 TokenTTL: time.Duration(tokenTTL) * time.Second, 94 }, nil 95 } 96 97 type tokenTTLRequestHeader struct{} 98 99 func (*tokenTTLRequestHeader) ID() string { return "tokenTTLRequestHeader" } 100 func (*tokenTTLRequestHeader) HandleSerialize( 101 ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler, 102 ) ( 103 out middleware.SerializeOutput, metadata middleware.Metadata, err error, 104 ) { 105 req, ok := in.Request.(*smithyhttp.Request) 106 if !ok { 107 return out, metadata, fmt.Errorf("expect HTTP transport, got %T", in.Request) 108 } 109 110 input, ok := in.Parameters.(*getTokenInput) 111 if !ok { 112 return out, metadata, fmt.Errorf("expect getTokenInput, got %T", in.Parameters) 113 } 114 115 req.Header.Set(tokenTTLHeader, strconv.Itoa(int(input.TokenTTL/time.Second))) 116 117 return next.HandleSerialize(ctx, in) 118 }