add more tests for rest (#462)
parent
28009c4224
commit
395a1db22f
@ -0,0 +1,64 @@
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: "etcd"
|
||||
namespace: discov
|
||||
labels:
|
||||
app: "etcd"
|
||||
spec:
|
||||
serviceName: "etcd"
|
||||
replicas: 5
|
||||
template:
|
||||
metadata:
|
||||
name: "etcd"
|
||||
labels:
|
||||
app: "etcd"
|
||||
spec:
|
||||
volumes:
|
||||
- name: etcd-pvc
|
||||
persistentVolumeClaim:
|
||||
claimName: etcd-pvc
|
||||
containers:
|
||||
- name: "etcd"
|
||||
image: quay.io/coreos/etcd:latest
|
||||
ports:
|
||||
- containerPort: 2379
|
||||
name: client
|
||||
- containerPort: 2380
|
||||
name: peer
|
||||
env:
|
||||
- name: CLUSTER_SIZE
|
||||
value: "5"
|
||||
- name: SET_NAME
|
||||
value: "etcd"
|
||||
- name: VOLNAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
apiVersion: v1
|
||||
fieldPath: metadata.name
|
||||
volumeMounts:
|
||||
- name: etcd-pvc
|
||||
mountPath: /var/lib/etcd
|
||||
subPathExpr: $(VOLNAME) # data mounted respectively in each pod
|
||||
command:
|
||||
- "/bin/sh"
|
||||
- "-ecx"
|
||||
- |
|
||||
|
||||
chmod 700 /var/lib/etcd
|
||||
|
||||
IP=$(hostname -i)
|
||||
PEERS=""
|
||||
for i in $(seq 0 $((${CLUSTER_SIZE} - 1))); do
|
||||
PEERS="${PEERS}${PEERS:+,}${SET_NAME}-${i}=http://${SET_NAME}-${i}.${SET_NAME}:2380"
|
||||
done
|
||||
exec etcd --name ${HOSTNAME} \
|
||||
--listen-peer-urls http://0.0.0.0:2380 \
|
||||
--listen-client-urls http://0.0.0.0:2379 \
|
||||
--advertise-client-urls http://${HOSTNAME}.${SET_NAME}.discov:2379 \
|
||||
--initial-advertise-peer-urls http://${HOSTNAME}.${SET_NAME}:2380 \
|
||||
--initial-cluster ${PEERS} \
|
||||
--initial-cluster-state new \
|
||||
--logger zap \
|
||||
--data-dir /var/lib/etcd \
|
||||
--auto-compaction-retention 1
|
@ -0,0 +1,169 @@
|
||||
package security
|
||||
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/tal-tech/go-zero/core/codec"
|
||||
"github.com/tal-tech/go-zero/core/fs"
|
||||
"github.com/tal-tech/go-zero/rest/httpx"
|
||||
)
|
||||
|
||||
const (
|
||||
pubKey = `-----BEGIN PUBLIC KEY-----
|
||||
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCyeDYV2ieOtNDi6tuNtAbmUjN9
|
||||
pTHluAU5yiKEz8826QohcxqUKP3hybZBcm60p+rUxMAJFBJ8Dt+UJ6sEMzrf1rOF
|
||||
YOImVvORkXjpFU7sCJkhnLMs/kxtRzcZJG6ADUlG4GDCNcZpY/qELEvwgm2kCcHi
|
||||
tGC2mO8opFFFHTR0aQIDAQAB
|
||||
-----END PUBLIC KEY-----`
|
||||
priKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICXQIBAAKBgQCyeDYV2ieOtNDi6tuNtAbmUjN9pTHluAU5yiKEz8826QohcxqU
|
||||
KP3hybZBcm60p+rUxMAJFBJ8Dt+UJ6sEMzrf1rOFYOImVvORkXjpFU7sCJkhnLMs
|
||||
/kxtRzcZJG6ADUlG4GDCNcZpY/qELEvwgm2kCcHitGC2mO8opFFFHTR0aQIDAQAB
|
||||
AoGAcENv+jT9VyZkk6karLuG75DbtPiaN5+XIfAF4Ld76FWVOs9V88cJVON20xpx
|
||||
ixBphqexCMToj8MnXuHJEN5M9H15XXx/9IuiMm3FOw0i6o0+4V8XwHr47siT6T+r
|
||||
HuZEyXER/2qrm0nxyC17TXtd/+TtpfQWSbivl6xcAEo9RRECQQDj6OR6AbMQAIDn
|
||||
v+AhP/y7duDZimWJIuMwhigA1T2qDbtOoAEcjv3DB1dAswJ7clcnkxI9a6/0RDF9
|
||||
0IEHUcX9AkEAyHdcegWiayEnbatxWcNWm1/5jFnCN+GTRRFrOhBCyFr2ZdjFV4T+
|
||||
acGtG6omXWaZJy1GZz6pybOGy93NwLB93QJARKMJ0/iZDbOpHqI5hKn5mhd2Je25
|
||||
IHDCTQXKHF4cAQ+7njUvwIMLx2V5kIGYuMa5mrB/KMI6rmyvHv3hLewhnQJBAMMb
|
||||
cPUOENMllINnzk2oEd3tXiscnSvYL4aUeoErnGP2LERZ40/YD+mMZ9g6FVboaX04
|
||||
0oHf+k5mnXZD7WJyJD0CQQDJ2HyFbNaUUHK+lcifCibfzKTgmnNh9ZpePFumgJzI
|
||||
EfFE5H+nzsbbry2XgJbWzRNvuFTOLWn4zM+aFyy9WvbO
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
body = "hello world!"
|
||||
)
|
||||
|
||||
var key = []byte("q4t7w!z%C*F-JaNdRgUjXn2r5u8x/A?D")
|
||||
|
||||
func TestContentSecurity(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
mode string
|
||||
extraKey string
|
||||
extraSecret string
|
||||
extraTime string
|
||||
err error
|
||||
code int
|
||||
}{
|
||||
{
|
||||
name: "encrypted",
|
||||
mode: "1",
|
||||
},
|
||||
{
|
||||
name: "unencrypted",
|
||||
mode: "0",
|
||||
},
|
||||
{
|
||||
name: "bad content type",
|
||||
mode: "a",
|
||||
err: ErrInvalidContentType,
|
||||
},
|
||||
{
|
||||
name: "bad secret",
|
||||
mode: "1",
|
||||
extraSecret: "any",
|
||||
err: ErrInvalidSecret,
|
||||
},
|
||||
{
|
||||
name: "bad key",
|
||||
mode: "1",
|
||||
extraKey: "any",
|
||||
err: ErrInvalidKey,
|
||||
},
|
||||
{
|
||||
name: "bad time",
|
||||
mode: "1",
|
||||
extraTime: "any",
|
||||
code: httpx.CodeSignatureInvalidHeader,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
test := test
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
r, err := http.NewRequest(http.MethodPost, "http://localhost:3333/a/b?c=first&d=second",
|
||||
strings.NewReader(body))
|
||||
assert.Nil(t, err)
|
||||
|
||||
timestamp := time.Now().Unix()
|
||||
sha := sha256.New()
|
||||
sha.Write([]byte(body))
|
||||
bodySign := fmt.Sprintf("%x", sha.Sum(nil))
|
||||
contentOfSign := strings.Join([]string{
|
||||
strconv.FormatInt(timestamp, 10),
|
||||
http.MethodPost,
|
||||
r.URL.Path,
|
||||
r.URL.RawQuery,
|
||||
bodySign,
|
||||
}, "\n")
|
||||
sign := hs256(key, contentOfSign)
|
||||
content := strings.Join([]string{
|
||||
"version=v1",
|
||||
"type=" + test.mode,
|
||||
fmt.Sprintf("key=%s", base64.StdEncoding.EncodeToString(key)) + test.extraKey,
|
||||
"time=" + strconv.FormatInt(timestamp, 10) + test.extraTime,
|
||||
}, "; ")
|
||||
|
||||
encrypter, err := codec.NewRsaEncrypter([]byte(pubKey))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
output, err := encrypter.Encrypt([]byte(content))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
encryptedContent := base64.StdEncoding.EncodeToString(output)
|
||||
r.Header.Set("X-Content-Security", strings.Join([]string{
|
||||
fmt.Sprintf("key=%s", fingerprint(pubKey)),
|
||||
"secret=" + encryptedContent + test.extraSecret,
|
||||
"signature=" + sign,
|
||||
}, "; "))
|
||||
|
||||
file, err := fs.TempFilenameWithText(priKey)
|
||||
assert.Nil(t, err)
|
||||
defer os.Remove(file)
|
||||
|
||||
dec, err := codec.NewRsaDecrypter(file)
|
||||
assert.Nil(t, err)
|
||||
|
||||
header, err := ParseContentSecurity(map[string]codec.RsaDecrypter{
|
||||
fingerprint(pubKey): dec,
|
||||
}, r)
|
||||
assert.Equal(t, test.err, err)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, test.code, VerifySignature(r, header, time.Minute))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func fingerprint(key string) string {
|
||||
h := md5.New()
|
||||
io.WriteString(h, key)
|
||||
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
func hs256(key []byte, body string) string {
|
||||
h := hmac.New(sha256.New, key)
|
||||
io.WriteString(h, body)
|
||||
return base64.StdEncoding.EncodeToString(h.Sum(nil))
|
||||
}
|
Loading…
Reference in New Issue