github.com/aliyun/credentials-go@v1.4.7/credentials/providers/ecs_ram_role_test.go (about)

     1  package providers
     2  
     3  import (
     4  	"errors"
     5  	"os"
     6  	"testing"
     7  	"time"
     8  
     9  	httputil "github.com/aliyun/credentials-go/credentials/internal/http"
    10  	"github.com/aliyun/credentials-go/credentials/internal/utils"
    11  	"github.com/stretchr/testify/assert"
    12  )
    13  
    14  func TestNewECSRAMRoleCredentialsProvider(t *testing.T) {
    15  	rollback := utils.Memory("ALIBABA_CLOUD_ECS_METADATA_DISABLED", "ALIBABA_CLOUD_ECS_METADATA", "ALIBABA_CLOUD_IMDSV1_DISABLED")
    16  	defer func() {
    17  		rollback()
    18  	}()
    19  	p, err := NewECSRAMRoleCredentialsProviderBuilder().Build()
    20  	assert.Nil(t, err)
    21  	assert.Equal(t, "", p.roleName)
    22  
    23  	os.Setenv("ALIBABA_CLOUD_ECS_METADATA", "rolename")
    24  	p, err = NewECSRAMRoleCredentialsProviderBuilder().Build()
    25  	assert.Nil(t, err)
    26  	assert.Equal(t, "rolename", p.roleName)
    27  
    28  	p, err = NewECSRAMRoleCredentialsProviderBuilder().WithRoleName("role").Build()
    29  	assert.Nil(t, err)
    30  	assert.Equal(t, "role", p.roleName)
    31  	assert.False(t, p.disableIMDSv1)
    32  
    33  	os.Setenv("ALIBABA_CLOUD_IMDSV1_DISABLED", "True")
    34  	p, err = NewECSRAMRoleCredentialsProviderBuilder().Build()
    35  	assert.Nil(t, err)
    36  	assert.True(t, p.disableIMDSv1)
    37  
    38  	os.Setenv("ALIBABA_CLOUD_IMDSV1_DISABLED", "1")
    39  	p, err = NewECSRAMRoleCredentialsProviderBuilder().WithDisableIMDSv1(true).Build()
    40  	assert.Nil(t, err)
    41  	assert.True(t, p.disableIMDSv1)
    42  
    43  	os.Setenv("ALIBABA_CLOUD_ECS_METADATA_DISABLED", "True")
    44  	_, err = NewECSRAMRoleCredentialsProviderBuilder().Build()
    45  	assert.Equal(t, "IMDS credentials is disabled", err.Error())
    46  
    47  	assert.True(t, p.needUpdateCredential())
    48  }
    49  
    50  func TestECSRAMRoleCredentialsProvider_getRoleName(t *testing.T) {
    51  	originHttpDo := httpDo
    52  	defer func() { httpDo = originHttpDo }()
    53  
    54  	p, err := NewECSRAMRoleCredentialsProviderBuilder().Build()
    55  	assert.Nil(t, err)
    56  
    57  	// case 1: server error
    58  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
    59  		err = errors.New("mock server error")
    60  		return
    61  	}
    62  
    63  	_, err = p.getRoleName()
    64  	assert.NotNil(t, err)
    65  	assert.Equal(t, "get role name failed: mock server error", err.Error())
    66  
    67  	// case 2: 4xx error
    68  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
    69  		res = &httputil.Response{
    70  			StatusCode: 400,
    71  			Body:       []byte("4xx error"),
    72  		}
    73  		return
    74  	}
    75  
    76  	_, err = p.getRoleName()
    77  	assert.NotNil(t, err)
    78  	assert.Equal(t, "get role name failed: GET http://100.100.100.200/latest/meta-data/ram/security-credentials/ 400", err.Error())
    79  
    80  	// case 3: ok
    81  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
    82  		res = &httputil.Response{
    83  			StatusCode: 200,
    84  			Body:       []byte("rolename"),
    85  		}
    86  		return
    87  	}
    88  	roleName, err := p.getRoleName()
    89  	assert.Nil(t, err)
    90  	assert.Equal(t, "rolename", roleName)
    91  }
    92  
    93  func TestECSRAMRoleCredentialsProvider_getRoleNameWithMetadataV2(t *testing.T) {
    94  	originHttpDo := httpDo
    95  	defer func() { httpDo = originHttpDo }()
    96  
    97  	p, err := NewECSRAMRoleCredentialsProviderBuilder().WithDisableIMDSv1(true).Build()
    98  	assert.Nil(t, err)
    99  
   100  	// case 1: get metadata token failed
   101  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   102  		err = errors.New("mock server error")
   103  		return
   104  	}
   105  
   106  	_, err = p.getRoleName()
   107  	assert.NotNil(t, err)
   108  	assert.Equal(t, "get metadata token failed: mock server error", err.Error())
   109  
   110  	// case 2: return token
   111  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   112  		if req.Path == "/latest/api/token" {
   113  			res = &httputil.Response{
   114  				StatusCode: 200,
   115  				Body:       []byte("tokenxxxxx"),
   116  			}
   117  		} else {
   118  			assert.Equal(t, "tokenxxxxx", req.Headers["x-aliyun-ecs-metadata-token"])
   119  
   120  			res = &httputil.Response{
   121  				StatusCode: 200,
   122  				Body:       []byte("rolename"),
   123  			}
   124  		}
   125  		return
   126  	}
   127  
   128  	roleName, err := p.getRoleName()
   129  	assert.Nil(t, err)
   130  	assert.Equal(t, "rolename", roleName)
   131  }
   132  
   133  func TestECSRAMRoleCredentialsProvider_getCredentials(t *testing.T) {
   134  	originHttpDo := httpDo
   135  	defer func() { httpDo = originHttpDo }()
   136  
   137  	p, err := NewECSRAMRoleCredentialsProviderBuilder().Build()
   138  	assert.Nil(t, err)
   139  
   140  	// case 1: server error
   141  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   142  		err = errors.New("mock server error")
   143  		return
   144  	}
   145  	_, err = p.getCredentials()
   146  	assert.NotNil(t, err)
   147  	assert.Equal(t, "get role name failed: mock server error", err.Error())
   148  
   149  	// case 2: get role name ok, get credentials failed with server error
   150  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   151  		if req.Path == "/latest/meta-data/ram/security-credentials/" {
   152  			res = &httputil.Response{
   153  				StatusCode: 200,
   154  				Body:       []byte("rolename"),
   155  			}
   156  			return
   157  		}
   158  		err = errors.New("mock server error")
   159  		return
   160  	}
   161  
   162  	_, err = p.getCredentials()
   163  	assert.NotNil(t, err)
   164  	assert.Equal(t, "refresh Ecs sts token err: mock server error", err.Error())
   165  
   166  	// case 3: 4xx error
   167  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   168  		if req.Path == "/latest/meta-data/ram/security-credentials/" {
   169  			res = &httputil.Response{
   170  				StatusCode: 200,
   171  				Body:       []byte("rolename"),
   172  			}
   173  			return
   174  		}
   175  
   176  		res = &httputil.Response{
   177  			StatusCode: 400,
   178  			Body:       []byte("4xx error"),
   179  		}
   180  		return
   181  	}
   182  
   183  	_, err = p.getCredentials()
   184  	assert.NotNil(t, err)
   185  	assert.Equal(t, "refresh Ecs sts token err, httpStatus: 400, message = 4xx error", err.Error())
   186  
   187  	// case 4: invalid json
   188  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   189  		if req.Path == "/latest/meta-data/ram/security-credentials/" {
   190  			res = &httputil.Response{
   191  				StatusCode: 200,
   192  				Body:       []byte("rolename"),
   193  			}
   194  			return
   195  		}
   196  
   197  		res = &httputil.Response{
   198  			StatusCode: 200,
   199  			Body:       []byte("invalid json"),
   200  		}
   201  		return
   202  	}
   203  
   204  	_, err = p.getCredentials()
   205  	assert.NotNil(t, err)
   206  	assert.Equal(t, "refresh Ecs sts token err, json.Unmarshal fail: invalid character 'i' looking for beginning of value", err.Error())
   207  
   208  	// case 5: empty response json
   209  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   210  		if req.Path == "/latest/meta-data/ram/security-credentials/" {
   211  			res = &httputil.Response{
   212  				StatusCode: 200,
   213  				Body:       []byte("rolename"),
   214  			}
   215  			return
   216  		}
   217  
   218  		res = &httputil.Response{
   219  			StatusCode: 200,
   220  			Body:       []byte("null"),
   221  		}
   222  		return
   223  	}
   224  
   225  	_, err = p.getCredentials()
   226  	assert.NotNil(t, err)
   227  	assert.Equal(t, "refresh Ecs sts token err, fail to get credentials", err.Error())
   228  
   229  	// case 6: empty session ak response json
   230  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   231  		if req.Path == "/latest/meta-data/ram/security-credentials/" {
   232  			res = &httputil.Response{
   233  				StatusCode: 200,
   234  				Body:       []byte("rolename"),
   235  			}
   236  			return
   237  		}
   238  
   239  		res = &httputil.Response{
   240  			StatusCode: 200,
   241  			Body:       []byte("{}"),
   242  		}
   243  		return
   244  	}
   245  	_, err = p.getCredentials()
   246  	assert.NotNil(t, err)
   247  	assert.Equal(t, "refresh Ecs sts token err, fail to get credentials", err.Error())
   248  
   249  	// case 7: non-success response
   250  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   251  		if req.Path == "/latest/meta-data/ram/security-credentials/" {
   252  			res = &httputil.Response{
   253  				StatusCode: 200,
   254  				Body:       []byte("rolename"),
   255  			}
   256  			return
   257  		}
   258  
   259  		res = &httputil.Response{
   260  			StatusCode: 200,
   261  			Body:       []byte(`{"AccessKeyId":"saki","AccessKeySecret":"saks","Expiration":"2021-10-20T04:27:09Z","SecurityToken":"token","Code":"Failed"}`),
   262  		}
   263  		return
   264  	}
   265  	_, err = p.getCredentials()
   266  	assert.NotNil(t, err)
   267  	assert.Equal(t, "refresh Ecs sts token err, Code is not Success", err.Error())
   268  
   269  	// case 8: mock ok value
   270  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   271  		if req.Path == "/latest/meta-data/ram/security-credentials/" {
   272  			res = &httputil.Response{
   273  				StatusCode: 200,
   274  				Body:       []byte("rolename"),
   275  			}
   276  			return
   277  		}
   278  
   279  		res = &httputil.Response{
   280  			StatusCode: 200,
   281  			Body:       []byte(`{"AccessKeyId":"saki","AccessKeySecret":"saks","Expiration":"2021-10-20T04:27:09Z","SecurityToken":"token","Code":"Success"}`),
   282  		}
   283  		return
   284  	}
   285  	creds, err := p.getCredentials()
   286  	assert.Nil(t, err)
   287  	assert.Equal(t, "saki", creds.AccessKeyId)
   288  	assert.Equal(t, "saks", creds.AccessKeySecret)
   289  	assert.Equal(t, "token", creds.SecurityToken)
   290  	assert.Equal(t, "2021-10-20T04:27:09Z", creds.Expiration)
   291  
   292  	// needUpdateCredential
   293  	assert.True(t, p.needUpdateCredential())
   294  	p.expirationTimestamp = time.Now().Unix()
   295  	assert.True(t, p.needUpdateCredential())
   296  
   297  	p.expirationTimestamp = time.Now().Unix() + 300
   298  	assert.False(t, p.needUpdateCredential())
   299  }
   300  
   301  func TestECSRAMRoleCredentialsProvider_getCredentialsWithMetadataV2(t *testing.T) {
   302  	originHttpDo := httpDo
   303  	defer func() { httpDo = originHttpDo }()
   304  
   305  	p, err := NewECSRAMRoleCredentialsProviderBuilder().WithDisableIMDSv1(true).WithRoleName("rolename").Build()
   306  	assert.Nil(t, err)
   307  
   308  	// case 1: get metadata token failed
   309  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   310  		err = errors.New("mock server error")
   311  		return
   312  	}
   313  
   314  	_, err = p.getCredentials()
   315  	assert.NotNil(t, err)
   316  	assert.Equal(t, "get metadata token failed: mock server error", err.Error())
   317  
   318  	// case 2: return token
   319  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   320  		if req.Path == "/latest/api/token" {
   321  			res = &httputil.Response{
   322  				StatusCode: 200,
   323  				Body:       []byte("tokenxxxxx"),
   324  			}
   325  		} else if req.Path == "/latest/meta-data/ram/security-credentials/rolename" {
   326  			assert.Equal(t, "tokenxxxxx", req.Headers["x-aliyun-ecs-metadata-token"])
   327  			res = &httputil.Response{
   328  				StatusCode: 200,
   329  				Body:       []byte(`{"AccessKeyId":"saki","AccessKeySecret":"saks","Expiration":"2021-10-20T04:27:09Z","SecurityToken":"token","Code":"Success"}`),
   330  			}
   331  		}
   332  		return
   333  	}
   334  
   335  	creds, err := p.getCredentials()
   336  	assert.Nil(t, err)
   337  	assert.Equal(t, "saki", creds.AccessKeyId)
   338  	assert.Equal(t, "saks", creds.AccessKeySecret)
   339  	assert.Equal(t, "token", creds.SecurityToken)
   340  	assert.Equal(t, "2021-10-20T04:27:09Z", creds.Expiration)
   341  
   342  	// needUpdateCredential
   343  	assert.True(t, p.needUpdateCredential())
   344  	p.expirationTimestamp = time.Now().Unix()
   345  	assert.True(t, p.needUpdateCredential())
   346  
   347  	p.expirationTimestamp = time.Now().Unix() + 300
   348  	assert.False(t, p.needUpdateCredential())
   349  }
   350  
   351  func TestECSRAMRoleCredentialsProviderGetCredentials(t *testing.T) {
   352  	originHttpDo := httpDo
   353  	defer func() { httpDo = originHttpDo }()
   354  
   355  	p, err := NewECSRAMRoleCredentialsProviderBuilder().WithRoleName("rolename").Build()
   356  	assert.Nil(t, err)
   357  	// case 1: get credentials failed
   358  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   359  		err = errors.New("mock server error")
   360  		return
   361  	}
   362  	_, err = p.GetCredentials()
   363  	assert.NotNil(t, err)
   364  	assert.Equal(t, "refresh Ecs sts token err: mock server error", err.Error())
   365  
   366  	// case 2: get invalid expiration
   367  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   368  		res = &httputil.Response{
   369  			StatusCode: 200,
   370  			Body:       []byte(`{"AccessKeyId":"saki","AccessKeySecret":"saks","Expiration":"invalidexpiration","SecurityToken":"token","Code":"Success"}`),
   371  		}
   372  		return
   373  	}
   374  	_, err = p.GetCredentials()
   375  	assert.NotNil(t, err)
   376  	assert.Equal(t, "parsing time \"invalidexpiration\" as \"2006-01-02T15:04:05Z\": cannot parse \"invalidexpiration\" as \"2006\"", err.Error())
   377  
   378  	// case 3: happy result
   379  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   380  		res = &httputil.Response{
   381  			StatusCode: 200,
   382  			Body:       []byte(`{"AccessKeyId":"akid","AccessKeySecret":"aksecret","Expiration":"2021-10-20T04:27:09Z","SecurityToken":"token","Code":"Success"}`),
   383  		}
   384  		return
   385  	}
   386  	cc, err := p.GetCredentials()
   387  	assert.Nil(t, err)
   388  	assert.Equal(t, "akid", cc.AccessKeyId)
   389  	assert.Equal(t, "aksecret", cc.AccessKeySecret)
   390  	assert.Equal(t, "token", cc.SecurityToken)
   391  	assert.True(t, p.needUpdateCredential())
   392  }
   393  
   394  func TestECSRAMRoleCredentialsProvider_getMetadataToken(t *testing.T) {
   395  	rollback := utils.Memory("ALIBABA_CLOUD_IMDSV1_DISABLED")
   396  	defer func() {
   397  		rollback()
   398  	}()
   399  
   400  	originHttpDo := httpDo
   401  	defer func() { httpDo = originHttpDo }()
   402  
   403  	p, err := NewECSRAMRoleCredentialsProviderBuilder().Build()
   404  	assert.Nil(t, err)
   405  
   406  	// case 1: server error
   407  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   408  		err = errors.New("mock server error")
   409  		return
   410  	}
   411  
   412  	_, err = p.getMetadataToken()
   413  	assert.Nil(t, err)
   414  
   415  	p, err = NewECSRAMRoleCredentialsProviderBuilder().WithDisableIMDSv1(false).Build()
   416  	assert.Nil(t, err)
   417  
   418  	_, err = p.getMetadataToken()
   419  	assert.Nil(t, err)
   420  
   421  	os.Setenv("ALIBABA_CLOUD_IMDSV1_DISABLED", "true")
   422  	p, err = NewECSRAMRoleCredentialsProviderBuilder().Build()
   423  	assert.Nil(t, err)
   424  
   425  	_, err = p.getMetadataToken()
   426  	assert.NotNil(t, err)
   427  
   428  	os.Setenv("ALIBABA_CLOUD_IMDSV1_DISABLED", "")
   429  	p, err = NewECSRAMRoleCredentialsProviderBuilder().Build()
   430  	assert.Nil(t, err)
   431  
   432  	_, err = p.getMetadataToken()
   433  	assert.Nil(t, err)
   434  
   435  	p, err = NewECSRAMRoleCredentialsProviderBuilder().WithDisableIMDSv1(true).Build()
   436  	assert.Nil(t, err)
   437  
   438  	_, err = p.getMetadataToken()
   439  	assert.NotNil(t, err)
   440  
   441  	assert.Equal(t, "get metadata token failed: mock server error", err.Error())
   442  
   443  	// case 2: return token
   444  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   445  		res = &httputil.Response{
   446  			StatusCode: 200,
   447  			Body:       []byte("tokenxxxxx"),
   448  		}
   449  		return
   450  	}
   451  	metadataToken, err := p.getMetadataToken()
   452  	assert.Nil(t, err)
   453  	assert.Equal(t, "tokenxxxxx", metadataToken)
   454  
   455  	// case 3: return 404
   456  	p, err = NewECSRAMRoleCredentialsProviderBuilder().WithDisableIMDSv1(false).Build()
   457  	assert.Nil(t, err)
   458  
   459  	httpDo = func(req *httputil.Request) (res *httputil.Response, err error) {
   460  		res = &httputil.Response{
   461  			StatusCode: 404,
   462  			Body:       []byte("not found"),
   463  		}
   464  		return
   465  	}
   466  	metadataToken, err = p.getMetadataToken()
   467  	assert.Nil(t, err)
   468  	assert.Equal(t, "", metadataToken)
   469  
   470  	p, err = NewECSRAMRoleCredentialsProviderBuilder().WithDisableIMDSv1(true).Build()
   471  	assert.Nil(t, err)
   472  
   473  	metadataToken, err = p.getMetadataToken()
   474  	assert.NotNil(t, err)
   475  	assert.Equal(t, "", metadataToken)
   476  }
   477  
   478  func TestNewECSRAMRoleCredentialsProviderWithHttpOptions(t *testing.T) {
   479  	p, err := NewECSRAMRoleCredentialsProviderBuilder().
   480  		WithRoleName("test").
   481  		WithHttpOptions(&HttpOptions{
   482  			ConnectTimeout: 1000,
   483  			ReadTimeout:    1000,
   484  			Proxy:          "localhost:3999",
   485  		}).
   486  		Build()
   487  	assert.Nil(t, err)
   488  
   489  	_, err = p.getRoleName()
   490  	assert.NotNil(t, err)
   491  	assert.Contains(t, err.Error(), "proxyconnect tcp:")
   492  
   493  	_, err = p.getCredentials()
   494  	assert.NotNil(t, err)
   495  	assert.Contains(t, err.Error(), "proxyconnect tcp:")
   496  
   497  	_, err = p.GetCredentials()
   498  	assert.NotNil(t, err)
   499  	assert.Contains(t, err.Error(), "proxyconnect tcp:")
   500  }