Skip to content

Commit ef09c1b

Browse files
authored
add support for multiple signature keys (#209)
1 parent 3bdd0fe commit ef09c1b

3 files changed

Lines changed: 44 additions & 21 deletions

File tree

cmd/imageproxy/main.go

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ var denyHosts = flag.String("denyHosts", "", "comma separated list of denied rem
4848
var referrers = flag.String("referrers", "", "comma separated list of allowed referring hosts")
4949
var baseURL = flag.String("baseURL", "", "default base URL for relative remote URLs")
5050
var cache tieredCache
51-
var signatureKey = flag.String("signatureKey", "", "HMAC key used in calculating request signatures")
51+
var signatureKeyList SignatureKeyList
5252
var scaleUp = flag.Bool("scaleUp", false, "allow images to scale beyond their original dimensions")
5353
var timeout = flag.Duration("timeout", 0, "time limit for requests served by this proxy")
5454
var verbose = flag.Bool("verbose", false, "print verbose logging messages")
@@ -58,6 +58,7 @@ var userAgent = flag.String("userAgent", "willnorris/imageproxy", "specify the u
5858

5959
func init() {
6060
flag.Var(&cache, "cache", "location to cache images (see https://github.com/willnorris/imageproxy#cache)")
61+
flag.Var(&signatureKeyList, "signatureKey", "HMAC key used in calculating request signatures")
6162
}
6263

6364
func main() {
@@ -77,18 +78,7 @@ func main() {
7778
if *contentTypes != "" {
7879
p.ContentTypes = strings.Split(*contentTypes, ",")
7980
}
80-
if *signatureKey != "" {
81-
key := []byte(*signatureKey)
82-
if strings.HasPrefix(*signatureKey, "@") {
83-
file := strings.TrimPrefix(*signatureKey, "@")
84-
var err error
85-
key, err = ioutil.ReadFile(file)
86-
if err != nil {
87-
log.Fatalf("error reading signature file: %v", err)
88-
}
89-
}
90-
p.SignatureKey = key
91-
}
81+
p.SignatureKeys = signatureKeyList
9282
if *baseURL != "" {
9383
var err error
9484
p.DefaultBaseURL, err = url.Parse(*baseURL)
@@ -112,6 +102,27 @@ func main() {
112102
log.Fatal(http.ListenAndServe(*addr, nil))
113103
}
114104

105+
type SignatureKeyList [][]byte
106+
107+
func (skl *SignatureKeyList) String() string {
108+
return fmt.Sprint(*skl)
109+
}
110+
111+
func (skl *SignatureKeyList) Set(value string) error {
112+
key := []byte(value)
113+
if strings.HasPrefix(value, "@") {
114+
file := strings.TrimPrefix(value, "@")
115+
var err error
116+
key, err = ioutil.ReadFile(file)
117+
if err != nil {
118+
log.Fatalf("error reading signature file: %v", err)
119+
}
120+
}
121+
122+
*skl = append(*skl, key)
123+
return nil
124+
}
125+
115126
// tieredCache allows specifying multiple caches via flags, which will create
116127
// tiered caches using the twotier package.
117128
type tieredCache struct {

imageproxy.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,9 @@ type Proxy struct {
6464
// The Logger used by the image proxy
6565
Logger *log.Logger
6666

67-
// SignatureKey is the HMAC key used to verify signed requests.
68-
SignatureKey []byte
67+
// SignatureKeys is a list of HMAC keys used to verify signed requests.
68+
// Any of them can be used to verify signed requests.
69+
SignatureKeys [][]byte
6970

7071
// Allow images to scale beyond their original dimensions.
7172
ScaleUp bool
@@ -258,16 +259,18 @@ func (p *Proxy) allowed(r *Request) error {
258259
return errDeniedHost
259260
}
260261

261-
if len(p.AllowHosts) == 0 && len(p.SignatureKey) == 0 {
262+
if len(p.AllowHosts) == 0 && len(p.SignatureKeys) == 0 {
262263
return nil // no allowed hosts or signature key, all requests accepted
263264
}
264265

265266
if len(p.AllowHosts) > 0 && hostMatches(p.AllowHosts, r.URL) {
266267
return nil
267268
}
268269

269-
if len(p.SignatureKey) > 0 && validSignature(p.SignatureKey, r) {
270-
return nil
270+
for _, signatureKey := range p.SignatureKeys {
271+
if len(signatureKey) > 0 && validSignature(signatureKey, r) {
272+
return nil
273+
}
271274
}
272275

273276
return errNotAllowed

imageproxy_test.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,13 @@ func TestCopyHeader(t *testing.T) {
116116

117117
func TestAllowed(t *testing.T) {
118118
allowHosts := []string{"good"}
119-
key := []byte("c0ffee")
119+
key := [][]byte{
120+
[]byte("c0ffee"),
121+
}
122+
multipleKey := [][]byte{
123+
[]byte("c0ffee"),
124+
[]byte("beer"),
125+
}
120126

121127
genRequest := func(headers map[string]string) *http.Request {
122128
req := &http.Request{Header: make(http.Header)}
@@ -132,7 +138,7 @@ func TestAllowed(t *testing.T) {
132138
allowHosts []string
133139
denyHosts []string
134140
referrers []string
135-
key []byte
141+
keys [][]byte
136142
request *http.Request
137143
allowed bool
138144
}{
@@ -151,7 +157,10 @@ func TestAllowed(t *testing.T) {
151157

152158
// signature key
153159
{"http://test/image", Options{Signature: "NDx5zZHx7QfE8E-ijowRreq6CJJBZjwiRfOVk_mkfQQ="}, nil, nil, nil, key, nil, true},
160+
{"http://test/image", Options{Signature: "NDx5zZHx7QfE8E-ijowRreq6CJJBZjwiRfOVk_mkfQQ="}, nil, nil, nil, multipleKey, nil, true}, // signed with key "c0ffee"
161+
{"http://test/image", Options{Signature: "FWIawYV4SEyI4zKJMeGugM-eJM1eI_jXPEQ20ZgRe4A="}, nil, nil, nil, multipleKey, nil, true}, // signed with key "beer"
154162
{"http://test/image", Options{Signature: "deadbeef"}, nil, nil, nil, key, nil, false},
163+
{"http://test/image", Options{Signature: "deadbeef"}, nil, nil, nil, multipleKey, nil, false},
155164
{"http://test/image", emptyOptions, nil, nil, nil, key, nil, false},
156165

157166
// allowHosts and signature
@@ -169,7 +178,7 @@ func TestAllowed(t *testing.T) {
169178
p := NewProxy(nil, nil)
170179
p.AllowHosts = tt.allowHosts
171180
p.DenyHosts = tt.denyHosts
172-
p.SignatureKey = tt.key
181+
p.SignatureKeys = tt.keys
173182
p.Referrers = tt.referrers
174183

175184
u, err := url.Parse(tt.url)

0 commit comments

Comments
 (0)