open-vault/api/request.go
2018-05-09 20:35:51 -04:00

132 lines
2.9 KiB
Go

package api
import (
"bytes"
"encoding/json"
"io"
"io/ioutil"
"net/http"
"net/url"
retryablehttp "github.com/hashicorp/go-retryablehttp"
)
// Request is a raw request configuration structure used to initiate
// API requests to the Vault server.
type Request struct {
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
}
// 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
}
r.Obj = val
r.Body = buf
r.BodySize = int64(buf.Len())
return nil
}
// 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)
}
// ToHTTP turns this request into a valid *http.Request for use with the
// net/http package.
func (r *Request) ToHTTP() (*http.Request, error) {
req, err := r.toRetryableHTTP(true)
if err != nil {
return nil, err
}
return req.Request, nil
}
// 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) {
// Encode the query parameters
r.URL.RawQuery = r.Params.Encode()
// Create the HTTP request, defaulting to retryable
var req *retryablehttp.Request
if legacy {
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
}
}
req.URL.User = r.URL.User
req.URL.Scheme = r.URL.Scheme
req.URL.Host = r.URL.Host
req.Host = r.URL.Host
if r.Headers != nil {
for header, vals := range r.Headers {
for _, val := range vals {
req.Header.Add(header, val)
}
}
}
if len(r.ClientToken) != 0 {
req.Header.Set("X-Vault-Token", r.ClientToken)
}
if len(r.WrapTTL) != 0 {
req.Header.Set("X-Vault-Wrap-TTL", r.WrapTTL)
}
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")
}
return req, nil
}