uri.go raw

   1  package providers
   2  
   3  import (
   4  	"encoding/json"
   5  	"errors"
   6  	"fmt"
   7  	"net/http"
   8  	"os"
   9  	"time"
  10  
  11  	httputil "github.com/aliyun/credentials-go/credentials/internal/http"
  12  )
  13  
  14  type URLCredentialsProvider struct {
  15  	url string
  16  	// for sts
  17  	sessionCredentials *sessionCredentials
  18  	// for http options
  19  	httpOptions *HttpOptions
  20  	// inner
  21  	expirationTimestamp int64
  22  }
  23  
  24  type URLCredentialsProviderBuilder struct {
  25  	provider *URLCredentialsProvider
  26  }
  27  
  28  func NewURLCredentialsProviderBuilder() *URLCredentialsProviderBuilder {
  29  	return &URLCredentialsProviderBuilder{
  30  		provider: &URLCredentialsProvider{},
  31  	}
  32  }
  33  
  34  func (builder *URLCredentialsProviderBuilder) WithUrl(url string) *URLCredentialsProviderBuilder {
  35  	builder.provider.url = url
  36  	return builder
  37  }
  38  
  39  func (builder *URLCredentialsProviderBuilder) WithHttpOptions(httpOptions *HttpOptions) *URLCredentialsProviderBuilder {
  40  	builder.provider.httpOptions = httpOptions
  41  	return builder
  42  }
  43  
  44  func (builder *URLCredentialsProviderBuilder) Build() (provider *URLCredentialsProvider, err error) {
  45  
  46  	if builder.provider.url == "" {
  47  		builder.provider.url = os.Getenv("ALIBABA_CLOUD_CREDENTIALS_URI")
  48  	}
  49  
  50  	if builder.provider.url == "" {
  51  		err = errors.New("the url is empty")
  52  		return
  53  	}
  54  
  55  	provider = builder.provider
  56  	return
  57  }
  58  
  59  type urlResponse struct {
  60  	AccessKeyId     *string `json:"AccessKeyId"`
  61  	AccessKeySecret *string `json:"AccessKeySecret"`
  62  	SecurityToken   *string `json:"SecurityToken"`
  63  	Expiration      *string `json:"Expiration"`
  64  }
  65  
  66  func (provider *URLCredentialsProvider) getCredentials() (session *sessionCredentials, err error) {
  67  	req := &httputil.Request{
  68  		Method: "GET",
  69  		URL:    provider.url,
  70  	}
  71  
  72  	connectTimeout := 5 * time.Second
  73  	readTimeout := 10 * time.Second
  74  
  75  	if provider.httpOptions != nil && provider.httpOptions.ConnectTimeout > 0 {
  76  		connectTimeout = time.Duration(provider.httpOptions.ConnectTimeout) * time.Millisecond
  77  	}
  78  	if provider.httpOptions != nil && provider.httpOptions.ReadTimeout > 0 {
  79  		readTimeout = time.Duration(provider.httpOptions.ReadTimeout) * time.Millisecond
  80  	}
  81  	if provider.httpOptions != nil && provider.httpOptions.Proxy != "" {
  82  		req.Proxy = provider.httpOptions.Proxy
  83  	}
  84  	req.ConnectTimeout = connectTimeout
  85  	req.ReadTimeout = readTimeout
  86  
  87  	res, err := httpDo(req)
  88  	if err != nil {
  89  		return
  90  	}
  91  
  92  	if res.StatusCode != http.StatusOK {
  93  		err = fmt.Errorf("get credentials from %s failed: %s", req.BuildRequestURL(), string(res.Body))
  94  		return
  95  	}
  96  
  97  	var resp urlResponse
  98  	err = json.Unmarshal(res.Body, &resp)
  99  	if err != nil {
 100  		err = fmt.Errorf("get credentials from %s failed with error, json unmarshal fail: %s", req.BuildRequestURL(), err.Error())
 101  		return
 102  	}
 103  
 104  	if resp.AccessKeyId == nil || resp.AccessKeySecret == nil || resp.SecurityToken == nil || resp.Expiration == nil {
 105  		err = fmt.Errorf("refresh credentials from %s failed: %s", req.BuildRequestURL(), string(res.Body))
 106  		return
 107  	}
 108  
 109  	session = &sessionCredentials{
 110  		AccessKeyId:     *resp.AccessKeyId,
 111  		AccessKeySecret: *resp.AccessKeySecret,
 112  		SecurityToken:   *resp.SecurityToken,
 113  		Expiration:      *resp.Expiration,
 114  	}
 115  	return
 116  }
 117  
 118  func (provider *URLCredentialsProvider) needUpdateCredential() (result bool) {
 119  	if provider.expirationTimestamp == 0 {
 120  		return true
 121  	}
 122  
 123  	return provider.expirationTimestamp-time.Now().Unix() <= 180
 124  }
 125  
 126  func (provider *URLCredentialsProvider) GetCredentials() (cc *Credentials, err error) {
 127  	if provider.sessionCredentials == nil || provider.needUpdateCredential() {
 128  		sessionCredentials, err1 := provider.getCredentials()
 129  		if err1 != nil {
 130  			return nil, err1
 131  		}
 132  
 133  		provider.sessionCredentials = sessionCredentials
 134  		expirationTime, err2 := time.Parse("2006-01-02T15:04:05Z", sessionCredentials.Expiration)
 135  		if err2 != nil {
 136  			return nil, err2
 137  		}
 138  		provider.expirationTimestamp = expirationTime.Unix()
 139  	}
 140  
 141  	cc = &Credentials{
 142  		AccessKeyId:     provider.sessionCredentials.AccessKeyId,
 143  		AccessKeySecret: provider.sessionCredentials.AccessKeySecret,
 144  		SecurityToken:   provider.sessionCredentials.SecurityToken,
 145  		ProviderName:    provider.GetProviderName(),
 146  	}
 147  	return
 148  }
 149  
 150  func (provider *URLCredentialsProvider) GetProviderName() string {
 151  	return "credential_uri"
 152  }
 153