@@ -0,0 +1,13 @@ | |||
package credentials | |||
type AliAppcodeCredential struct { | |||
AccessKeyId string `json:"access_key_id" yaml:"access_key_id"` | |||
AccessKeySecret string `json:"access_key_secret" yaml:"access_key_secret"` | |||
} | |||
func NewAliAppcodeCredential(accessKeyId, accessKeySecret string) *AliAppcodeCredential { | |||
return &AliAppcodeCredential{ | |||
AccessKeyId: accessKeyId, | |||
AccessKeySecret: accessKeySecret, | |||
} | |||
} |
@@ -0,0 +1,156 @@ | |||
package auth | |||
import ( | |||
"bytes" | |||
"errors" | |||
"fmt" | |||
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" | |||
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/utils" | |||
"net/http" | |||
"net/url" | |||
"sort" | |||
"strconv" | |||
"strings" | |||
"time" | |||
) | |||
func signRaliRequest(request requests.AcsRequest, signer Signer) (err error) { | |||
err = completeRaliSignParams(request, signer) | |||
if err != nil { | |||
return | |||
} | |||
stringToSign := buildRaliStringToSign(request) | |||
request.SetStringToSign(stringToSign) | |||
signature := signer.Sign(stringToSign, "") | |||
request.GetHeaders()["X-Ca-Signature"] = signature | |||
debug("GrSdk sign: %s", signature) | |||
debug("GrSdk sign string: %s", strings.ReplaceAll(stringToSign, "\n", "#")) | |||
debug("GrSdk sign: \r\n") | |||
return | |||
} | |||
func completeRaliSignParams(request requests.AcsRequest, signer Signer) (err error) { | |||
request.GetHeaders()["X-Ca-Timestamp"] = fmt.Sprintf("%d", time.Now().Unix()*1000) | |||
request.GetHeaders()["X-Ca-Signature-Method"] = signer.GetName() | |||
request.GetHeaders()["X-Ca-Nonce"] = utils.GetUUID() | |||
request.GetHeaders()["X-Ca-Key"], err = signer.GetAccessKeyId() | |||
if request.GetMethod() == requests.POST { | |||
request.GetHeaders()["Content-type"] = requests.Form | |||
} | |||
formString := utils.GetUrlFormedMap(request.GetFormParams()) | |||
request.SetContent(bytes.NewBufferString(formString).Bytes()) | |||
return | |||
} | |||
func buildRaliSignHeader(request requests.AcsRequest) (str1, str2 string) { | |||
headParams := make(map[string]string) | |||
signatureHeaders := make([]string, 0) | |||
for key, val := range request.GetHeaders() { | |||
headParams[key] = val | |||
} | |||
delete(headParams, "X-Ca-Signature") | |||
delete(headParams, "X-Ca-Signature-Headers") | |||
delete(headParams, "Accept") | |||
delete(headParams, "Content-MD5") | |||
delete(headParams, "Content-Type") | |||
delete(headParams, "Date") | |||
for key, _ := range headParams { | |||
signatureHeaders = append(signatureHeaders, key) | |||
} | |||
sort.Strings(signatureHeaders) | |||
for _, key := range signatureHeaders { | |||
str1 += fmt.Sprintf("%s:%s\n", key, headParams[key]) | |||
} | |||
return strings.TrimRight(str1, "\n"), strings.Join(signatureHeaders, ",") | |||
} | |||
func buildRaliStringToSign(request requests.AcsRequest) (stringToSign string) { | |||
signParams := make(map[string]string) | |||
for key, value := range request.GetQueryParams() { | |||
signParams[key] = value | |||
} | |||
if strings.ToUpper(request.GetMethod()) == requests.POST { | |||
for key, value := range request.GetFormParams() { | |||
signParams[key] = value | |||
} | |||
} | |||
str1, str2 := buildRaliSignHeader(request) | |||
stringToSign = request.GetMethod() + "\n" | |||
stringToSign += request.GetHeaders()["Accept"] + "\n\n" | |||
stringToSign += request.GetHeaders()["Content-type"] + "\n\n" | |||
stringToSign += str1 + "\n" | |||
stringToSign += request.GetActionName() + "?" + utils.GetUrlByKeySort(signParams) | |||
request.GetHeaders()["X-Ca-Signature-Headers"] = str2 | |||
//stringToSign = utils.GetUrlFormedMap(signParams) | |||
//stringToSign = strings.Replace(stringToSign, "+", "%20", -1) | |||
//stringToSign = strings.Replace(stringToSign, "*", "%2A", -1) | |||
//stringToSign = strings.Replace(stringToSign, "%7E", "~", -1) | |||
//stringToSign = url.QueryEscape(stringToSign) | |||
//stringToSign = request.GetMethod() + "&%2F&" + stringToSign | |||
return | |||
} | |||
func unsignRaliRequest(request *http.Request, signer Signer) (err error) { | |||
signParams := make(map[string]string) | |||
for key, value := range request.URL.Query() { | |||
signParams[key] = value[0] | |||
} | |||
if strings.ToUpper(request.Method) == requests.POST { | |||
for key, value := range request.Form { | |||
signParams[key] = value[0] | |||
} | |||
} | |||
if accessKey, err := signer.GetAccessKeyId(); err != nil { | |||
return err | |||
} else if accessKey == "" { | |||
return errors.New("access key is not allow empty") | |||
} else if accessKey != signParams["access_key"] { | |||
return errors.New("illegal access key") | |||
} | |||
signValue, ok := signParams["sign"] | |||
if !ok { | |||
return errors.New("sign value is not exists") | |||
} else { | |||
delete(signParams, "sign") | |||
} | |||
stringToSign := utils.GetUrlFormedMap(signParams) | |||
stringToSign = strings.Replace(stringToSign, "+", "%20", -1) | |||
stringToSign = strings.Replace(stringToSign, "*", "%2A", -1) | |||
stringToSign = strings.Replace(stringToSign, "%7E", "~", -1) | |||
stringToSign = url.QueryEscape(stringToSign) | |||
stringToSign = request.Method + "&%2F&" + stringToSign | |||
debug("GrSdk sign: %s", stringToSign) | |||
if timestamp, err := strconv.ParseInt(signParams["access_time"], 10, 64); err != nil { | |||
return err | |||
} else { | |||
if time.Unix(timestamp, 0).Before(time.Now().Add(-5 * time.Minute)) { | |||
err = errors.New("sign timeout 5 minute") | |||
} | |||
} | |||
if signer.Sign(stringToSign, "&") != signValue { | |||
return errors.New("sign string is not correct") | |||
} | |||
return | |||
} |
@@ -0,0 +1,128 @@ | |||
package auth | |||
import ( | |||
"bytes" | |||
"errors" | |||
"fmt" | |||
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/requests" | |||
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/utils" | |||
"net/http" | |||
"net/url" | |||
"strconv" | |||
"strings" | |||
"time" | |||
) | |||
func signRoaRequest(request requests.AcsRequest, signer Signer) (err error) { | |||
err = completeRoaSignParams(request, signer) | |||
if err != nil { | |||
return | |||
} | |||
if _, isContainsSign := request.GetQueryParams()["sign"]; isContainsSign { | |||
delete(request.GetQueryParams(), "sign") | |||
} | |||
stringToSign := buildRoaStringToSign(request) | |||
request.SetStringToSign(stringToSign) | |||
signature := signer.Sign(stringToSign, "&") | |||
request.GetQueryParams()["sign"] = signature | |||
debug("GrSdk sign: %s", signature) | |||
debug("GrSdk sign string: %s", stringToSign) | |||
debug("GrSdk sign: \r\n") | |||
return | |||
} | |||
func completeRoaSignParams(request requests.AcsRequest, signer Signer) (err error) { | |||
var accessKeyFrom string | |||
if accessKeyFrom, err = signer.GetAccessKeyFrom(); err != nil { | |||
return | |||
} | |||
queryParams := request.GetQueryParams() | |||
queryParams["access_time"] = fmt.Sprintf("%d", time.Now().Unix()) | |||
queryParams["access_key"], err = signer.GetAccessKeyId() | |||
queryParams["access_from"] = accessKeyFrom | |||
if err != nil { | |||
return | |||
} | |||
if request.GetMethod() == requests.POST { | |||
request.GetHeaders()["Content-type"] = requests.Form | |||
} | |||
request.GetHeaders()["Gr-Sdk-From"] = accessKeyFrom | |||
formString := utils.GetUrlFormedMap(request.GetFormParams()) | |||
request.SetContent(bytes.NewBufferString(formString).Bytes()) | |||
return | |||
} | |||
func buildRoaStringToSign(request requests.AcsRequest) (stringToSign string) { | |||
signParams := make(map[string]string) | |||
for key, value := range request.GetQueryParams() { | |||
signParams[key] = value | |||
} | |||
if strings.ToUpper(request.GetMethod()) == requests.POST { | |||
for key, value := range request.GetFormParams() { | |||
signParams[key] = value | |||
} | |||
} | |||
stringToSign = utils.GetUrlFormedMap(signParams) | |||
stringToSign = strings.Replace(stringToSign, "+", "%20", -1) | |||
stringToSign = strings.Replace(stringToSign, "*", "%2A", -1) | |||
stringToSign = strings.Replace(stringToSign, "%7E", "~", -1) | |||
stringToSign = url.QueryEscape(stringToSign) | |||
stringToSign = request.GetMethod() + "&%2F&" + stringToSign | |||
return | |||
} | |||
func unsignRoaRequest(request *http.Request, signer Signer) (err error) { | |||
signParams := make(map[string]string) | |||
for key, value := range request.URL.Query() { | |||
signParams[key] = value[0] | |||
} | |||
if strings.ToUpper(request.Method) == requests.POST { | |||
for key, value := range request.Form { | |||
signParams[key] = value[0] | |||
} | |||
} | |||
if accessKey, err := signer.GetAccessKeyId(); err != nil { | |||
return err | |||
} else if accessKey == "" { | |||
return errors.New("access key is not allow empty") | |||
} else if accessKey != signParams["access_key"] { | |||
return errors.New("illegal access key") | |||
} | |||
signValue, ok := signParams["sign"] | |||
if !ok { | |||
return errors.New("sign value is not exists") | |||
} else { | |||
delete(signParams, "sign") | |||
} | |||
stringToSign := utils.GetUrlFormedMap(signParams) | |||
stringToSign = strings.Replace(stringToSign, "+", "%20", -1) | |||
stringToSign = strings.Replace(stringToSign, "*", "%2A", -1) | |||
stringToSign = strings.Replace(stringToSign, "%7E", "~", -1) | |||
stringToSign = url.QueryEscape(stringToSign) | |||
stringToSign = request.Method + "&%2F&" + stringToSign | |||
debug("GrSdk sign: %s", stringToSign) | |||
if timestamp, err := strconv.ParseInt(signParams["access_time"], 10, 64); err != nil { | |||
return err | |||
} else { | |||
if time.Unix(timestamp, 0).Before(time.Now().Add(-5 * time.Minute)) { | |||
err = errors.New("sign timeout 5 minute") | |||
} | |||
} | |||
if signer.Sign(stringToSign, "&") != signValue { | |||
return errors.New("sign string is not correct") | |||
} | |||
return | |||
} |
@@ -24,6 +24,8 @@ func NewSignerWithCredential(credential Credential, commonApi func(request *requ | |||
signer = signers.NewAccessKeySigner(instance.ToAccessKeyCredential()) | |||
case *credentials.StdTokenCredential: | |||
signer = signers.NewStsTokenSigner(instance) | |||
case *credentials.AliAppcodeCredential: | |||
signer = signers.NewAliAppcodeSigner(instance) | |||
default: | |||
err = errors.New("UnsupportedCredentialErrorCode = SDK.UnsupportedCredential") | |||
} | |||
@@ -31,8 +33,19 @@ func NewSignerWithCredential(credential Credential, commonApi func(request *requ | |||
} | |||
func Sign(request requests.AcsRequest, signer Signer) (err error) { | |||
switch signer.(type) { | |||
case *signers.AliAppcodeSigner: | |||
err = signRaliRequest(request, signer) | |||
return | |||
} | |||
//TODO 根据rpc和roa两种风格签名,自行选择 | |||
err = signRpcRequest(request, signer) | |||
switch request.GetStyle() { | |||
case requests.RPC: | |||
err = signRpcRequest(request, signer) | |||
case requests.ROA: | |||
err = signRoaRequest(request, signer) | |||
} | |||
return | |||
} | |||
@@ -0,0 +1,43 @@ | |||
package signers | |||
import ( | |||
"crypto/hmac" | |||
"crypto/sha256" | |||
"encoding/base64" | |||
"golib.gaore.com/GaoreGo/gaore-common-sdk-go/sdk/auth/credentials" | |||
) | |||
type AliAppcodeSigner struct { | |||
credential *credentials.AliAppcodeCredential | |||
} | |||
func (signer *AliAppcodeSigner) GetName() string { | |||
return "HmacSHA256" | |||
} | |||
func (signer *AliAppcodeSigner) GetAccessKeyId() (string, error) { | |||
return signer.credential.AccessKeyId, nil | |||
} | |||
func (signer *AliAppcodeSigner) GetAccessKeyFrom() (string, error) { | |||
return "", nil | |||
} | |||
func (signer *AliAppcodeSigner) Sign(stringToSign, secretSuffix string) string { | |||
secret := signer.credential.AccessKeySecret + secretSuffix | |||
return ShaHmac256(stringToSign, secret) | |||
} | |||
func NewAliAppcodeSigner(credential *credentials.AliAppcodeCredential) *AliAppcodeSigner { | |||
return &AliAppcodeSigner{ | |||
credential: credential, | |||
} | |||
} | |||
func ShaHmac256(source, secret string) string { | |||
key := []byte(secret) | |||
hmac1 := hmac.New(sha256.New, key) | |||
hmac1.Write([]byte(source)) | |||
signedString := base64.StdEncoding.EncodeToString(hmac1.Sum(nil)) | |||
return signedString | |||
} |
@@ -93,6 +93,12 @@ func (client *Client) InitWithAccessKey(accessKeyId, accessKeySecret, accessKeyF | |||
return client.InitWithOptions(config, credential) | |||
} | |||
func (client *Client) InitWithAliAppcode(accessKeyId, accessKeySecret string) (err error) { | |||
config := client.InitWithConfig() | |||
credential := credentials.NewAliAppcodeCredential(accessKeyId, accessKeySecret) | |||
return client.InitWithOptions(config, credential) | |||
} | |||
func (client *Client) InitWithStsToken(accessKeyId, accessKeySecret, accessKeyFrom string) (err error) { | |||
config := client.InitWithConfig() | |||
credential := &credentials.StdTokenCredential{ | |||
@@ -26,3 +26,11 @@ func (request *CommonRequest) BuildQueries() string { | |||
func (request *CommonRequest) GetBodyReader() io.Reader { | |||
return request.Ontology.GetBodyReader() | |||
} | |||
func (request *CommonRequest) GetStyle() string { | |||
return request.Ontology.GetStyle() | |||
} | |||
func (request *CommonRequest) InitWithApiInfo(domain, version, urlPath string) { | |||
request.Ontology.InitWithApiInfo(domain, version, urlPath) | |||
} |
@@ -64,7 +64,10 @@ type AcsRequest interface { | |||
GetDomain() string | |||
GetActionName() string | |||
GetAcceptFormat() string | |||
GetAccept() string | |||
GetHeaders() map[string]string | |||
GetStyle() string | |||
InitWithApiInfo(domain, version, urlPath string) | |||
BuildUrl() string | |||
BuildQueries() string | |||
@@ -119,6 +122,16 @@ func (request *baseRequest) GetAcceptFormat() string { | |||
return request.AcceptFormat | |||
} | |||
func (request *baseRequest) GetAccept() string { | |||
switch request.GetAcceptFormat() { | |||
case JSON: | |||
return Json | |||
case XML: | |||
return Xml | |||
} | |||
return "" | |||
} | |||
func (request *baseRequest) GetHeaders() map[string]string { | |||
return request.Headers | |||
} | |||
@@ -24,6 +24,10 @@ func (request *RpcRequest) BuildUrl() string { | |||
return url + request.BuildQueries() | |||
} | |||
func (request *RpcRequest) GetStyle() string { | |||
return RPC | |||
} | |||
func (request *RpcRequest) BuildQueries() string { | |||
path := strings.TrimLeft(strings.TrimSpace(request.GetActionName()), "/") | |||
request.queries = "/" + path + "?" + utils.GetUrlFormedMap(request.QueryParams) | |||
@@ -34,12 +38,11 @@ func (request *RpcRequest) GetActionName() string { | |||
return request.actionName | |||
} | |||
func (request *RpcRequest) InitWithApiInfo(domain, version, urlPath string) *RpcRequest { | |||
func (request *RpcRequest) InitWithApiInfo(domain, version, urlPath string) { | |||
request.init() | |||
request.SetDomain(domain) | |||
request.version = version | |||
request.actionName = urlPath | |||
return request | |||
} | |||
func (request *RpcRequest) GetBodyReader() io.Reader { | |||
@@ -1,14 +1,63 @@ | |||
package utils | |||
import ( | |||
"crypto/md5" | |||
"crypto/rand" | |||
"encoding/hex" | |||
"fmt" | |||
"hash" | |||
rand2 "math/rand" | |||
"net/url" | |||
"reflect" | |||
"sort" | |||
"strconv" | |||
"strings" | |||
"time" | |||
) | |||
type UUID [16]byte | |||
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" | |||
func GetUUID() (uuidHex string) { | |||
uuid := NewUUID() | |||
uuidHex = hex.EncodeToString(uuid[:]) | |||
return | |||
} | |||
func NewUUID() UUID { | |||
ns := UUID{} | |||
safeRandom(ns[:]) | |||
u := newFromHash(md5.New(), ns, RandStringBytes(16)) | |||
u[6] = (u[6] & 0x0f) | (byte(2) << 4) | |||
u[8] = (u[8]&(0xff>>2) | (0x02 << 6)) | |||
return u | |||
} | |||
func RandStringBytes(n int) string { | |||
b := make([]byte, n) | |||
for i := range b { | |||
b[i] = letterBytes[rand2.Intn(len(letterBytes))] | |||
} | |||
return string(b) | |||
} | |||
func newFromHash(h hash.Hash, ns UUID, name string) UUID { | |||
u := UUID{} | |||
h.Write(ns[:]) | |||
h.Write([]byte(name)) | |||
copy(u[:], h.Sum(nil)) | |||
return u | |||
} | |||
func safeRandom(dest []byte) { | |||
if _, err := rand.Read(dest); err != nil { | |||
panic(err) | |||
} | |||
} | |||
func GetUrlFormedMap(source map[string]string) (urlEncoded string) { | |||
urlEncoder := url.Values{} | |||
for key, value := range source { | |||
@@ -18,6 +67,18 @@ func GetUrlFormedMap(source map[string]string) (urlEncoded string) { | |||
return | |||
} | |||
func GetUrlByKeySort(source map[string]string) (url string) { | |||
keys := make([]string, 0, len(source)) | |||
for k := range source { | |||
keys = append(keys, k) | |||
} | |||
sort.Strings(keys) | |||
for _, key := range keys { | |||
url += fmt.Sprintf("%s=%s&", key, source[key]) | |||
} | |||
return strings.TrimRight(url, "&") | |||
} | |||
func InitStructWithDefaultTag(bean interface{}) { | |||
beantype := reflect.TypeOf(bean) | |||
for i := 0; i < beantype.Elem().NumField(); i++ { | |||
@@ -6,7 +6,7 @@ import ( | |||
) | |||
const ( | |||
HOST = "jedi" | |||
HOST = "jedi.oapi.gaore.com" | |||
VERSION = "2020-08-04" | |||
) | |||
@@ -34,3 +34,9 @@ func NewClientWithAccessKey(accesskey, secrect, source string) (client *Client, | |||
err = client.InitWithAccessKey(accesskey, secrect, source) | |||
return | |||
} | |||
func NewClientWithAliAppcode(accesskey, secrect string) (client *Client, err error) { | |||
client = &Client{} | |||
err = client.InitWithAliAppcode(accesskey, secrect) | |||
return | |||
} |
@@ -7,9 +7,9 @@ import ( | |||
type SendSmsRequest struct { | |||
*requests.RpcRequest | |||
User string `position:"Query" field:"user" default:"" ` | |||
Code string `position:"Query" field:"code" default:"" ` | |||
Params string `position:"Query" field:"params" default:"" ` | |||
User string `position:"Body" field:"user" default:"" ` | |||
Code string `position:"Body" field:"code" default:"" ` | |||
Params string `position:"Body" field:"params" default:"" ` | |||
ParamsArray []string | |||
} | |||
@@ -28,7 +28,7 @@ func CreateSendSmsRequest() (req *SendSmsRequest) { | |||
RpcRequest: &requests.RpcRequest{}, | |||
} | |||
req.InitWithApiInfo(HOST, VERSION, "/api/sms/send") | |||
req.Method = requests.GET | |||
req.Method = requests.POST | |||
return | |||
} | |||