Skip to content

Commit 6759ce2

Browse files
committed
Set User-Agent and X-Request-Id headers in API token request
1 parent 29cb428 commit 6759ce2

File tree

2 files changed

+60
-11
lines changed

2 files changed

+60
-11
lines changed

command/api/token/create.go

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,14 @@ import (
1414
"github.com/google/uuid"
1515
"github.com/urfave/cli"
1616

17+
"github.com/smallstep/certificates/ca"
1718
"github.com/smallstep/cli-utils/errs"
1819
"github.com/smallstep/cli-utils/ui"
1920
"go.step.sm/crypto/pemutil"
21+
"go.step.sm/crypto/randutil"
2022

2123
"github.com/smallstep/cli/internal/cryptoutil"
24+
"github.com/smallstep/cli/internal/httptransport"
2225
)
2326

2427
func createCommand() cli.Command {
@@ -98,27 +101,23 @@ func createAction(ctx *cli.Context) (err error) {
98101
return err
99102
}
100103

101-
b := &bytes.Buffer{}
102-
r := &createTokenReq{
104+
b := new(bytes.Buffer)
105+
r := createTokenReq{
103106
Bundle: clientCert.Certificate,
104107
Audience: audience,
105108
}
109+
106110
if err := uuid.Validate(teamID); err != nil {
107111
r.TeamSlug = teamID
108112
} else {
109113
r.TeamID = teamID
110114
}
111-
err = json.NewEncoder(b).Encode(r)
112-
if err != nil {
113-
return err
114-
}
115115

116-
post, err := http.NewRequest("POST", apiURL, b)
117-
if err != nil {
116+
if err := json.NewEncoder(b).Encode(r); err != nil {
118117
return err
119118
}
120-
post.Header.Set("Content-Type", "application/json")
121-
transport := http.DefaultTransport.(*http.Transport).Clone()
119+
120+
transport := httptransport.New()
122121
transport.TLSClientConfig = &tls.Config{
123122
GetClientCertificate: func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
124123
return clientCert, nil
@@ -128,7 +127,16 @@ func createAction(ctx *cli.Context) (err error) {
128127
client := http.Client{
129128
Transport: transport,
130129
}
131-
resp, err := client.Do(post)
130+
131+
req, err := http.NewRequest("POST", apiURL, b)
132+
if err != nil {
133+
return err
134+
}
135+
req.Header.Set("Content-Type", "application/json")
136+
req.Header.Set("User-Agent", ca.UserAgent) // this is set to step.Version() during init; i.e. "Smallstep CLI/vX.X.X (os/arch)"
137+
req.Header.Set(requestIDHeader, newRequestID())
138+
139+
resp, err := client.Do(req)
132140
if err != nil {
133141
return err
134142
}
@@ -152,6 +160,21 @@ func createAction(ctx *cli.Context) (err error) {
152160
return nil
153161
}
154162

163+
// requestIDHeader is the header name used for propagating request IDs from
164+
// the client to the server and back again.
165+
const requestIDHeader = "X-Request-Id"
166+
167+
// newRequestID generates a new random UUIDv4 request ID. If it fails,
168+
// the request ID will be the empty string.
169+
func newRequestID() string {
170+
requestID, err := randutil.UUIDv4()
171+
if err != nil {
172+
return ""
173+
}
174+
175+
return requestID
176+
}
177+
155178
func createClientCertificate(crtFile, keyFile string) (*tls.Certificate, error) {
156179
certs, err := pemutil.ReadCertificateBundle(crtFile)
157180
if err != nil {
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Package httptransport implements initialization of [http.Transport] instances and related
2+
// functionality.
3+
package httptransport
4+
5+
import (
6+
"net"
7+
"net/http"
8+
"time"
9+
)
10+
11+
// New returns a reference to an [http.Transport] that's initialized just like the
12+
// [http.DefaultTransport] is by the standard library.
13+
func New() *http.Transport {
14+
return &http.Transport{
15+
Proxy: http.ProxyFromEnvironment,
16+
DialContext: (&net.Dialer{
17+
Timeout: 30 * time.Second,
18+
KeepAlive: 30 * time.Second,
19+
}).DialContext,
20+
ForceAttemptHTTP2: true,
21+
MaxIdleConns: 100,
22+
IdleConnTimeout: 90 * time.Second,
23+
TLSHandshakeTimeout: 10 * time.Second,
24+
ExpectContinueTimeout: 1 * time.Second,
25+
}
26+
}

0 commit comments

Comments
 (0)