2015-03-09 18:38:50 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"io"
|
2018-05-09 21:44:53 +00:00
|
|
|
"io/ioutil"
|
2016-07-11 21:37:46 +00:00
|
|
|
"net/http"
|
2015-03-09 18:38:50 +00:00
|
|
|
"net/url"
|
2018-05-09 21:44:53 +00:00
|
|
|
|
|
|
|
retryablehttp "github.com/hashicorp/go-retryablehttp"
|
2015-03-09 18:38:50 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Request is a raw request configuration structure used to initiate
|
|
|
|
// API requests to the Vault server.
|
|
|
|
type Request struct {
|
2017-10-23 20:52:56 +00:00
|
|
|
Method string
|
|
|
|
URL *url.URL
|
|
|
|
Params url.Values
|
|
|
|
Headers http.Header
|
|
|
|
ClientToken string
|
|
|
|
MFAHeaderVals []string
|
|
|
|
WrapTTL string
|
|
|
|
Obj interface{}
|
|
|
|
Body io.Reader
|
|
|
|
BodySize int64
|
|
|
|
|
|
|
|
// Whether to request overriding soft-mandatory Sentinel policies (RGPs and
|
|
|
|
// EGPs). If set, the override flag will take effect for all policies
|
|
|
|
// evaluated during the request.
|
|
|
|
PolicyOverride bool
|
2015-03-09 18:38:50 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetJSONBody is used to set a request body that is a JSON-encoded value.
|
|
|
|
func (r *Request) SetJSONBody(val interface{}) error {
|
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
enc := json.NewEncoder(buf)
|
|
|
|
if err := enc.Encode(val); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2015-04-20 17:44:51 +00:00
|
|
|
r.Obj = val
|
2015-03-09 18:38:50 +00:00
|
|
|
r.Body = buf
|
|
|
|
r.BodySize = int64(buf.Len())
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2015-04-20 17:44:51 +00:00
|
|
|
// ResetJSONBody is used to reset the body for a redirect
|
|
|
|
func (r *Request) ResetJSONBody() error {
|
|
|
|
if r.Body == nil {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
return r.SetJSONBody(r.Obj)
|
|
|
|
}
|
|
|
|
|
2016-07-11 21:37:46 +00:00
|
|
|
// ToHTTP turns this request into a valid *http.Request for use with the
|
|
|
|
// net/http package.
|
|
|
|
func (r *Request) ToHTTP() (*http.Request, error) {
|
2018-05-09 21:44:53 +00:00
|
|
|
req, err := r.toRetryableHTTP(true)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return req.Request, nil
|
|
|
|
}
|
|
|
|
|
2018-05-10 00:35:47 +00:00
|
|
|
// legacy indicates whether we want to return a request derived from
|
|
|
|
// http.NewRequest instead of retryablehttp.NewRequest, so that legacy clents
|
|
|
|
// that might be using the public ToHTTP method still work
|
|
|
|
func (r *Request) toRetryableHTTP(legacy bool) (*retryablehttp.Request, error) {
|
2015-03-09 18:38:50 +00:00
|
|
|
// Encode the query parameters
|
|
|
|
r.URL.RawQuery = r.Params.Encode()
|
|
|
|
|
2018-05-09 21:44:53 +00:00
|
|
|
// Create the HTTP request, defaulting to retryable
|
|
|
|
var req *retryablehttp.Request
|
|
|
|
|
2018-05-10 00:35:47 +00:00
|
|
|
if legacy {
|
2018-05-09 21:44:53 +00:00
|
|
|
regReq, err := http.NewRequest(r.Method, r.URL.RequestURI(), r.Body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
req = &retryablehttp.Request{
|
|
|
|
Request: regReq,
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
var buf []byte
|
|
|
|
var err error
|
|
|
|
if r.Body != nil {
|
|
|
|
buf, err = ioutil.ReadAll(r.Body)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
req, err = retryablehttp.NewRequest(r.Method, r.URL.RequestURI(), bytes.NewReader(buf))
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2015-03-09 18:38:50 +00:00
|
|
|
}
|
|
|
|
|
2017-03-10 12:19:23 +00:00
|
|
|
req.URL.User = r.URL.User
|
2015-03-09 18:38:50 +00:00
|
|
|
req.URL.Scheme = r.URL.Scheme
|
|
|
|
req.URL.Host = r.URL.Host
|
|
|
|
req.Host = r.URL.Host
|
|
|
|
|
2017-06-19 22:20:44 +00:00
|
|
|
if r.Headers != nil {
|
|
|
|
for header, vals := range r.Headers {
|
|
|
|
for _, val := range vals {
|
|
|
|
req.Header.Add(header, val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-22 00:36:19 +00:00
|
|
|
if len(r.ClientToken) != 0 {
|
|
|
|
req.Header.Set("X-Vault-Token", r.ClientToken)
|
|
|
|
}
|
|
|
|
|
2016-05-02 05:58:58 +00:00
|
|
|
if len(r.WrapTTL) != 0 {
|
|
|
|
req.Header.Set("X-Vault-Wrap-TTL", r.WrapTTL)
|
|
|
|
}
|
|
|
|
|
2017-10-23 20:52:56 +00:00
|
|
|
if len(r.MFAHeaderVals) != 0 {
|
|
|
|
for _, mfaHeaderVal := range r.MFAHeaderVals {
|
|
|
|
req.Header.Add("X-Vault-MFA", mfaHeaderVal)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if r.PolicyOverride {
|
|
|
|
req.Header.Set("X-Vault-Policy-Override", "true")
|
|
|
|
}
|
|
|
|
|
2015-03-09 18:38:50 +00:00
|
|
|
return req, nil
|
|
|
|
}
|