github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/oracle/oci/client/transport.go (about) 1 package oci 2 3 import ( 4 "bytes" 5 "crypto" 6 "crypto/rand" 7 "crypto/rsa" 8 "crypto/sha256" 9 "encoding/base64" 10 "fmt" 11 "io" 12 "net/http" 13 "strconv" 14 "strings" 15 "time" 16 ) 17 18 type nopCloser struct { 19 io.Reader 20 } 21 22 func (nopCloser) Close() error { 23 return nil 24 } 25 26 // Transport adds OCI signature authentication to each outgoing request. 27 type Transport struct { 28 transport http.RoundTripper 29 config *Config 30 } 31 32 // NewTransport creates a new Transport to add OCI signature authentication 33 // to each outgoing request. 34 func NewTransport(transport http.RoundTripper, config *Config) *Transport { 35 return &Transport{ 36 transport: transport, 37 config: config, 38 } 39 } 40 41 func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) { 42 var buf *bytes.Buffer 43 44 if req.Body != nil { 45 buf = new(bytes.Buffer) 46 buf.ReadFrom(req.Body) 47 req.Body = nopCloser{buf} 48 } 49 if req.Header.Get("date") == "" { 50 req.Header.Set("date", time.Now().UTC().Format(http.TimeFormat)) 51 } 52 if req.Header.Get("content-type") == "" { 53 req.Header.Set("content-type", "application/json") 54 } 55 if req.Header.Get("accept") == "" { 56 req.Header.Set("accept", "application/json") 57 } 58 if req.Header.Get("host") == "" { 59 req.Header.Set("host", req.URL.Host) 60 } 61 62 var signheaders []string 63 if (req.Method == "PUT" || req.Method == "POST") && buf != nil { 64 signheaders = []string{"(request-target)", "host", "date", 65 "content-length", "content-type", "x-content-sha256"} 66 67 if req.Header.Get("content-length") == "" { 68 req.Header.Set("content-length", strconv.Itoa(buf.Len())) 69 } 70 71 hasher := sha256.New() 72 hasher.Write(buf.Bytes()) 73 hash := hasher.Sum(nil) 74 req.Header.Set("x-content-sha256", base64.StdEncoding.EncodeToString(hash)) 75 } else { 76 signheaders = []string{"date", "host", "(request-target)"} 77 } 78 79 var signbuffer bytes.Buffer 80 for idx, header := range signheaders { 81 signbuffer.WriteString(header) 82 signbuffer.WriteString(": ") 83 84 if header == "(request-target)" { 85 signbuffer.WriteString(strings.ToLower(req.Method)) 86 signbuffer.WriteString(" ") 87 signbuffer.WriteString(req.URL.RequestURI()) 88 } else { 89 signbuffer.WriteString(req.Header.Get(header)) 90 } 91 92 if idx < len(signheaders)-1 { 93 signbuffer.WriteString("\n") 94 } 95 } 96 97 h := sha256.New() 98 h.Write(signbuffer.Bytes()) 99 digest := h.Sum(nil) 100 signature, err := rsa.SignPKCS1v15(rand.Reader, t.config.Key, crypto.SHA256, digest) 101 if err != nil { 102 return nil, err 103 } 104 105 authHeader := fmt.Sprintf("Signature headers=\"%s\","+ 106 "keyId=\"%s/%s/%s\","+ 107 "algorithm=\"rsa-sha256\","+ 108 "signature=\"%s\","+ 109 "version=\"1\"", 110 strings.Join(signheaders, " "), 111 t.config.Tenancy, t.config.User, t.config.Fingerprint, 112 base64.StdEncoding.EncodeToString(signature)) 113 req.Header.Add("Authorization", authHeader) 114 115 return t.transport.RoundTrip(req) 116 }