oss/lib/util_sts.go (138 lines of code) (raw):

package lib import ( "crypto/hmac" "crypto/sha1" "crypto/tls" "encoding/base64" "encoding/json" "fmt" "io/ioutil" "net/http" "net/url" "strconv" "strings" "time" ) // Client sts client type Client struct { AccessKeyId string AccessKeySecret string RoleArn string SessionName string ExternalId string } // ServiceError sts service error type ServiceError struct { Code string Message string RequestId string HostId string RawMessage string StatusCode int } // Credentials the credentials obtained by AssumedRole, // used for the peration of Alibaba Cloud service. type Credentials struct { AccessKeyId string AccessKeySecret string Expiration time.Time SecurityToken string } // AssumedRoleUser the user to AssumedRole type AssumedRoleUser struct { Arn string AssumedRoleId string } // Response the response of AssumeRole type Response struct { Credentials Credentials AssumedRoleUser AssumedRoleUser RequestId string } // Error implement interface error func (e *ServiceError) Error() string { return fmt.Sprintf("oss: service returned error: StatusCode=%d, ErrorCode=%s, ErrorMessage=%s, RequestId=%s", e.StatusCode, e.Code, e.Message, e.RequestId) } // NewClient New STS Client func NewClient(accessKeyId, accessKeySecret, roleArn, sessionName, externalId string) *Client { return &Client{ AccessKeyId: accessKeyId, AccessKeySecret: accessKeySecret, RoleArn: roleArn, SessionName: sessionName, ExternalId: externalId, } } const ( // StsSignVersion sts sign version StsSignVersion = "1.0" // StsAPIVersion sts api version StsAPIVersion = "2015-04-01" // // StsHost sts host // StsHost = "https://sts.aliyuncs.com/" // TimeFormat time fomrat TimeFormat = "2006-01-02T15:04:05Z" // RespBodyFormat respone body format RespBodyFormat = "JSON" // PercentEncode '/' PercentEncode = "%2F" // HTTPGet http get method HTTPGet = "GET" ) // StsHost sts host var StsHost = "https://sts.aliyuncs.com/" // AssumeRole assume role func (c *Client) AssumeRole(tokenTimeout uint, stsEndPoint string) (*Response, error) { if stsEndPoint != "" { StsHost = stsEndPoint } url, err := c.generateSignedURL(tokenTimeout) if err != nil { return nil, err } body, status, err := c.sendRequest(url) if err != nil { return nil, err } return c.handleResponse(body, status) } // Private function func (c *Client) generateSignedURL(expiredTime uint) (string, error) { randId := strings.ToUpper(randStr(24)) queryStr := "SignatureVersion=" + StsSignVersion queryStr += "&Format=" + RespBodyFormat queryStr += "&Timestamp=" + url.QueryEscape(time.Now().UTC().Format(TimeFormat)) queryStr += "&RoleArn=" + url.QueryEscape(c.RoleArn) queryStr += "&RoleSessionName=" + c.SessionName queryStr += "&AccessKeyId=" + c.AccessKeyId queryStr += "&SignatureMethod=HMAC-SHA1" queryStr += "&Version=" + StsAPIVersion queryStr += "&Action=AssumeRole" queryStr += "&SignatureNonce=" + randId queryStr += "&DurationSeconds=" + strconv.FormatUint((uint64)(expiredTime), 10) if c.ExternalId != "" { queryStr += "&ExternalId=" + c.ExternalId } // Sort query string queryParams, err := url.ParseQuery(queryStr) if err != nil { return "", err } result := queryParams.Encode() strToSign := HTTPGet + "&" + PercentEncode + "&" + url.QueryEscape(result) // Generate signature hashSign := hmac.New(sha1.New, []byte(c.AccessKeySecret+"&")) hashSign.Write([]byte(strToSign)) signature := base64.StdEncoding.EncodeToString(hashSign.Sum(nil)) // Build url assumeURL := StsHost + "?" + queryStr + "&Signature=" + url.QueryEscape(signature) return assumeURL, nil } func (c *Client) sendRequest(url string) ([]byte, int, error) { tr := &http.Transport{ TLSClientConfig: &tls.Config{}, } client := &http.Client{Transport: tr} resp, err := client.Get(url) if err != nil { return nil, -1, err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) return body, resp.StatusCode, err } func (c *Client) handleResponse(responseBody []byte, statusCode int) (*Response, error) { if statusCode != http.StatusOK { se := ServiceError{StatusCode: statusCode, RawMessage: string(responseBody)} err := json.Unmarshal(responseBody, &se) if err != nil { return nil, err } return nil, &se } resp := Response{} err := json.Unmarshal(responseBody, &resp) if err != nil { return nil, err } return &resp, nil }