File: authenticate_callback.go

package info (click to toggle)
golang-github-denverdino-aliyungo 0.0~git20180921.13fa8aa-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 1,824 kB
  • sloc: xml: 1,359; makefile: 3
file content (88 lines) | stat: -rw-r--r-- 2,264 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package oss

import (
	"crypto"
	"crypto/md5"
	"crypto/rsa"
	"crypto/x509"
	"encoding/base64"
	"encoding/pem"
	"errors"
	"io/ioutil"
	"net/http"
	"regexp"
	"strings"
	"sync"
)

type authenticationType struct {
	lock        *sync.RWMutex
	certificate map[string]*rsa.PublicKey
}

var (
	authentication = authenticationType{lock: &sync.RWMutex{}, certificate: map[string]*rsa.PublicKey{}}
	urlReg         = regexp.MustCompile(`^http(|s)://gosspublic.alicdn.com/[0-9a-zA-Z]`)
)

//验证OSS向业务服务器发来的回调函数。
//该方法是并发安全的
//pubKeyUrl 回调请求头中[x-oss-pub-key-url]一项,以Base64编码
//reqUrl oss所发来请求的url,由path+query组成
//reqBody oss所发来请求的body
//authorization authorization为回调头中的签名
func AuthenticateCallBack(pubKeyUrl, reqUrl, reqBody, authorization string) error {
	//获取证书url
	keyURL, err := base64.URLEncoding.DecodeString(pubKeyUrl)
	if err != nil {
		return err
	}
	url := string(keyURL)
	//判断证书是否来自于阿里云
	if !urlReg.Match(keyURL) {
		return errors.New("certificate address error")
	}
	//获取文件名
	rs := []rune(url)
	filename := string(rs[strings.LastIndex(url, "/") : len(rs)-1])
	authentication.lock.RLock()
	certificate := authentication.certificate[filename]
	authentication.lock.RUnlock()
	//内存中没有证书,下载
	if certificate == nil {
		authentication.lock.Lock()
		res, err := http.Get(url)
		if err != nil {
			return err
		}
		defer res.Body.Close()
		body, err := ioutil.ReadAll(res.Body)
		if err != nil {
			return err
		}
		block, _ := pem.Decode(body)
		if block == nil {
			return errors.New("certificate error")
		}
		pubKey, err := x509.ParsePKIXPublicKey(block.Bytes)
		if err != nil {
			return err
		}
		certificate = pubKey.(*rsa.PublicKey)
		authentication.certificate[filename] = certificate
		authentication.lock.Unlock()
	}
	//证书准备完毕,开始验证
	//解析签名
	signature, err := base64.StdEncoding.DecodeString(authorization)
	if err != nil {
		return err
	}
	hashed := md5.New()
	hashed.Write([]byte(reqUrl + "\n" + reqBody))
	if err := rsa.VerifyPKCS1v15(certificate, crypto.MD5, hashed.Sum(nil), signature); err != nil {
		return err
	}
	//验证通过
	return nil
}