1 | /* |
2 | * Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"). |
5 | * You may not use this file except in compliance with the License. |
6 | * A copy of the License is located at |
7 | * |
8 | * http://aws.amazon.com/apache2.0 |
9 | * |
10 | * or in the "license" file accompanying this file. This file is distributed |
11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either |
12 | * express or implied. See the License for the specific language governing |
13 | * permissions and limitations under the License. |
14 | */ |
15 | |
16 | #include <cassert> |
17 | #include <aws/core/utils/DNS.h> |
18 | #include <aws/core/utils/Outcome.h> |
19 | #include <aws/core/utils/StringUtils.h> |
20 | #include <aws/s3/S3ARN.h> |
21 | |
22 | namespace Aws |
23 | { |
24 | namespace S3 |
25 | { |
26 | S3ARN::S3ARN(const Aws::String& arn) : Utils::ARN(arn) |
27 | { |
28 | ParseARNResource(); |
29 | } |
30 | |
31 | S3ARNOutcome S3ARN::Validate(const char* clientRegion) const |
32 | { |
33 | // Take pseudo region into consideration here. |
34 | if (this->GetRegion() != clientRegion && "fips-" + this->GetRegion() != clientRegion && this->GetRegion() + "-fips" != clientRegion) |
35 | { |
36 | Aws::StringStream ss; |
37 | ss << "Region mismatch between \"" << this->GetRegion() << "\" defined in ARN and \"" |
38 | << clientRegion << "\" defined in client configuration. " |
39 | << "You can specify AWS_S3_USE_ARN_REGION to ignore region defined in client configuration." ; |
40 | return S3ARNOutcome(Aws::Client::AWSError<S3Errors>(S3Errors::VALIDATION, "VALIDATION" , ss.str(), false)); |
41 | } |
42 | else |
43 | { |
44 | return Validate(); |
45 | } |
46 | } |
47 | |
48 | S3ARNOutcome S3ARN::Validate() const |
49 | { |
50 | Aws::String errorMessage; |
51 | bool success = false; |
52 | Aws::StringStream ss; |
53 | |
54 | if (!*this) |
55 | { |
56 | errorMessage = "Invalid ARN." ; |
57 | } |
58 | // Validation on partition. |
59 | else if (this->GetPartition().find("aws" ) != 0) |
60 | { |
61 | ss.str("" ); |
62 | ss << "Invalid partition in ARN: " << this->GetPartition() << ". Valid options: aws, aws-cn, and etc." ; |
63 | } |
64 | // Validation on service. |
65 | else if (this->GetService() != "s3" ) |
66 | { |
67 | ss.str("" ); |
68 | ss << "Invalid service in ARN: " << this->GetService() << ". Valid options: s3" ; |
69 | errorMessage = ss.str(); |
70 | } |
71 | // Validation on region. |
72 | // TODO: Failure on different partitions. |
73 | else if (this->GetRegion().empty()) |
74 | { |
75 | errorMessage = "Invalid ARN with empty region." ; |
76 | } |
77 | else if (!Utils::IsValidDnsLabel(this->GetRegion())) |
78 | { |
79 | ss.str("" ); |
80 | ss << "Invalid region in ARN: " << this->GetRegion() << ". Region should be a RFC 3986 Host label." ; |
81 | errorMessage = ss.str(); |
82 | } |
83 | // Validation on account ID |
84 | else if (!Utils::IsValidDnsLabel(this->GetAccountId())) |
85 | { |
86 | ss.str("" ); |
87 | ss << "Invalid account ID in ARN: " << this->GetAccountId() << ". Account ID should be a RFC 3986 Host label." ; |
88 | errorMessage = ss.str(); |
89 | } |
90 | // Validation on resource. |
91 | else if (this->GetResourceType() != ARNResourceType::ACCESSPOINT) |
92 | { |
93 | ss.str("" ); |
94 | ss << "Invalid resource type in ARN: " << this->GetResourceType() << ". Valid options: " << ARNResourceType::ACCESSPOINT; |
95 | errorMessage = ss.str(); |
96 | } |
97 | else if (this->GetResourceId().empty()) |
98 | { |
99 | errorMessage = "Invalid Access Point ARN with empty resource ID." ; |
100 | } |
101 | else if (!Utils::IsValidDnsLabel(this->GetResourceId())) |
102 | { |
103 | ss.str("" ); |
104 | ss << "Invalid resource ID in Access Point ARN: " << this->GetResourceId() << ". Resource ID should be a RFC 3986 Host label." ; |
105 | errorMessage = ss.str(); |
106 | } |
107 | else if (!this->GetResourceQualifier().empty()) |
108 | { |
109 | errorMessage = "Invalid Access Point ARN with non empty resource qualifier." ; |
110 | } |
111 | else |
112 | { |
113 | success = true; |
114 | } |
115 | |
116 | if (success) |
117 | { |
118 | return S3ARNOutcome(success); |
119 | } |
120 | else |
121 | { |
122 | return S3ARNOutcome(Aws::Client::AWSError<S3Errors>(S3Errors::VALIDATION, "VALIDATION" , errorMessage, false)); |
123 | } |
124 | } |
125 | |
126 | void S3ARN::ParseARNResource() |
127 | { |
128 | if (!*this) return; |
129 | |
130 | Aws::String resource = this->GetResource(); |
131 | Aws::Vector<Aws::String> resourceSegments; |
132 | if (resource.find(':') != std::string::npos) |
133 | { |
134 | resourceSegments = Utils::StringUtils::Split(resource, ':', 3, Utils::StringUtils::SplitOptions::INCLUDE_EMPTY_ENTRIES); |
135 | } |
136 | else if (resource.find('/') != std::string::npos) |
137 | { |
138 | resourceSegments = Utils::StringUtils::Split(resource, '/', 3, Utils::StringUtils::SplitOptions::INCLUDE_EMPTY_ENTRIES); |
139 | } |
140 | else |
141 | { |
142 | resourceSegments.emplace_back(resource); |
143 | } |
144 | |
145 | switch (resourceSegments.size()) |
146 | { |
147 | case 1: |
148 | m_resourceId = resourceSegments[0]; |
149 | break; |
150 | case 2: |
151 | m_resourceType = resourceSegments[0]; |
152 | m_resourceId = resourceSegments[1]; |
153 | break; |
154 | case 3: |
155 | m_resourceType = resourceSegments[0]; |
156 | m_resourceId = resourceSegments[1]; |
157 | m_resourceQualifier = resourceSegments[2]; |
158 | break; |
159 | default: |
160 | assert(false); |
161 | break; |
162 | } |
163 | } |
164 | } |
165 | } |
166 | |