diff options
Diffstat (limited to 'vendor/github.com/mitchellh/packer/builder/oracle/oci/client/transport.go')
-rw-r--r-- | vendor/github.com/mitchellh/packer/builder/oracle/oci/client/transport.go | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/vendor/github.com/mitchellh/packer/builder/oracle/oci/client/transport.go b/vendor/github.com/mitchellh/packer/builder/oracle/oci/client/transport.go new file mode 100644 index 00000000..79da2050 --- /dev/null +++ b/vendor/github.com/mitchellh/packer/builder/oracle/oci/client/transport.go @@ -0,0 +1,116 @@ +package oci + +import ( + "bytes" + "crypto" + "crypto/rand" + "crypto/rsa" + "crypto/sha256" + "encoding/base64" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "time" +) + +type nopCloser struct { + io.Reader +} + +func (nopCloser) Close() error { + return nil +} + +// Transport adds OCI signature authentication to each outgoing request. +type Transport struct { + transport http.RoundTripper + config *Config +} + +// NewTransport creates a new Transport to add OCI signature authentication +// to each outgoing request. +func NewTransport(transport http.RoundTripper, config *Config) *Transport { + return &Transport{ + transport: transport, + config: config, + } +} + +func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { + var buf *bytes.Buffer + + if req.Body != nil { + buf = new(bytes.Buffer) + buf.ReadFrom(req.Body) + req.Body = nopCloser{buf} + } + if req.Header.Get("date") == "" { + req.Header.Set("date", time.Now().UTC().Format(http.TimeFormat)) + } + if req.Header.Get("content-type") == "" { + req.Header.Set("content-type", "application/json") + } + if req.Header.Get("accept") == "" { + req.Header.Set("accept", "application/json") + } + if req.Header.Get("host") == "" { + req.Header.Set("host", req.URL.Host) + } + + var signheaders []string + if (req.Method == "PUT" || req.Method == "POST") && buf != nil { + signheaders = []string{"(request-target)", "host", "date", + "content-length", "content-type", "x-content-sha256"} + + if req.Header.Get("content-length") == "" { + req.Header.Set("content-length", strconv.Itoa(buf.Len())) + } + + hasher := sha256.New() + hasher.Write(buf.Bytes()) + hash := hasher.Sum(nil) + req.Header.Set("x-content-sha256", base64.StdEncoding.EncodeToString(hash)) + } else { + signheaders = []string{"date", "host", "(request-target)"} + } + + var signbuffer bytes.Buffer + for idx, header := range signheaders { + signbuffer.WriteString(header) + signbuffer.WriteString(": ") + + if header == "(request-target)" { + signbuffer.WriteString(strings.ToLower(req.Method)) + signbuffer.WriteString(" ") + signbuffer.WriteString(req.URL.RequestURI()) + } else { + signbuffer.WriteString(req.Header.Get(header)) + } + + if idx < len(signheaders)-1 { + signbuffer.WriteString("\n") + } + } + + h := sha256.New() + h.Write(signbuffer.Bytes()) + digest := h.Sum(nil) + signature, err := rsa.SignPKCS1v15(rand.Reader, t.config.Key, crypto.SHA256, digest) + if err != nil { + return nil, err + } + + authHeader := fmt.Sprintf("Signature headers=\"%s\","+ + "keyId=\"%s/%s/%s\","+ + "algorithm=\"rsa-sha256\","+ + "signature=\"%s\","+ + "version=\"1\"", + strings.Join(signheaders, " "), + t.config.Tenancy, t.config.User, t.config.Fingerprint, + base64.StdEncoding.EncodeToString(signature)) + req.Header.Add("Authorization", authHeader) + + return t.transport.RoundTrip(req) +} |