0
Fork 0
mirror of https://github.com/willnorris/imageproxy.git synced 2024-12-16 21:56:43 -05:00

add support for multiple signature keys (#209)

This commit is contained in:
Mauro Ciancio 2020-02-01 22:03:59 -03:00 committed by GitHub
parent 3bdd0fe8ed
commit ef09c1ba31
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 44 additions and 21 deletions

View file

@ -48,7 +48,7 @@ var denyHosts = flag.String("denyHosts", "", "comma separated list of denied rem
var referrers = flag.String("referrers", "", "comma separated list of allowed referring hosts") var referrers = flag.String("referrers", "", "comma separated list of allowed referring hosts")
var baseURL = flag.String("baseURL", "", "default base URL for relative remote URLs") var baseURL = flag.String("baseURL", "", "default base URL for relative remote URLs")
var cache tieredCache var cache tieredCache
var signatureKey = flag.String("signatureKey", "", "HMAC key used in calculating request signatures") var signatureKeyList SignatureKeyList
var scaleUp = flag.Bool("scaleUp", false, "allow images to scale beyond their original dimensions") var scaleUp = flag.Bool("scaleUp", false, "allow images to scale beyond their original dimensions")
var timeout = flag.Duration("timeout", 0, "time limit for requests served by this proxy") var timeout = flag.Duration("timeout", 0, "time limit for requests served by this proxy")
var verbose = flag.Bool("verbose", false, "print verbose logging messages") var verbose = flag.Bool("verbose", false, "print verbose logging messages")
@ -58,6 +58,7 @@ var userAgent = flag.String("userAgent", "willnorris/imageproxy", "specify the u
func init() { func init() {
flag.Var(&cache, "cache", "location to cache images (see https://github.com/willnorris/imageproxy#cache)") flag.Var(&cache, "cache", "location to cache images (see https://github.com/willnorris/imageproxy#cache)")
flag.Var(&signatureKeyList, "signatureKey", "HMAC key used in calculating request signatures")
} }
func main() { func main() {
@ -77,18 +78,7 @@ func main() {
if *contentTypes != "" { if *contentTypes != "" {
p.ContentTypes = strings.Split(*contentTypes, ",") p.ContentTypes = strings.Split(*contentTypes, ",")
} }
if *signatureKey != "" { p.SignatureKeys = signatureKeyList
key := []byte(*signatureKey)
if strings.HasPrefix(*signatureKey, "@") {
file := strings.TrimPrefix(*signatureKey, "@")
var err error
key, err = ioutil.ReadFile(file)
if err != nil {
log.Fatalf("error reading signature file: %v", err)
}
}
p.SignatureKey = key
}
if *baseURL != "" { if *baseURL != "" {
var err error var err error
p.DefaultBaseURL, err = url.Parse(*baseURL) p.DefaultBaseURL, err = url.Parse(*baseURL)
@ -112,6 +102,27 @@ func main() {
log.Fatal(http.ListenAndServe(*addr, nil)) log.Fatal(http.ListenAndServe(*addr, nil))
} }
type SignatureKeyList [][]byte
func (skl *SignatureKeyList) String() string {
return fmt.Sprint(*skl)
}
func (skl *SignatureKeyList) Set(value string) error {
key := []byte(value)
if strings.HasPrefix(value, "@") {
file := strings.TrimPrefix(value, "@")
var err error
key, err = ioutil.ReadFile(file)
if err != nil {
log.Fatalf("error reading signature file: %v", err)
}
}
*skl = append(*skl, key)
return nil
}
// tieredCache allows specifying multiple caches via flags, which will create // tieredCache allows specifying multiple caches via flags, which will create
// tiered caches using the twotier package. // tiered caches using the twotier package.
type tieredCache struct { type tieredCache struct {

View file

@ -64,8 +64,9 @@ type Proxy struct {
// The Logger used by the image proxy // The Logger used by the image proxy
Logger *log.Logger Logger *log.Logger
// SignatureKey is the HMAC key used to verify signed requests. // SignatureKeys is a list of HMAC keys used to verify signed requests.
SignatureKey []byte // Any of them can be used to verify signed requests.
SignatureKeys [][]byte
// Allow images to scale beyond their original dimensions. // Allow images to scale beyond their original dimensions.
ScaleUp bool ScaleUp bool
@ -258,7 +259,7 @@ func (p *Proxy) allowed(r *Request) error {
return errDeniedHost return errDeniedHost
} }
if len(p.AllowHosts) == 0 && len(p.SignatureKey) == 0 { if len(p.AllowHosts) == 0 && len(p.SignatureKeys) == 0 {
return nil // no allowed hosts or signature key, all requests accepted return nil // no allowed hosts or signature key, all requests accepted
} }
@ -266,9 +267,11 @@ func (p *Proxy) allowed(r *Request) error {
return nil return nil
} }
if len(p.SignatureKey) > 0 && validSignature(p.SignatureKey, r) { for _, signatureKey := range p.SignatureKeys {
if len(signatureKey) > 0 && validSignature(signatureKey, r) {
return nil return nil
} }
}
return errNotAllowed return errNotAllowed
} }

View file

@ -116,7 +116,13 @@ func TestCopyHeader(t *testing.T) {
func TestAllowed(t *testing.T) { func TestAllowed(t *testing.T) {
allowHosts := []string{"good"} allowHosts := []string{"good"}
key := []byte("c0ffee") key := [][]byte{
[]byte("c0ffee"),
}
multipleKey := [][]byte{
[]byte("c0ffee"),
[]byte("beer"),
}
genRequest := func(headers map[string]string) *http.Request { genRequest := func(headers map[string]string) *http.Request {
req := &http.Request{Header: make(http.Header)} req := &http.Request{Header: make(http.Header)}
@ -132,7 +138,7 @@ func TestAllowed(t *testing.T) {
allowHosts []string allowHosts []string
denyHosts []string denyHosts []string
referrers []string referrers []string
key []byte keys [][]byte
request *http.Request request *http.Request
allowed bool allowed bool
}{ }{
@ -151,7 +157,10 @@ func TestAllowed(t *testing.T) {
// signature key // signature key
{"http://test/image", Options{Signature: "NDx5zZHx7QfE8E-ijowRreq6CJJBZjwiRfOVk_mkfQQ="}, nil, nil, nil, key, nil, true}, {"http://test/image", Options{Signature: "NDx5zZHx7QfE8E-ijowRreq6CJJBZjwiRfOVk_mkfQQ="}, nil, nil, nil, key, nil, true},
{"http://test/image", Options{Signature: "NDx5zZHx7QfE8E-ijowRreq6CJJBZjwiRfOVk_mkfQQ="}, nil, nil, nil, multipleKey, nil, true}, // signed with key "c0ffee"
{"http://test/image", Options{Signature: "FWIawYV4SEyI4zKJMeGugM-eJM1eI_jXPEQ20ZgRe4A="}, nil, nil, nil, multipleKey, nil, true}, // signed with key "beer"
{"http://test/image", Options{Signature: "deadbeef"}, nil, nil, nil, key, nil, false}, {"http://test/image", Options{Signature: "deadbeef"}, nil, nil, nil, key, nil, false},
{"http://test/image", Options{Signature: "deadbeef"}, nil, nil, nil, multipleKey, nil, false},
{"http://test/image", emptyOptions, nil, nil, nil, key, nil, false}, {"http://test/image", emptyOptions, nil, nil, nil, key, nil, false},
// allowHosts and signature // allowHosts and signature
@ -169,7 +178,7 @@ func TestAllowed(t *testing.T) {
p := NewProxy(nil, nil) p := NewProxy(nil, nil)
p.AllowHosts = tt.allowHosts p.AllowHosts = tt.allowHosts
p.DenyHosts = tt.denyHosts p.DenyHosts = tt.denyHosts
p.SignatureKey = tt.key p.SignatureKeys = tt.keys
p.Referrers = tt.referrers p.Referrers = tt.referrers
u, err := url.Parse(tt.url) u, err := url.Parse(tt.url)