package responses import ( "encoding/xml" "testing" "github.com/stretchr/testify/require" ) func TestParseArn(t *testing.T) { cases := map[string]struct { arn string expArn *ParsedArn }{ "assumed-role": { arn: "arn:aws:sts::000000000000:assumed-role/my-role/session-name", expArn: &ParsedArn{ Partition: "aws", AccountNumber: "000000000000", Type: "assumed-role", Path: "", FriendlyName: "my-role", SessionInfo: "session-name", }, }, "role": { arn: "arn:aws:iam::000000000000:role/my-role", expArn: &ParsedArn{ Partition: "aws", AccountNumber: "000000000000", Type: "role", Path: "", FriendlyName: "my-role", SessionInfo: "", }, }, "user": { arn: "arn:aws:iam::000000000000:user/my-user", expArn: &ParsedArn{ Partition: "aws", AccountNumber: "000000000000", Type: "user", Path: "", FriendlyName: "my-user", SessionInfo: "", }, }, "role with path": { arn: "arn:aws:iam::000000000000:role/path/my-role", expArn: &ParsedArn{ Partition: "aws", AccountNumber: "000000000000", Type: "role", Path: "path", FriendlyName: "my-role", SessionInfo: "", }, }, "role with path 2": { arn: "arn:aws:iam::000000000000:role/path/to/my-role", expArn: &ParsedArn{ Partition: "aws", AccountNumber: "000000000000", Type: "role", Path: "path/to", FriendlyName: "my-role", SessionInfo: "", }, }, "role with path 3": { arn: "arn:aws:iam::000000000000:role/some/path/to/my-role", expArn: &ParsedArn{ Partition: "aws", AccountNumber: "000000000000", Type: "role", Path: "some/path/to", FriendlyName: "my-role", SessionInfo: "", }, }, "user with path": { arn: "arn:aws:iam::000000000000:user/path/my-user", expArn: &ParsedArn{ Partition: "aws", AccountNumber: "000000000000", Type: "user", Path: "path", FriendlyName: "my-user", SessionInfo: "", }, }, // Invalid cases "empty string": {arn: ""}, "wildcard": {arn: "*"}, "missing prefix": {arn: ":aws:sts::000000000000:assumed-role/my-role/session-name"}, "missing partition": {arn: "arn::sts::000000000000:assumed-role/my-role/session-name"}, "missing service": {arn: "arn:aws:::000000000000:assumed-role/my-role/session-name"}, "missing separator": {arn: "arn:aws:sts:000000000000:assumed-role/my-role/session-name"}, "missing account id": {arn: "arn:aws:sts:::assumed-role/my-role/session-name"}, "missing resource": {arn: "arn:aws:sts::000000000000:"}, "assumed-role missing parts": {arn: "arn:aws:sts::000000000000:assumed-role/my-role"}, "role missing parts": {arn: "arn:aws:sts::000000000000:role"}, "role missing parts 2": {arn: "arn:aws:sts::000000000000:role/"}, "user missing parts": {arn: "arn:aws:sts::000000000000:user"}, "user missing parts 2": {arn: "arn:aws:sts::000000000000:user/"}, "unsupported service": {arn: "arn:aws:ecs:us-east-1:000000000000:task/my-task/00000000000000000000000000000000"}, } for name, c := range cases { t.Run(name, func(t *testing.T) { parsed, err := ParseArn(c.arn) if c.expArn != nil { require.NoError(t, err) require.Equal(t, c.expArn, parsed) } else { require.Error(t, err) require.Nil(t, parsed) } }) } } func TestCanonicalArn(t *testing.T) { cases := map[string]struct { arn string expArn string }{ "assumed-role arn": { arn: "arn:aws:sts::000000000000:assumed-role/my-role/session-name", expArn: "arn:aws:iam::000000000000:role/my-role", }, "role arn": { arn: "arn:aws:iam::000000000000:role/my-role", expArn: "arn:aws:iam::000000000000:role/my-role", }, "role arn with path": { arn: "arn:aws:iam::000000000000:role/path/to/my-role", expArn: "arn:aws:iam::000000000000:role/my-role", }, "user arn": { arn: "arn:aws:iam::000000000000:user/my-user", expArn: "arn:aws:iam::000000000000:user/my-user", }, "user arn with path": { arn: "arn:aws:iam::000000000000:user/path/to/my-user", expArn: "arn:aws:iam::000000000000:user/my-user", }, } for name, c := range cases { t.Run(name, func(t *testing.T) { parsed, err := ParseArn(c.arn) require.NoError(t, err) require.Equal(t, c.expArn, parsed.CanonicalArn()) }) } } func TestUnmarshalXML(t *testing.T) { t.Run("user xml", func(t *testing.T) { var resp GetUserResponse err := xml.Unmarshal([]byte(rawUserXML), &resp) require.NoError(t, err) require.Equal(t, expectedParsedUserXML, resp) }) t.Run("role xml", func(t *testing.T) { var resp GetRoleResponse err := xml.Unmarshal([]byte(rawRoleXML), &resp) require.NoError(t, err) require.Equal(t, expectedParsedRoleXML, resp) }) } var ( rawUserXML = ` / arn:aws:iam::000000000000:user/my-user my-user AIDAexampleuserid 2021-01-01T00:01:02Z some-value some-tag another-value another-tag third-value third-tag 11815b96-cb16-4d33-b2cf-0042fa4db4cd ` expectedParsedUserXML = GetUserResponse{ XMLName: xml.Name{ Space: "https://iam.amazonaws.com/doc/2010-05-08/", Local: "GetUserResponse", }, GetUserResult: []GetUserResult{ { User: User{ Arn: "arn:aws:iam::000000000000:user/my-user", Path: "/", UserId: "AIDAexampleuserid", UserName: "my-user", Tags: Tags{ Members: []TagMember{ {Key: "some-tag", Value: "some-value"}, {Key: "another-tag", Value: "another-value"}, {Key: "third-tag", Value: "third-value"}, }, }, }, }, }, ResponseMetadata: []ResponseMetadata{ {RequestId: "11815b96-cb16-4d33-b2cf-0042fa4db4cd"}, }, } rawRoleXML = ` / some-json-document-that-we-ignore 43200 AROAsomeuniqueid 2022-01-01T01:02:03Z us-east-1 my-role arn:aws:iam::000000000000:role/my-role 2020-01-01T00:00:01Z some-value some-key another-value another-key a-third-value third-key a9866067-c0e5-4b5e-86ba-429c1151e2fb ` expectedParsedRoleXML = GetRoleResponse{ XMLName: xml.Name{ Space: "https://iam.amazonaws.com/doc/2010-05-08/", Local: "GetRoleResponse", }, GetRoleResult: []GetRoleResult{ { Role: Role{ Arn: "arn:aws:iam::000000000000:role/my-role", Path: "/", RoleId: "AROAsomeuniqueid", RoleName: "my-role", Tags: Tags{ Members: []TagMember{ {Key: "some-key", Value: "some-value"}, {Key: "another-key", Value: "another-value"}, {Key: "third-key", Value: "a-third-value"}, }, }, }, }, }, ResponseMetadata: []ResponseMetadata{ {RequestId: "a9866067-c0e5-4b5e-86ba-429c1151e2fb"}, }, } )