From 8ab694dd191c6f70d6c2456f3bfb1f75f23b624c Mon Sep 17 00:00:00 2001 From: Patrick Peng Sun Date: Thu, 6 Jul 2017 16:23:38 +1000 Subject: [PATCH] signature for intra api using token signature and nonance timestamp , TestGetAccessToken worked. --- common_test.go | 3 ++ configIntraApi.go | 32 ++++++++++++++++++ intrapi_config.json | 3 ++ server.go | 35 +++++++++++++++++-- server_test.go | 82 +++++++++++++++++++++++++++++++-------------- 5 files changed, 126 insertions(+), 29 deletions(-) create mode 100644 configIntraApi.go create mode 100644 intrapi_config.json diff --git a/common_test.go b/common_test.go index 4b1c89d..d71c390 100644 --- a/common_test.go +++ b/common_test.go @@ -31,6 +31,9 @@ func SetupConfig() { "wechat", "crmwechat.api", "/tmp/"} + IntraAPIConfig = ConfigIntraAPI{ + "cAT/ckkfjajvczxiaufodqdfakpozcczfas341fda.vfasdk/8934125", + } GlobalPath = PathsConfig{"/tmp"} KFUsers.kfRenewList() } diff --git a/configIntraApi.go b/configIntraApi.go new file mode 100644 index 0000000..6e49739 --- /dev/null +++ b/configIntraApi.go @@ -0,0 +1,32 @@ +package main + +import ( + "encoding/json" + "errors" + "io/ioutil" + "log" +) + +//ConfigIntraAPI config for intra server api +type ConfigIntraAPI struct { + CRMSecrete string `json:"CRMScrete,omitempty"` +} + +//IntraAPIConfig Configuration Data for Intra Server API +var IntraAPIConfig ConfigIntraAPI + +func (m *ConfigIntraAPI) readConfig() (err error) { + path := "intrapi_config.json" + log.Printf("read Intra API config from %s\r\n", path) + body, err := ioutil.ReadFile(path) + if err != nil { + log.Fatalf("Cannot read config from %s ", path) + return err + } + err = json.Unmarshal(body, &IntraAPIConfig) + if IntraAPIConfig.CRMSecrete == "" { + return errors.New("CRM CRMSecrete not available not available") + } + + return +} diff --git a/intrapi_config.json b/intrapi_config.json new file mode 100644 index 0000000..903af04 --- /dev/null +++ b/intrapi_config.json @@ -0,0 +1,3 @@ +{ + "CRMScrete": "cAT/ckkfjajvczxiaufodqdfakpozcczfas341fda.vfasdk/8934125" +} \ No newline at end of file diff --git a/server.go b/server.go index 0a9c1a7..ae02499 100644 --- a/server.go +++ b/server.go @@ -136,23 +136,51 @@ func answerWechatPostEcho(w http.ResponseWriter, r *http.Request) { // func checkSignature(r *http.Request) bool { + return checkSignatureByToken(r, APIConfig.Token) +} + +func checkSignatureByToken(r *http.Request, token string) bool { rq := r.URL.RawQuery m, _ := url.ParseQuery(rq) signature, sok := m["signature"] timestamp, tok := m["timestamp"] nonce, nok := m["nonce"] - token := APIConfig.Token - if sok && tok && nok { + token = strings.TrimSpace(token) + if sok && tok && nok && token != "" { return verifySignature(signature[0], timestamp[0], nonce[0], token) } return false } +func checkCookieSignatureBytoken(r *http.Request, token string) bool { + signature := "" + nonce := "" + timestamp := "" + for _, c := range r.Cookies() { + switch c.Name { + case "signature": + signature = c.Value + case "nonce": + nonce = c.Value + case "timestamp": + timestamp = c.Value + } + } + if signature != "" && nonce != "" && timestamp != "" { + return verifySignature(signature, timestamp, nonce, IntraAPIConfig.CRMSecrete) + } + return false +} + func verifySignature(signature, timestamp, nonce, token string) bool { if timestampTooOldStr(timestamp) { return false } + return signature == calculateSignature(timestamp, nonce, token) +} + +func calculateSignature(timestamp, nonce, token string) (signature string) { //sort token, timestamp, nonce and join them strs := []string{token, timestamp, nonce} sort.Strings(strs) @@ -162,7 +190,8 @@ func verifySignature(signature, timestamp, nonce, token string) bool { h := sha1.New() h.Write([]byte(s)) calculated := fmt.Sprintf("%x", h.Sum(nil)) - return signature == calculated + signature = calculated + return } func timestampTooOldStr(timestamp string) bool { diff --git a/server_test.go b/server_test.go index f6d3ae9..126b489 100644 --- a/server_test.go +++ b/server_test.go @@ -7,19 +7,16 @@ import ( "net/http" "net/http/httptest" "testing" + "time" ) //when we setup wechate parameters,we chat will verify us func TestInitialSetup(t *testing.T) { - - - - req := buildReqWechatAPISetup() + expected := `913461463450840893` + req := buildReqWechatAPISetup(expected) rr, _ := getHTTPResponse(req, answerInitialAuth) - // Check the response body is what we expect. - expected := `913461463450840893` if rr.Body.String() != expected { t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) @@ -27,7 +24,7 @@ func TestInitialSetup(t *testing.T) { } func TestWebRootHandler(t *testing.T) { - + req := buildReqWechatWebRoot() rr, _ := getHTTPResponse(req, webrootHandler) @@ -46,7 +43,7 @@ echostr => [913461463450840893]` //we only check decrypted ToUserName should be the one we sent out. //as decrypt itself is already a good proof of its working state. func TestPostTxtMsg(t *testing.T) { - + req := buildReqWechatPostTxtMsg() rr, _ := getHTTPResponse(req, apiV1Main) @@ -62,6 +59,17 @@ func TestPostTxtMsg(t *testing.T) { } +func TestGetAccesstoken(t *testing.T) { + req := buildReqGetAccessToken() + rr, _ := getHTTPResponse(req, supplyAccessToken) + errorResponse := "errortoken" + m := rr.Body.String() + expected, _ := GetAccessToken() + log.Printf("TestGetAccesstoken got: [%s] ", m) + AssertEqual(t, m != errorResponse, true, "Signature check failed, error response") + AssertEqual(t, m, expected, "token incorrect") +} + func getHTTPResponse(req *http.Request, handler http.HandlerFunc) (rr *httptest.ResponseRecorder, err error) { // Our handlers satisfy http.Handler, so we can call their ServeHTTP method @@ -109,9 +117,9 @@ func buildReqWechatPostTxtMsg() *http.Request { ` b := bytes.NewBufferString(xml) - req, _ := http.NewRequest("POST", "/api?signature=f06bb28c1d3847815d498fc0a343b11b4d03e095×tamp=1493212928&nonce=1461107899&openid=oUN420bxqFqlx0ZQHciUOesZO3PE&encrypt_type=aes&msg_signature=61a50d4656b13a7bbeecf53a5a85fbf37835762f", b) + req, _ := http.NewRequest("POST", "/api?openid=oUN420bxqFqlx0ZQHciUOesZO3PE&encrypt_type=aes&msg_signature=61a50d4656b13a7bbeecf53a5a85fbf37835762f", b) + buildReqCommonSignature(req, APIConfig.Token) buildReqCommonHeader(req) - return req } @@ -125,7 +133,7 @@ func buildReqWechatWebRoot() *http.Request { return req } -func buildReqWechatAPISetup() *http.Request { +func buildReqWechatAPISetup(echostr string) *http.Request { // Create a request to pass to our handler. //We don't have any query body for now, so we'll // pass 'nil' as the third parameter. @@ -133,18 +141,41 @@ func buildReqWechatAPISetup() *http.Request { if err != nil { log.Fatal(err) } - + buildReqCommonSignature(req, APIConfig.Token) q := req.URL.Query() - q.Add("signature", "e39de9f2e28079c01ebb4b803dfc3442b819545c") - q.Add("echostr", "913461463450840893") - q.Add("timestamp", "1492970761") - q.Add("nonce", "1850971833") + q.Add("echostr", echostr) req.URL.RawQuery = q.Encode() buildReqCommonHeader(req) return req } +func buildReqGetAccessToken() *http.Request { + req, err := http.NewRequest("GET", "/iapi/getAccessToken", nil) + if err != nil { + log.Fatal(err) + } + buildReqCommonSignature(req, IntraAPIConfig.CRMSecrete) + buildReqCommonHeader(req) + return req +} + +func buildSignature(token string) (signature, timestamp, nonce string) { + timestamp = fmt.Sprintf("%d", int32(time.Now().Unix())) + nonce = "1461107899" //a randome string cut from previous wechat request + signature = calculateSignature(timestamp, nonce, token) + return +} + +func buildReqCommonSignature(req *http.Request, token string) { + signature, timestamp, nonce := buildSignature(token) + q := req.URL.Query() + q.Add("signature", signature) + q.Add("timestamp", timestamp) + q.Add("nonce", nonce) + req.URL.RawQuery = q.Encode() +} + func buildReqCommonHeader(r *http.Request) { // // example request @@ -160,15 +191,14 @@ func buildReqCommonHeader(r *http.Request) { // X-Forwarded-Host: wechat.hitxy.org.au // X-Forwarded-Server: wechat.hitxy.org.au - h := r.Header - h.Set("Host", "wechat.hitxy.org.au") - h.Set("Accept", "*/*") - h.Set("Cache-Control", "no-cache") - h.Set("Connection", "Keep-Alive") - h.Set("Pragma", "no-cache") - h.Set("User-Agent", "Patrick testcase") - h.Set("X-Forwarded-For", "103.7.30.107") - h.Set("X-Forwarded-Host", "wechat.hitxy.org.au") - h.Set("X-Forwarded-Server", "wechat.hitxy.org.au") + r.Header.Set("Host", "wechat.hitxy.org.au") + r.Header.Set("Accept", "*/*") + r.Header.Set("Cache-Control", "no-cache") + r.Header.Set("Connection", "Keep-Alive") + r.Header.Set("Pragma", "no-cache") + r.Header.Set("User-Agent", "Patrick testcase") + r.Header.Set("X-Forwarded-For", "103.7.30.107") + r.Header.Set("X-Forwarded-Host", "wechat.hitxy.org.au") + r.Header.Set("X-Forwarded-Server", "wechat.hitxy.org.au") }