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 }