-
Notifications
You must be signed in to change notification settings - Fork 351
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
`HeaderSHA256` predicate matches SHA-256 hash of the configured header value. ``` $ go test ./predicates/auth/ -run NONE -bench BenchmarkHeaderSHA256Match -benchmem goos: linux goarch: amd64 pkg: github.com/zalando/skipper/predicates/auth cpu: Intel(R) Core(TM) i5-8350U CPU @ 1.70GHz BenchmarkHeaderSHA256Match-8 3489882 340.6 ns/op 32 B/op 1 allocs/op ``` Signed-off-by: Alexander Yastrebov <[email protected]>
- Loading branch information
1 parent
1e26fcd
commit bb9d8ec
Showing
5 changed files
with
225 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
package auth | ||
|
||
import ( | ||
"bytes" | ||
"crypto/sha256" | ||
"encoding/hex" | ||
"net/http" | ||
|
||
"github.com/zalando/skipper/predicates" | ||
"github.com/zalando/skipper/routing" | ||
) | ||
|
||
type headerSha256Spec struct{} | ||
|
||
type headerSha256Predicate struct { | ||
name string | ||
hashes [][]byte | ||
} | ||
|
||
// NewHeaderSHA256 creates a predicate specification, whose instances match SHA-256 hash of the header value. | ||
// | ||
// The HeaderSHA256 predicate requires the header name and one or more hex-encoded SHA-256 hash values of the matching header. | ||
func NewHeaderSHA256() routing.PredicateSpec { return &headerSha256Spec{} } | ||
|
||
func (*headerSha256Spec) Name() string { | ||
return predicates.HeaderSHA256Name | ||
} | ||
|
||
// Create a predicate instance matching SHA256 hash of the header value | ||
func (*headerSha256Spec) Create(args []interface{}) (routing.Predicate, error) { | ||
if len(args) < 2 { | ||
return nil, predicates.ErrInvalidPredicateParameters | ||
} | ||
|
||
name, ok := args[0].(string) | ||
if !ok { | ||
return nil, predicates.ErrInvalidPredicateParameters | ||
} | ||
|
||
var hashes [][]byte | ||
for _, arg := range args[1:] { | ||
hexHash, ok := arg.(string) | ||
if !ok { | ||
return nil, predicates.ErrInvalidPredicateParameters | ||
} | ||
hash, err := hex.DecodeString(hexHash) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if len(hash) != sha256.Size { | ||
return nil, predicates.ErrInvalidPredicateParameters | ||
} | ||
hashes = append(hashes, hash) | ||
} | ||
|
||
return &headerSha256Predicate{name, hashes}, nil | ||
} | ||
|
||
func (p *headerSha256Predicate) Match(r *http.Request) bool { | ||
value := r.Header.Get(p.name) | ||
if value == "" { | ||
return false | ||
} | ||
|
||
h := sha256.New() | ||
h.Write([]byte(value)) | ||
valueHash := h.Sum(nil) | ||
|
||
for _, hash := range p.hashes { | ||
if bytes.Equal(valueHash, hash) { | ||
return true | ||
} | ||
} | ||
|
||
return false | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package auth | ||
|
||
import ( | ||
"net/http" | ||
"testing" | ||
) | ||
|
||
func TestHeaderSHA256Args(t *testing.T) { | ||
s := NewHeaderSHA256() | ||
for _, tc := range []struct { | ||
args []interface{} | ||
}{ | ||
{ | ||
args: []interface{}{}, | ||
}, | ||
{ | ||
args: []interface{}{"X-Secret", "xyz"}, | ||
}, | ||
{ | ||
args: []interface{}{"X-Secret", "00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF", "AA"}, | ||
}, | ||
} { | ||
if _, err := s.Create(tc.args); err == nil { | ||
t.Errorf("expected error for arguments: %v", tc.args) | ||
} | ||
} | ||
} | ||
|
||
func TestHeaderSHA256Match(t *testing.T) { | ||
s := NewHeaderSHA256() | ||
p, err := s.Create([]interface{}{ | ||
"X-Secret", | ||
"2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b", // "secret" | ||
"5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8", // "password" | ||
}) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
for _, tc := range []struct { | ||
header http.Header | ||
match bool | ||
}{ | ||
{ | ||
header: http.Header{ | ||
"X-Test": []string{"foo"}, | ||
}, | ||
match: false, | ||
}, | ||
{ | ||
header: http.Header{ | ||
"X-Secret": []string{"foo"}, | ||
}, | ||
match: false, | ||
}, | ||
{ | ||
header: http.Header{ | ||
"X-Secret": []string{"SECRET"}, | ||
}, | ||
match: false, | ||
}, | ||
{ | ||
header: http.Header{ | ||
"X-Secret": []string{"PASSWORD"}, | ||
}, | ||
match: false, | ||
}, | ||
{ | ||
header: http.Header{ | ||
"X-Secret": []string{"secret"}, | ||
}, | ||
match: true, | ||
}, | ||
{ | ||
header: http.Header{ | ||
"X-Secret": []string{"password"}, | ||
}, | ||
match: true, | ||
}, | ||
} { | ||
if p.Match(&http.Request{Header: tc.header}) != tc.match { | ||
t.Errorf("expected match: %v", tc.match) | ||
} | ||
} | ||
} | ||
|
||
func BenchmarkHeaderSHA256Match(b *testing.B) { | ||
s := NewHeaderSHA256() | ||
p, err := s.Create([]interface{}{"X-Secret", "2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b"}) | ||
if err != nil { | ||
b.Fatal(err) | ||
} | ||
r := &http.Request{Header: http.Header{"X-Secret": []string{"secret"}}} | ||
if !p.Match(r) { | ||
b.Fatal("match expected") | ||
} | ||
b.ResetTimer() | ||
for i := 0; i < b.N; i++ { | ||
p.Match(r) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters