Skip to content

Commit

Permalink
add more tests for rest (zeromicro#462)
Browse files Browse the repository at this point in the history
  • Loading branch information
kevwan authored Feb 10, 2021
1 parent 28009c4 commit 395a1db
Show file tree
Hide file tree
Showing 2 changed files with 233 additions and 0 deletions.
64 changes: 64 additions & 0 deletions core/discov/kubernetes/etcd-statefulset.yaml
Original file line number Diff line number Diff line change
@@ -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
169 changes: 169 additions & 0 deletions rest/internal/security/contentsecurity_test.go
Original file line number Diff line number Diff line change
@@ -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))
}

0 comments on commit 395a1db

Please sign in to comment.