-
Notifications
You must be signed in to change notification settings - Fork 5
/
util.go
150 lines (133 loc) · 3.54 KB
/
util.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
package proxy
import (
log "github.com/Sirupsen/logrus"
"crypto/tls"
"crypto/x509"
"errors"
"io/ioutil"
"net/url"
"time"
)
const (
MAX_BACKOFF_DELAY = 2 * time.Second
)
// Backoff provides stepped delay on each failed attempts. Maximum delay time
// is capped off at 2 seconds.
type Backoff struct {
attempts int64
}
func (b *Backoff) min(x, y time.Duration) time.Duration {
if x < y {
return x
} else {
return y
}
}
// Delay marks this attempt failed, increments counter, and sleep for no more
// then 2 seconds in this goroutine
func (b *Backoff) Delay() {
b.attempts = b.attempts + 1
delay := b.min(time.Duration(b.attempts)*2*time.Millisecond, MAX_BACKOFF_DELAY)
log.WithFields(log.Fields{"after": delay, "attempts": b.attempts}).Debug("delay")
time.Sleep(delay)
}
// Reset clears failed attempt counter
func (b *Backoff) Reset() {
log.WithFields(log.Fields{"attempts": b.attempts}).Debug("reset")
b.attempts = 0
}
// Attempts reports current failed attempts
func (b *Backoff) Attempts() int64 {
return b.attempts
}
func loadCertFromFile(ca, tlscert, tlskey string) ([]tls.Certificate, *x509.CertPool, error) {
cert, err := tls.LoadX509KeyPair(tlscert, tlskey)
if err != nil {
return nil, nil, err
}
ca_data, err := ioutil.ReadFile(ca)
if err != nil {
return nil, nil, err
}
pool := x509.NewCertPool()
if !pool.AppendCertsFromPEM(ca_data) {
return nil, nil, errors.New("Unable to process CA chain data")
}
return []tls.Certificate{cert}, pool, nil
}
func getfile(uri string) (p string, e error) {
u, err := url.Parse(uri)
if err != nil {
log.WithFields(log.Fields{"err": err}).Debug("getfile")
return "", err
}
logger := log.WithFields(log.Fields{"type": u.Scheme})
switch {
case u.Scheme == "" || u.Scheme == "file":
p, e = uri, nil
break
case u.Scheme == "s3" || u.Scheme == "s3":
p, e = news3cli().get(u)
break
case u.Scheme == "http" || u.Scheme == "https":
p, e = "", errors.New("http/https not supported")
break
default:
p, e = "", errors.New("unexpected resource URI "+u.Scheme)
break
}
logger.WithFields(log.Fields{"uri": p, "err": e}).Debug("getfile")
return
}
func loadCertCommon(ca, tlscert, tlskey string) ([]tls.Certificate, *x509.CertPool, error) {
cafp, err := getfile(ca)
if err != nil {
return nil, nil, err
}
tlscertfp, err := getfile(tlscert)
if err != nil {
return nil, nil, err
}
tlskeyfp, err := getfile(tlskey)
if err != nil {
return nil, nil, err
}
return loadCertFromFile(cafp, tlscertfp, tlskeyfp)
}
// CertOptions provides specification to path of certificate and whether this
// is for listening server or connecting client
type CertOptions struct {
// Certificate path information
CA string
TlsCert string
TlsKey string
// Setup tls.Config so we are listening server, otherwise we are connecting
// client
Server bool
}
// LoadCertificate processes certificate resource for TLSConfg to consume.
// Reads CA cert chain, Private, and Public key, then returns tls.Config.
//
// Supported URI:
// - Local file on disk (file://)
// - Amazon Web Services S3 object (s3://)
//
// If left unspecified, URI is treated as if its a file reating on disk
//
// The default authentication rule is to verify cert key pair.
func LoadCertificate(opts CertOptions) (*tls.Config, error) {
certs, pool, err := loadCertCommon(opts.CA, opts.TlsCert, opts.TlsKey)
if err != nil {
return nil, err
}
cfg := &tls.Config{
ClientAuth: tls.RequireAndVerifyClientCert,
Certificates: certs,
}
if opts.Server {
cfg.ClientCAs = pool
} else {
cfg.RootCAs = pool
}
return cfg, nil
}