S3ARN.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. /**
  2. * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
  3. * SPDX-License-Identifier: Apache-2.0.
  4. */
  5. #include <cassert>
  6. #include <aws/core/Region.h>
  7. #include <aws/core/utils/DNS.h>
  8. #include <aws/core/utils/Outcome.h>
  9. #include <aws/core/utils/StringUtils.h>
  10. #include <aws/s3/S3ARN.h>
  11. namespace Aws
  12. {
  13. namespace S3
  14. {
  15. S3ARN::S3ARN(const Aws::String& arn) : Utils::ARN(arn)
  16. {
  17. ParseARNResource();
  18. }
  19. S3ARNOutcome S3ARN::Validate(const char* clientRegion) const
  20. {
  21. // Take pseudo region into consideration here.
  22. Aws::String region = clientRegion ? clientRegion : "";
  23. Aws::StringStream ss;
  24. if (this->GetResourceType() == ARNResourceType::OUTPOST && region.find("fips") != Aws::String::npos)
  25. {
  26. ss.str("");
  27. ss << "Outposts ARN do not support fips regions right now.";
  28. return S3ARNOutcome(Aws::Client::AWSError<S3Errors>(S3Errors::VALIDATION, "VALIDATION", ss.str(), false));
  29. }
  30. else if (this->GetRegion() != Aws::Region::ComputeSignerRegion(clientRegion))
  31. {
  32. ss.str("");
  33. ss << "Region mismatch between \"" << this->GetRegion() << "\" defined in ARN and \""
  34. << clientRegion << "\" defined in client configuration. "
  35. << "You can specify AWS_S3_USE_ARN_REGION to ignore region defined in client configuration.";
  36. return S3ARNOutcome(Aws::Client::AWSError<S3Errors>(S3Errors::VALIDATION, "VALIDATION", ss.str(), false));
  37. }
  38. else
  39. {
  40. return Validate();
  41. }
  42. }
  43. S3ARNOutcome S3ARN::Validate() const
  44. {
  45. Aws::String errorMessage;
  46. bool success = false;
  47. Aws::StringStream ss;
  48. if (!*this)
  49. {
  50. errorMessage = "Invalid ARN.";
  51. }
  52. // Validation on partition.
  53. else if (this->GetPartition().find("aws") != 0)
  54. {
  55. ss.str("");
  56. ss << "Invalid partition in ARN: " << this->GetPartition() << ". Valid options: aws, aws-cn, and etc.";
  57. }
  58. // Validation on service.
  59. else if (this->GetService() != ARNService::S3 && this->GetService() != ARNService::S3_OUTPOSTS && this->GetService() != ARNService::S3_OBJECT_LAMBDA)
  60. {
  61. ss.str("");
  62. ss << "Invalid service in ARN: " << this->GetService() << ". Valid options: " << ARNService::S3 << ", " << ARNService::S3_OUTPOSTS << ", " << ARNService::S3_OBJECT_LAMBDA << ".";
  63. errorMessage = ss.str();
  64. }
  65. // Validation on region.
  66. // TODO: Failure on different partitions.
  67. else if (this->GetRegion().empty())
  68. {
  69. errorMessage = "Invalid ARN with empty region.";
  70. }
  71. else if (!Utils::IsValidDnsLabel(this->GetRegion()))
  72. {
  73. ss.str("");
  74. ss << "Invalid region in ARN: " << this->GetRegion() << ". Region should be a RFC 3986 Host label.";
  75. errorMessage = ss.str();
  76. }
  77. // Validation on account ID
  78. else if (!Utils::IsValidDnsLabel(this->GetAccountId()))
  79. {
  80. ss.str("");
  81. ss << "Invalid account ID in ARN: " << this->GetAccountId() << ". Account ID should be a RFC 3986 Host label.";
  82. errorMessage = ss.str();
  83. }
  84. // Validation on Access Point ARN and Object Lambda Access Point ARN:
  85. else if (this->GetResourceType() == ARNResourceType::ACCESSPOINT)
  86. {
  87. if (!Utils::IsValidDnsLabel(this->GetResourceId()))
  88. {
  89. ss.str("");
  90. ss << "Invalid resource ID in accesspoint ARN: " << this->GetResourceId() << ". Resource ID should be a RFC 3986 Host label.";
  91. errorMessage = ss.str();
  92. }
  93. else if (!this->GetResourceQualifier().empty())
  94. {
  95. ss.str("");
  96. ss << "Invalid accesspoint ARN with non empty resource qualifier: " << this->GetResourceQualifier();
  97. errorMessage = ss.str();
  98. }
  99. else if (!this->GetSubResourceType().empty() || !this->GetSubResourceId().empty())
  100. {
  101. ss.str("");
  102. ss << "Invalid accesspoint ARN with non empty sub resource type: " << this->GetSubResourceType() << ", sub resource ID: " << this->GetSubResourceId();
  103. errorMessage = ss.str();
  104. }
  105. else
  106. {
  107. success = true;
  108. }
  109. }
  110. // Validation on Outposts ARN:
  111. else if (this->GetResourceType() == ARNResourceType::OUTPOST)
  112. {
  113. if (this->GetRegion().find("fips") != Aws::String::npos)
  114. {
  115. ss.str("");
  116. ss << "Outposts ARN do not support fips regions right now.";
  117. errorMessage = ss.str();
  118. }
  119. else if (!Utils::IsValidDnsLabel(this->GetResourceId()))
  120. {
  121. ss.str("");
  122. ss << "Invalid outpost ID in Outposts ARN: " << this->GetResourceId() << ". Outpost ID should be a RFC 3986 Host label.";
  123. errorMessage = ss.str();
  124. }
  125. else if (this->GetSubResourceType() != ARNResourceType::ACCESSPOINT)
  126. {
  127. ss.str("");
  128. ss << "Invalid sub resource type in Outposts ARN: " << this->GetSubResourceType() << ". Valid options: " << ARNResourceType::ACCESSPOINT;
  129. errorMessage = ss.str();
  130. }
  131. else if (!Utils::IsValidDnsLabel(this->GetSubResourceId()))
  132. {
  133. ss.str("");
  134. ss << "Invalid accesspoint name in Outposts ARN: " << this->GetSubResourceId() << ", accesspoint name should be a RFC 3986 Host label.";
  135. errorMessage = ss.str();
  136. }
  137. else
  138. {
  139. success = true;
  140. }
  141. }
  142. // ARN with unknown resource type.
  143. else
  144. {
  145. ss.str("");
  146. ss << "Invalid resource type in ARN: " << this->GetResourceType() << ". Valid options: " << ARNResourceType::ACCESSPOINT << ", " << ARNResourceType::OUTPOST << ".";
  147. errorMessage = ss.str();
  148. }
  149. if (success)
  150. {
  151. return S3ARNOutcome(success);
  152. }
  153. else
  154. {
  155. return S3ARNOutcome(Aws::Client::AWSError<S3Errors>(S3Errors::VALIDATION, "VALIDATION", errorMessage, false));
  156. }
  157. }
  158. void S3ARN::ParseARNResource()
  159. {
  160. if (!*this) return;
  161. Aws::String resource = this->GetResource();
  162. Aws::Vector<Aws::String> resourceSegments;
  163. if (resource.find(':') != std::string::npos)
  164. {
  165. resourceSegments = Utils::StringUtils::Split(resource, ':', 4, Utils::StringUtils::SplitOptions::INCLUDE_EMPTY_ENTRIES);
  166. }
  167. else if (resource.find('/') != std::string::npos)
  168. {
  169. resourceSegments = Utils::StringUtils::Split(resource, '/', 4, Utils::StringUtils::SplitOptions::INCLUDE_EMPTY_ENTRIES);
  170. }
  171. else
  172. {
  173. resourceSegments.emplace_back(resource);
  174. }
  175. switch (resourceSegments.size())
  176. {
  177. case 1:
  178. m_resourceId = resourceSegments[0];
  179. break;
  180. case 2:
  181. m_resourceType = resourceSegments[0];
  182. m_resourceId = resourceSegments[1];
  183. break;
  184. case 3:
  185. m_resourceType = resourceSegments[0];
  186. m_resourceId = resourceSegments[1];
  187. m_resourceQualifier = resourceSegments[2];
  188. break;
  189. case 4:
  190. m_resourceType = resourceSegments[0];
  191. m_resourceId = resourceSegments[1];
  192. m_subResourceType = resourceSegments[2];
  193. m_subResourceId = resourceSegments[3];
  194. break;
  195. default:
  196. assert(false);
  197. break;
  198. }
  199. }
  200. }
  201. }